1 /* w32-io.c - W32 API I/O functions.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004, 2007, 2010 g10 Code GmbH
5 This file is part of GPGME.
7 GPGME is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
12 GPGME is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
32 #include <sys/types.h>
36 #ifdef HAVE_W32CE_SYSTEM
39 #define GPGCEDEV_IOCTL_UNBLOCK \
40 CTL_CODE (FILE_DEVICE_STREAMS, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS)
41 #define GPGCEDEV_IOCTL_ASSIGN_RVID \
42 CTL_CODE (FILE_DEVICE_STREAMS, 2051, METHOD_BUFFERED, FILE_ANY_ACCESS)
51 /* FIXME: Optimize. */
58 /* If this is not INVALID_HANDLE_VALUE, then it's a handle. */
61 /* If this is not INVALID_SOCKET, then it's a Windows socket. */
64 /* If this is not 0, then it's a rendezvous ID for the pipe server. */
67 /* DUP_FROM is -1 if this file descriptor was allocated by pipe or
68 socket functions. Only then should the handle or socket be
69 destroyed when this FD is closed. This, together with the fact
70 that dup'ed file descriptors are closed before the file
71 descriptors from which they are dup'ed are closed, ensures that
72 the handle or socket is always valid, and shared among all file
73 descriptors refering to the same underlying object.
75 The logic behind this is that there is only one reason for us to
76 dup file descriptors anyway: to allow simpler book-keeping of
77 file descriptors shared between GPGME and libassuan, which both
78 want to close something. Using the same handle for these
79 duplicates works just fine. */
81 } fd_table[MAX_SLAFD];
84 /* Returns the FD or -1 on resource limit. */
90 for (idx = 0; idx < MAX_SLAFD; idx++)
91 if (! fd_table[idx].used)
96 gpg_err_set_errno (EIO);
100 fd_table[idx].used = 1;
101 fd_table[idx].handle = INVALID_HANDLE_VALUE;
102 fd_table[idx].socket = INVALID_SOCKET;
103 fd_table[idx].rvid = 0;
104 fd_table[idx].dup_from = -1;
113 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
116 fd_table[fd].used = 0;
117 fd_table[fd].handle = INVALID_HANDLE_VALUE;
118 fd_table[fd].socket = INVALID_SOCKET;
119 fd_table[fd].rvid = 0;
120 fd_table[fd].dup_from = -1;
124 #define pid_to_handle(a) ((HANDLE)(a))
125 #define handle_to_pid(a) ((int)(a))
127 #define READBUF_SIZE 4096
128 #define WRITEBUF_SIZE 4096
129 #define PIPEBUF_SIZE 4096
130 #define MAX_READERS 64
131 #define MAX_WRITERS 64
137 _gpgme_close_notify_handler_t handler;
139 } notify_table[MAX_SLAFD];
140 DEFINE_STATIC_LOCK (notify_table_lock);
143 struct reader_context_s
150 DECLARE_LOCK (mutex);
158 /* This is manually reset. */
160 /* This is automatically reset. */
161 HANDLE have_space_ev;
163 size_t readpos, writepos;
164 char buffer[READBUF_SIZE];
172 struct reader_context_s *context;
173 } reader_table[MAX_READERS];
174 static int reader_table_size= MAX_READERS;
175 DEFINE_STATIC_LOCK (reader_table_lock);
178 struct writer_context_s
185 DECLARE_LOCK (mutex);
191 /* This is manually reset. */
196 char buffer[WRITEBUF_SIZE];
204 struct writer_context_s *context;
205 } writer_table[MAX_WRITERS];
206 static int writer_table_size= MAX_WRITERS;
207 DEFINE_STATIC_LOCK (writer_table_lock);
211 get_desired_thread_priority (void)
215 if (!_gpgme_get_conf_int ("IOThreadPriority", &value))
217 value = THREAD_PRIORITY_HIGHEST;
218 TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
219 "%d (default)", value);
223 TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
224 "%d (configured)", value);
231 set_synchronize (HANDLE hd)
233 #ifdef HAVE_W32CE_SYSTEM
238 /* For NT we have to set the sync flag. It seems that the only way
239 to do it is by duplicating the handle. Tsss... */
240 if (!DuplicateHandle (GetCurrentProcess (), hd,
241 GetCurrentProcess (), &new_hd,
242 EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0))
244 TRACE1 (DEBUG_SYSIO, "gpgme:set_synchronize", hd,
245 "DuplicateHandle failed: ec=%d", (int) GetLastError ());
246 /* FIXME: Should translate the error code. */
247 gpg_err_set_errno (EIO);
248 return INVALID_HANDLE_VALUE;
257 /* Return 1 if HD refers to a socket, 0 if it does not refer to a
258 socket, and -1 for unknown (autodetect). */
260 is_socket (HANDLE hd)
262 #ifdef HAVE_W32CE_SYSTEM
265 /* We need to figure out whether we are working on a socket or on a
266 handle. A trivial way would be to check for the return code of
267 recv and see if it is WSAENOTSOCK. However the recv may block
268 after the server process died and thus the destroy_reader will
269 hang. Another option is to use getsockopt to test whether it is
270 a socket. The bug here is that once a socket with a certain
271 values has been opened, closed and later a CreatePipe returned
272 the same value (i.e. handle), getsockopt still believes it is a
273 socket. What we do now is to use a combination of GetFileType
274 and GetNamedPipeInfo. The specs say that the latter may be used
275 on anonymous pipes as well. Note that there are claims that
276 since winsocket version 2 ReadFile may be used on a socket but
277 only if it is supported by the service provider. Tests on a
278 stock XP using a local TCP socket show that it does not work. */
279 DWORD dummyflags, dummyoutsize, dummyinsize, dummyinst;
281 if (GetFileType (hd) == FILE_TYPE_PIPE
282 && !GetNamedPipeInfo (hd, &dummyflags, &dummyoutsize,
283 &dummyinsize, &dummyinst))
284 return 1; /* Function failed; thus we assume it is a socket. */
286 return 0; /* Success; this is not a socket. */
291 static DWORD CALLBACK
294 struct reader_context_s *ctx = arg;
298 TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
299 "thread=%p", ctx->thread_hd);
301 if (ctx->file_hd != INVALID_HANDLE_VALUE)
309 /* Leave a 1 byte gap so that we can see whether it is empty or
311 if ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
313 /* Wait for space. */
314 if (!ResetEvent (ctx->have_space_ev))
315 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
317 TRACE_LOG ("waiting for space");
318 WaitForSingleObject (ctx->have_space_ev, INFINITE);
319 TRACE_LOG ("got space");
327 nbytes = (ctx->readpos + READBUF_SIZE
328 - ctx->writepos - 1) % READBUF_SIZE;
329 if (nbytes > READBUF_SIZE - ctx->writepos)
330 nbytes = READBUF_SIZE - ctx->writepos;
333 TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes);
339 n = recv (ctx->file_sock, ctx->buffer + ctx->writepos, nbytes, 0);
342 ctx->error_code = (int) WSAGetLastError ();
343 if (ctx->error_code == ERROR_BROKEN_PIPE)
346 TRACE_LOG ("got EOF (broken connection)");
351 TRACE_LOG1 ("recv error: ec=%d", ctx->error_code);
359 if (!ReadFile (ctx->file_hd,
360 ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
362 ctx->error_code = (int) GetLastError ();
363 /* NOTE (W32CE): Do not ignore ERROR_BUSY! Check at
364 least stop_me if that happens. */
365 if (ctx->error_code == ERROR_BROKEN_PIPE)
368 TRACE_LOG ("got EOF (broken pipe)");
373 TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
387 TRACE_LOG ("got eof");
391 TRACE_LOG1 ("got %u bytes", nread);
393 ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
394 if (!SetEvent (ctx->have_data_ev))
395 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
396 (int) GetLastError ());
399 /* Indicate that we have an error or EOF. */
400 if (!SetEvent (ctx->have_data_ev))
401 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
402 (int) GetLastError ());
403 SetEvent (ctx->stopped);
409 static struct reader_context_s *
410 create_reader (int fd)
412 struct reader_context_s *ctx;
413 SECURITY_ATTRIBUTES sec_attr;
416 TRACE_BEG (DEBUG_SYSIO, "gpgme:create_reader", fd);
418 memset (&sec_attr, 0, sizeof sec_attr);
419 sec_attr.nLength = sizeof sec_attr;
420 sec_attr.bInheritHandle = FALSE;
422 ctx = calloc (1, sizeof *ctx);
425 TRACE_SYSERR (errno);
429 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
434 ctx->file_hd = fd_table[fd].handle;
435 ctx->file_sock = fd_table[fd].socket;
438 ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
439 if (ctx->have_data_ev)
440 ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
441 if (ctx->have_space_ev)
442 ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
443 if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->stopped)
445 TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
446 if (ctx->have_data_ev)
447 CloseHandle (ctx->have_data_ev);
448 if (ctx->have_space_ev)
449 CloseHandle (ctx->have_space_ev);
451 CloseHandle (ctx->stopped);
453 /* FIXME: Translate the error code. */
458 ctx->have_data_ev = set_synchronize (ctx->have_data_ev);
459 INIT_LOCK (ctx->mutex);
461 ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid);
464 TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
465 DESTROY_LOCK (ctx->mutex);
466 if (ctx->have_data_ev)
467 CloseHandle (ctx->have_data_ev);
468 if (ctx->have_space_ev)
469 CloseHandle (ctx->have_space_ev);
471 CloseHandle (ctx->stopped);
478 /* We set the priority of the thread higher because we know that
479 it only runs for a short time. This greatly helps to
480 increase the performance of the I/O. */
481 SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
490 destroy_reader (struct reader_context_s *ctx)
494 if (ctx->refcount != 0)
500 if (ctx->have_space_ev)
501 SetEvent (ctx->have_space_ev);
504 #ifdef HAVE_W32CE_SYSTEM
505 /* Scenario: We never create a full pipe, but already started
506 reading. Then we need to unblock the reader in the pipe driver
507 to make our reader thread notice that we want it to go away. */
509 if (ctx->file_hd != INVALID_HANDLE_VALUE)
511 if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
512 NULL, 0, NULL, 0, NULL, NULL))
514 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
515 "unblock control call failed for thread %p", ctx->thread_hd);
520 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
521 "waiting for termination of thread %p", ctx->thread_hd);
522 WaitForSingleObject (ctx->stopped, INFINITE);
523 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
524 "thread %p has terminated", ctx->thread_hd);
527 CloseHandle (ctx->stopped);
528 if (ctx->have_data_ev)
529 CloseHandle (ctx->have_data_ev);
530 if (ctx->have_space_ev)
531 CloseHandle (ctx->have_space_ev);
532 CloseHandle (ctx->thread_hd);
533 DESTROY_LOCK (ctx->mutex);
538 /* Find a reader context or create a new one. Note that the reader
539 context will last until a _gpgme_io_close. */
540 static struct reader_context_s *
541 find_reader (int fd, int start_it)
543 struct reader_context_s *rd = NULL;
546 LOCK (reader_table_lock);
547 for (i = 0; i < reader_table_size; i++)
548 if (reader_table[i].used && reader_table[i].fd == fd)
549 rd = reader_table[i].context;
553 UNLOCK (reader_table_lock);
557 for (i = 0; i < reader_table_size; i++)
558 if (!reader_table[i].used)
561 if (i != reader_table_size)
563 rd = create_reader (fd);
566 reader_table[i].fd = fd;
567 reader_table[i].context = rd;
568 reader_table[i].used = 1;
572 UNLOCK (reader_table_lock);
582 LOCK (reader_table_lock);
583 for (i = 0; i < reader_table_size; i++)
585 if (reader_table[i].used && reader_table[i].fd == fd)
587 destroy_reader (reader_table[i].context);
588 reader_table[i].context = NULL;
589 reader_table[i].used = 0;
593 UNLOCK (reader_table_lock);
598 _gpgme_io_read (int fd, void *buffer, size_t count)
601 struct reader_context_s *ctx;
602 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
603 "buffer=%p, count=%u", buffer, count);
605 ctx = find_reader (fd, 1);
608 gpg_err_set_errno (EBADF);
609 return TRACE_SYSRES (-1);
611 if (ctx->eof_shortcut)
612 return TRACE_SYSRES (0);
615 if (ctx->readpos == ctx->writepos && !ctx->error)
617 /* No data available. */
619 TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd);
620 WaitForSingleObject (ctx->have_data_ev, INFINITE);
621 TRACE_LOG1 ("data from thread %p available", ctx->thread_hd);
625 if (ctx->readpos == ctx->writepos || ctx->error)
628 ctx->eof_shortcut = 1;
630 return TRACE_SYSRES (0);
633 TRACE_LOG ("EOF but ctx->eof flag not set");
636 gpg_err_set_errno (ctx->error_code);
637 return TRACE_SYSRES (-1);
640 nread = ctx->readpos < ctx->writepos
641 ? ctx->writepos - ctx->readpos
642 : READBUF_SIZE - ctx->readpos;
645 memcpy (buffer, ctx->buffer + ctx->readpos, nread);
646 ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
647 if (ctx->readpos == ctx->writepos && !ctx->eof)
649 if (!ResetEvent (ctx->have_data_ev))
651 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
653 /* FIXME: Should translate the error code. */
654 gpg_err_set_errno (EIO);
655 return TRACE_SYSRES (-1);
658 if (!SetEvent (ctx->have_space_ev))
660 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d",
661 ctx->have_space_ev, (int) GetLastError ());
663 /* FIXME: Should translate the error code. */
664 gpg_err_set_errno (EIO);
665 return TRACE_SYSRES (-1);
669 TRACE_LOGBUF (buffer, nread);
670 return TRACE_SYSRES (nread);
674 /* The writer does use a simple buffering strategy so that we are
675 informed about write errors as soon as possible (i. e. with the the
676 next call to the write function. */
677 static DWORD CALLBACK
680 struct writer_context_s *ctx = arg;
683 TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
684 "thread=%p", ctx->thread_hd);
686 if (ctx->file_hd != INVALID_HANDLE_VALUE)
701 if (!SetEvent (ctx->is_empty))
702 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
703 if (!ResetEvent (ctx->have_data))
704 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
707 WaitForSingleObject (ctx->have_data, INFINITE);
708 TRACE_LOG ("got data to send");
718 TRACE_LOG2 ("%s %d bytes", sock?"sending":"writing", ctx->nbytes);
720 /* Note that CTX->nbytes is not zero at this point, because
721 _gpgme_io_write always writes at least 1 byte before waking
722 us up, unless CTX->stop_me is true, which we catch above. */
725 /* We need to try send first because a socket handle can't
726 be used with WriteFile. */
729 n = send (ctx->file_sock, ctx->buffer, ctx->nbytes, 0);
732 ctx->error_code = (int) WSAGetLastError ();
734 TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
741 if (!WriteFile (ctx->file_hd, ctx->buffer,
742 ctx->nbytes, &nwritten, NULL))
744 if (GetLastError () == ERROR_BUSY)
746 /* Probably stop_me is set now. */
747 TRACE_LOG ("pipe busy (unblocked?)");
751 ctx->error_code = (int) GetLastError ();
753 TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
757 TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
760 ctx->nbytes -= nwritten;
763 /* Indicate that we have an error. */
764 if (!SetEvent (ctx->is_empty))
765 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
766 SetEvent (ctx->stopped);
772 static struct writer_context_s *
773 create_writer (int fd)
775 struct writer_context_s *ctx;
776 SECURITY_ATTRIBUTES sec_attr;
779 TRACE_BEG (DEBUG_SYSIO, "gpgme:create_writer", fd);
781 memset (&sec_attr, 0, sizeof sec_attr);
782 sec_attr.nLength = sizeof sec_attr;
783 sec_attr.bInheritHandle = FALSE;
785 ctx = calloc (1, sizeof *ctx);
788 TRACE_SYSERR (errno);
792 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
797 ctx->file_hd = fd_table[fd].handle;
798 ctx->file_sock = fd_table[fd].socket;
801 ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
803 ctx->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
805 ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
806 if (!ctx->have_data || !ctx->is_empty || !ctx->stopped)
808 TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
810 CloseHandle (ctx->have_data);
812 CloseHandle (ctx->is_empty);
814 CloseHandle (ctx->stopped);
816 /* FIXME: Translate the error code. */
821 ctx->is_empty = set_synchronize (ctx->is_empty);
822 INIT_LOCK (ctx->mutex);
824 ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
827 TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
828 DESTROY_LOCK (ctx->mutex);
830 CloseHandle (ctx->have_data);
832 CloseHandle (ctx->is_empty);
834 CloseHandle (ctx->stopped);
841 /* We set the priority of the thread higher because we know
842 that it only runs for a short time. This greatly helps to
843 increase the performance of the I/O. */
844 SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
852 destroy_writer (struct writer_context_s *ctx)
856 if (ctx->refcount != 0)
863 SetEvent (ctx->have_data);
866 #ifdef HAVE_W32CE_SYSTEM
867 /* Scenario: We never create a full pipe, but already started
868 writing more than the pipe buffer. Then we need to unblock the
869 writer in the pipe driver to make our writer thread notice that
870 we want it to go away. */
872 if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
873 NULL, 0, NULL, 0, NULL, NULL))
875 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
876 "unblock control call failed for thread %p", ctx->thread_hd);
880 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
881 "waiting for termination of thread %p", ctx->thread_hd);
882 WaitForSingleObject (ctx->stopped, INFINITE);
883 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
884 "thread %p has terminated", ctx->thread_hd);
887 CloseHandle (ctx->stopped);
889 CloseHandle (ctx->have_data);
891 CloseHandle (ctx->is_empty);
892 CloseHandle (ctx->thread_hd);
893 DESTROY_LOCK (ctx->mutex);
898 /* Find a writer context or create a new one. Note that the writer
899 context will last until a _gpgme_io_close. */
900 static struct writer_context_s *
901 find_writer (int fd, int start_it)
903 struct writer_context_s *wt = NULL;
906 LOCK (writer_table_lock);
907 for (i = 0; i < writer_table_size; i++)
908 if (writer_table[i].used && writer_table[i].fd == fd)
909 wt = writer_table[i].context;
913 UNLOCK (writer_table_lock);
917 for (i = 0; i < writer_table_size; i++)
918 if (!writer_table[i].used)
921 if (i != writer_table_size)
923 wt = create_writer (fd);
926 writer_table[i].fd = fd;
927 writer_table[i].context = wt;
928 writer_table[i].used = 1;
932 UNLOCK (writer_table_lock);
942 LOCK (writer_table_lock);
943 for (i = 0; i < writer_table_size; i++)
945 if (writer_table[i].used && writer_table[i].fd == fd)
947 destroy_writer (writer_table[i].context);
948 writer_table[i].context = NULL;
949 writer_table[i].used = 0;
953 UNLOCK (writer_table_lock);
958 _gpgme_io_write (int fd, const void *buffer, size_t count)
960 struct writer_context_s *ctx;
961 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
962 "buffer=%p, count=%u", buffer, count);
963 TRACE_LOGBUF (buffer, count);
966 return TRACE_SYSRES (0);
968 ctx = find_writer (fd, 0);
970 return TRACE_SYSRES (-1);
973 if (!ctx->error && ctx->nbytes)
975 /* Bytes are pending for send. */
977 /* Reset the is_empty event. Better safe than sorry. */
978 if (!ResetEvent (ctx->is_empty))
980 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
982 /* FIXME: Should translate the error code. */
983 gpg_err_set_errno (EIO);
984 return TRACE_SYSRES (-1);
987 TRACE_LOG1 ("waiting for empty buffer in thread %p", ctx->thread_hd);
988 WaitForSingleObject (ctx->is_empty, INFINITE);
989 TRACE_LOG1 ("thread %p buffer is empty", ctx->thread_hd);
996 if (ctx->error_code == ERROR_NO_DATA)
997 gpg_err_set_errno (EPIPE);
999 gpg_err_set_errno (EIO);
1000 return TRACE_SYSRES (-1);
1003 /* If no error occured, the number of bytes in the buffer must be
1005 assert (!ctx->nbytes);
1007 if (count > WRITEBUF_SIZE)
1008 count = WRITEBUF_SIZE;
1009 memcpy (ctx->buffer, buffer, count);
1010 ctx->nbytes = count;
1012 /* We have to reset the is_empty event early, because it is also
1013 used by the select() implementation to probe the channel. */
1014 if (!ResetEvent (ctx->is_empty))
1016 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
1017 UNLOCK (ctx->mutex);
1018 /* FIXME: Should translate the error code. */
1019 gpg_err_set_errno (EIO);
1020 return TRACE_SYSRES (-1);
1022 if (!SetEvent (ctx->have_data))
1024 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
1025 UNLOCK (ctx->mutex);
1026 /* FIXME: Should translate the error code. */
1027 gpg_err_set_errno (EIO);
1028 return TRACE_SYSRES (-1);
1030 UNLOCK (ctx->mutex);
1032 return TRACE_SYSRES ((int) count);
1037 _gpgme_io_pipe (int filedes[2], int inherit_idx)
1041 #ifdef HAVE_W32CE_SYSTEM
1047 SECURITY_ATTRIBUTES sec_attr;
1050 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
1051 "inherit_idx=%i (GPGME uses it for %s)",
1052 inherit_idx, inherit_idx ? "reading" : "writing");
1056 return TRACE_SYSRES (-1);
1061 return TRACE_SYSRES (-1);
1064 #ifdef HAVE_W32CE_SYSTEM
1065 hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
1066 if (hd == INVALID_HANDLE_VALUE)
1068 TRACE_LOG1 ("_assuan_w32ce_prepare_pipe failed: ec=%d",
1069 (int) GetLastError ());
1072 /* FIXME: Should translate the error code. */
1073 gpg_err_set_errno (EIO);
1074 return TRACE_SYSRES (-1);
1077 if (inherit_idx == 0)
1079 fd_table[rfd].rvid = rvid;
1080 fd_table[wfd].handle = hd;
1084 fd_table[rfd].handle = hd;
1085 fd_table[wfd].rvid = rvid;
1090 memset (&sec_attr, 0, sizeof (sec_attr));
1091 sec_attr.nLength = sizeof (sec_attr);
1092 sec_attr.bInheritHandle = FALSE;
1094 if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
1096 TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
1099 /* FIXME: Should translate the error code. */
1100 gpg_err_set_errno (EIO);
1101 return TRACE_SYSRES (-1);
1104 /* Make one end inheritable. */
1105 if (inherit_idx == 0)
1108 if (!DuplicateHandle (GetCurrentProcess(), rh,
1109 GetCurrentProcess(), &hd, 0,
1110 TRUE, DUPLICATE_SAME_ACCESS))
1112 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1113 (int) GetLastError ());
1118 /* FIXME: Should translate the error code. */
1119 gpg_err_set_errno (EIO);
1120 return TRACE_SYSRES (-1);
1125 else if (inherit_idx == 1)
1128 if (!DuplicateHandle( GetCurrentProcess(), wh,
1129 GetCurrentProcess(), &hd, 0,
1130 TRUE, DUPLICATE_SAME_ACCESS))
1132 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1133 (int) GetLastError ());
1138 /* FIXME: Should translate the error code. */
1139 gpg_err_set_errno (EIO);
1140 return TRACE_SYSRES (-1);
1145 fd_table[rfd].handle = rh;
1146 fd_table[wfd].handle = wh;
1149 if (inherit_idx == 0)
1151 struct writer_context_s *ctx;
1152 ctx = find_writer (wfd, 0);
1153 assert (ctx == NULL);
1154 ctx = find_writer (wfd, 1);
1157 /* No way/need to close RVIDs on Windows CE. */
1158 if (fd_table[rfd].handle)
1159 CloseHandle (fd_table[rfd].handle);
1160 if (fd_table[wfd].handle)
1161 CloseHandle (fd_table[wfd].handle);
1164 /* FIXME: Should translate the error code. */
1165 gpg_err_set_errno (EIO);
1166 return TRACE_SYSRES (-1);
1169 else if (inherit_idx == 1)
1171 struct reader_context_s *ctx;
1172 ctx = find_reader (rfd, 0);
1173 assert (ctx == NULL);
1174 ctx = find_reader (rfd, 1);
1177 if (fd_table[rfd].handle)
1178 CloseHandle (fd_table[rfd].handle);
1179 /* No way/need to close RVIDs on Windows CE. */
1180 if (fd_table[wfd].handle)
1181 CloseHandle (fd_table[wfd].handle);
1184 /* FIXME: Should translate the error code. */
1185 gpg_err_set_errno (EIO);
1186 return TRACE_SYSRES (-1);
1192 return TRACE_SUC6 ("read=0x%x (%p/0x%x), write=0x%x (%p/0x%x)",
1193 rfd, fd_table[rfd].handle, fd_table[rfd].rvid,
1194 wfd, fd_table[wfd].handle, fd_table[wfd].rvid);
1199 _gpgme_io_close (int fd)
1202 _gpgme_close_notify_handler_t handler = NULL;
1205 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
1209 gpg_err_set_errno (EBADF);
1210 return TRACE_SYSRES (-1);
1212 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1214 gpg_err_set_errno (EBADF);
1215 return TRACE_SYSRES (-1);
1220 LOCK (notify_table_lock);
1221 for (i = 0; i < DIM (notify_table); i++)
1223 if (notify_table[i].inuse && notify_table[i].fd == fd)
1225 handler = notify_table[i].handler;
1226 value = notify_table[i].value;
1227 notify_table[i].handler = NULL;
1228 notify_table[i].value = NULL;
1229 notify_table[i].inuse = 0;
1233 UNLOCK (notify_table_lock);
1235 handler (fd, value);
1237 if (fd_table[fd].dup_from == -1)
1239 if (fd_table[fd].handle != INVALID_HANDLE_VALUE)
1241 if (!CloseHandle (fd_table[fd].handle))
1243 TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ());
1244 /* FIXME: Should translate the error code. */
1245 gpg_err_set_errno (EIO);
1246 return TRACE_SYSRES (-1);
1249 else if (fd_table[fd].socket != INVALID_SOCKET)
1251 if (closesocket (fd_table[fd].socket))
1253 TRACE_LOG1 ("closesocket failed: ec=%d", (int) WSAGetLastError ());
1254 /* FIXME: Should translate the error code. */
1255 gpg_err_set_errno (EIO);
1256 return TRACE_SYSRES (-1);
1259 /* Nothing to do for RVIDs. */
1264 return TRACE_SYSRES (0);
1269 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
1273 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
1274 "close_handler=%p/%p", handler, value);
1278 LOCK (notify_table_lock);
1279 for (i=0; i < DIM (notify_table); i++)
1280 if (notify_table[i].inuse && notify_table[i].fd == fd)
1282 if (i == DIM (notify_table))
1283 for (i = 0; i < DIM (notify_table); i++)
1284 if (!notify_table[i].inuse)
1286 if (i == DIM (notify_table))
1288 UNLOCK (notify_table_lock);
1289 gpg_err_set_errno (EINVAL);
1290 return TRACE_SYSRES (-1);
1292 notify_table[i].fd = fd;
1293 notify_table[i].handler = handler;
1294 notify_table[i].value = value;
1295 notify_table[i].inuse = 1;
1296 UNLOCK (notify_table_lock);
1297 return TRACE_SYSRES (0);
1302 _gpgme_io_set_nonblocking (int fd)
1304 TRACE (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
1309 #ifdef HAVE_W32CE_SYSTEM
1311 build_commandline (char **argv, int fd0, int fd0_isnull,
1312 int fd1, int fd1_isnull,
1313 int fd2, int fd2_isnull)
1326 strcpy (p, "-&S0=null ");
1328 snprintf (p, 25, "-&S0=%d ", fd_table[fd0].rvid);
1334 strcpy (p, "-&S1=null ");
1336 snprintf (p, 25, "-&S1=%d ", fd_table[fd1].rvid);
1342 strcpy (p, "-&S2=null ");
1344 snprintf (p, 25, "-&S2=%d ", fd_table[fd2].rvid);
1347 strcpy (p, "-&S2=null ");
1351 for (i=0; (s = argv[i]); i++)
1354 continue; /* Ignore argv[0]. */
1355 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting) */
1358 n++; /* Need to double inner quotes. */
1361 buf = p = malloc (n);
1365 p = stpcpy (p, fdbuf);
1366 for (i = 0; argv[i]; i++)
1369 continue; /* Ignore argv[0]. */
1371 p = stpcpy (p, " ");
1373 if (! *argv[i]) /* Empty string. */
1374 p = stpcpy (p, "\"\"");
1375 else if (strpbrk (argv[i], " \t\n\v\f\""))
1377 p = stpcpy (p, "\"");
1378 for (s = argv[i]; *s; s++)
1388 p = stpcpy (p, argv[i]);
1395 build_commandline (char **argv)
1402 /* We have to quote some things because under Windows the program
1403 parses the commandline and does some unquoting. We enclose the
1404 whole argument in double-quotes, and escape literal double-quotes
1405 as well as backslashes with a backslash. We end up with a
1406 trailing space at the end of the line, but that is harmless. */
1407 for (i = 0; argv[i]; i++)
1410 /* The leading double-quote. */
1414 /* An extra one for each literal that must be escaped. */
1415 if (*p == '\\' || *p == '"')
1420 /* The trailing double-quote and the delimiter. */
1423 /* And a trailing zero. */
1426 buf = p = malloc (n);
1429 for (i = 0; argv[i]; i++)
1431 char *argvp = argv[i];
1436 if (*argvp == '\\' || *argvp == '"')
1438 *(p++) = *(argvp++);
1451 _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
1452 struct spawn_fd_item_s *fd_list,
1453 void (*atfork) (void *opaque, int reserved),
1454 void *atforkvalue, pid_t *r_pid)
1456 PROCESS_INFORMATION pi =
1458 NULL, /* returns process handle */
1459 0, /* returns primary thread handle */
1460 0, /* returns pid */
1465 #ifdef HAVE_W32CE_SYSTEM
1469 int fd_in_isnull = 1;
1470 int fd_out_isnull = 1;
1471 int fd_err_isnull = 1;
1473 HANDLE hd = INVALID_HANDLE_VALUE;
1475 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1480 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1484 for (i = 0; fd_list[i].fd != -1; i++)
1486 int fd = fd_list[i].fd;
1488 TRACE_LOG3 ("fd_list[%2i] = fd %i, dup_to %i", i, fd, fd_list[i].dup_to);
1489 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1491 TRACE_LOG1 ("invalid fd 0x%x", fd);
1492 gpg_err_set_errno (EBADF);
1493 return TRACE_SYSRES (-1);
1495 if (fd_table[fd].rvid == 0)
1497 TRACE_LOG1 ("fd 0x%x not inheritable (not an RVID)", fd);
1498 gpg_err_set_errno (EBADF);
1499 return TRACE_SYSRES (-1);
1502 if (fd_list[i].dup_to == 0)
1504 fd_in = fd_list[i].fd;
1507 else if (fd_list[i].dup_to == 1)
1509 fd_out = fd_list[i].fd;
1512 else if (fd_list[i].dup_to == 2)
1514 fd_err = fd_list[i].fd;
1519 cmdline = build_commandline (argv, fd_in, fd_in_isnull,
1520 fd_out, fd_out_isnull, fd_err, fd_err_isnull);
1523 TRACE_LOG1 ("build_commandline failed: %s", strerror (errno));
1524 return TRACE_SYSRES (-1);
1527 if (!CreateProcessA (path, /* Program to start. */
1528 cmdline, /* Command line arguments. */
1529 NULL, /* (not supported) */
1530 NULL, /* (not supported) */
1531 FALSE, /* (not supported) */
1532 (CREATE_SUSPENDED), /* Creation flags. */
1533 NULL, /* (not supported) */
1534 NULL, /* (not supported) */
1535 NULL, /* (not supported) */
1536 &pi /* Returns process information.*/
1539 TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1541 gpg_err_set_errno (EIO);
1542 return TRACE_SYSRES (-1);
1545 /* Create arbitrary pipe descriptor to send in ASSIGN_RVID
1546 commands. Errors are ignored. We don't need read or write access,
1547 as ASSIGN_RVID works without any permissions, yay! */
1548 hd = CreateFile (L"GPG1:", 0, 0,
1549 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1550 if (hd == INVALID_HANDLE_VALUE)
1552 TRACE_LOG1 (DEBUG_SYSIO, "CreateFile failed (ignored): ec=%d",
1553 (int) GetLastError ());
1556 /* Insert the inherited handles. */
1557 for (i = 0; fd_list[i].fd != -1; i++)
1559 /* Return the child name of this handle. */
1560 fd_list[i].peer_name = fd_table[fd_list[i].fd].rvid;
1562 if (hd != INVALID_HANDLE_VALUE)
1565 data[0] = (DWORD) fd_table[fd_list[i].fd].rvid;
1566 data[1] = pi.dwProcessId;
1567 if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_ASSIGN_RVID,
1568 data, sizeof (data), NULL, 0, NULL, NULL))
1570 TRACE_LOG1 (DEBUG_SYSIO,
1571 "ASSIGN_RVID(%i, %i) failed (ignored): %i",
1572 data[0], data[1], (int) GetLastError ());
1576 if (hd != INVALID_HANDLE_VALUE)
1580 SECURITY_ATTRIBUTES sec_attr;
1582 int cr_flags = CREATE_DEFAULT_ERROR_MODE;
1590 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1595 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1599 /* We do not inherit any handles by default, and just insert those
1600 handles we want the child to have afterwards. But some handle
1601 values occur on the command line, and we need to move
1602 stdin/out/err to the right location. So we use a wrapper program
1603 which gets the information from a temporary file. */
1604 if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
1606 TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
1607 return TRACE_SYSRES (-1);
1609 TRACE_LOG1 ("tmp_name = %s", tmp_name);
1611 args = calloc (2 + i + 1, sizeof (*args));
1612 args[0] = (char *) _gpgme_get_w32spawn_path ();
1615 memcpy (&args[3], &argv[1], i * sizeof (*args));
1617 memset (&sec_attr, 0, sizeof sec_attr);
1618 sec_attr.nLength = sizeof sec_attr;
1619 sec_attr.bInheritHandle = FALSE;
1621 arg_string = build_commandline (args);
1626 DeleteFileA (tmp_name);
1627 return TRACE_SYSRES (-1);
1630 memset (&si, 0, sizeof si);
1631 si.cb = sizeof (si);
1632 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1633 si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
1634 si.hStdInput = INVALID_HANDLE_VALUE;
1635 si.hStdOutput = INVALID_HANDLE_VALUE;
1636 si.hStdError = INVALID_HANDLE_VALUE;
1638 cr_flags |= CREATE_SUSPENDED;
1639 #ifndef HAVE_W32CE_SYSTEM
1640 cr_flags |= DETACHED_PROCESS;
1641 cr_flags |= GetPriorityClass (GetCurrentProcess ());
1643 if (!CreateProcessA (_gpgme_get_w32spawn_path (),
1645 &sec_attr, /* process security attributes */
1646 &sec_attr, /* thread security attributes */
1647 FALSE, /* inherit handles */
1648 cr_flags, /* creation flags */
1649 NULL, /* environment */
1650 NULL, /* use current drive/directory */
1651 &si, /* startup information */
1652 &pi)) /* returns process information */
1654 TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1657 DeleteFileA (tmp_name);
1659 /* FIXME: Should translate the error code. */
1660 gpg_err_set_errno (EIO);
1661 return TRACE_SYSRES (-1);
1666 if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
1667 _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
1669 /* Insert the inherited handles. */
1670 for (i = 0; fd_list[i].fd != -1; i++)
1674 /* Make it inheritable for the wrapper process. */
1675 if (!DuplicateHandle (GetCurrentProcess(), fd_to_handle (fd_list[i].fd),
1676 pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
1678 TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
1679 TerminateProcess (pi.hProcess, 0);
1680 /* Just in case TerminateProcess didn't work, let the
1681 process fail on its own. */
1682 ResumeThread (pi.hThread);
1683 CloseHandle (pi.hThread);
1684 CloseHandle (pi.hProcess);
1687 DeleteFileA (tmp_name);
1689 /* FIXME: Should translate the error code. */
1690 gpg_err_set_errno (EIO);
1691 return TRACE_SYSRES (-1);
1693 /* Return the child name of this handle. */
1694 fd_list[i].peer_name = handle_to_fd (hd);
1697 /* Write the handle translation information to the temporary
1700 /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
1701 notation: "0xFEDCBA9876543210" with an extra white space after
1702 every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead
1703 for a time when a HANDLE is 64 bit. */
1704 #define BUFFER_MAX 810
1705 char line[BUFFER_MAX + 1];
1710 if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
1711 strcpy (line, "~1 \n");
1713 strcpy (line, "\n");
1714 for (i = 0; fd_list[i].fd != -1; i++)
1716 /* Strip the newline. */
1717 len = strlen (line) - 1;
1719 /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx. */
1720 snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d \n",
1721 fd_list[i].fd, fd_list[i].dup_to,
1722 fd_list[i].peer_name, fd_list[i].arg_loc);
1723 /* Rather safe than sorry. */
1724 line[BUFFER_MAX - 1] = '\n';
1725 line[BUFFER_MAX] = '\0';
1727 len = strlen (line);
1731 res = write (tmp_fd, &line[written], len - written);
1735 while (res > 0 || (res < 0 && errno == EAGAIN));
1738 /* The temporary file is deleted by the gpgme-w32spawn process
1743 TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
1744 "dwProcessID=%d, dwThreadId=%d",
1745 pi.hProcess, pi.hThread,
1746 (int) pi.dwProcessId, (int) pi.dwThreadId);
1749 *r_pid = (pid_t)pi.dwProcessId;
1752 if (ResumeThread (pi.hThread) < 0)
1753 TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
1755 if (!CloseHandle (pi.hThread))
1756 TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
1757 (int) GetLastError ());
1759 TRACE_LOG1 ("process=%p", pi.hProcess);
1761 /* We don't need to wait for the process. */
1762 if (!CloseHandle (pi.hProcess))
1763 TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
1764 (int) GetLastError ());
1766 if (! (flags & IOSPAWN_FLAG_NOCLOSE))
1768 for (i = 0; fd_list[i].fd != -1; i++)
1769 _gpgme_io_close (fd_list[i].fd);
1772 for (i = 0; fd_list[i].fd != -1; i++)
1773 if (fd_list[i].dup_to == -1)
1774 TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
1775 fd_list[i].peer_name);
1777 TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
1778 fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
1779 ((fd_list[i].dup_to == 1) ? "out" : "err"));
1781 return TRACE_SYSRES (0);
1785 /* Select on the list of fds. Returns: -1 = error, 0 = timeout or
1786 nothing to select, > 0 = number of signaled fds. */
1788 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
1790 HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1791 int waitidx[MAXIMUM_WAIT_OBJECTS];
1798 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
1799 "nfds=%u, nonblock=%u", nfds, nonblock);
1802 TRACE_SEQ (dbg_help, "select on [ ");
1806 for (i=0; i < nfds; i++)
1808 if (fds[i].fd == -1)
1810 fds[i].signaled = 0;
1811 if (fds[i].for_read || fds[i].for_write)
1813 if (fds[i].for_read)
1815 struct reader_context_s *ctx = find_reader (fds[i].fd,0);
1818 TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
1822 if (nwait >= DIM (waitbuf))
1824 TRACE_END (dbg_help, "oops ]");
1825 TRACE_LOG ("Too many objects for WFMO!");
1826 /* FIXME: Should translate the error code. */
1827 gpg_err_set_errno (EIO);
1828 return TRACE_SYSRES (-1);
1831 waitbuf[nwait++] = ctx->have_data_ev;
1833 TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
1836 else if (fds[i].for_write)
1838 struct writer_context_s *ctx = find_writer (fds[i].fd,0);
1841 TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
1845 if (nwait >= DIM (waitbuf))
1847 TRACE_END (dbg_help, "oops ]");
1848 TRACE_LOG ("Too many objects for WFMO!");
1849 /* FIXME: Should translate the error code. */
1850 gpg_err_set_errno (EIO);
1851 return TRACE_SYSRES (-1);
1854 waitbuf[nwait++] = ctx->is_empty;
1856 TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
1861 TRACE_END (dbg_help, "]");
1863 return TRACE_SYSRES (0);
1865 code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
1866 if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
1868 /* This WFMO is a really silly function: It does return either
1869 the index of the signaled object or if 2 objects have been
1870 signalled at the same time, the index of the object with the
1871 lowest object is returned - so and how do we find out how
1872 many objects have been signaled???. The only solution I can
1873 imagine is to test each object starting with the returned
1874 index individually - how dull. */
1876 for (i = code - WAIT_OBJECT_0; i < nwait; i++)
1878 if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
1880 assert (waitidx[i] >=0 && waitidx[i] < nfds);
1881 fds[waitidx[i]].signaled = 1;
1888 TRACE_LOG ("no signaled objects found after WFMO");
1892 else if (code == WAIT_TIMEOUT)
1893 TRACE_LOG ("WFMO timed out");
1894 else if (code == WAIT_FAILED)
1896 int le = (int) GetLastError ();
1898 if (le == ERROR_INVALID_HANDLE)
1901 int j = handle_to_fd (waitbuf[i]);
1903 TRACE_LOG1 ("WFMO invalid handle %d removed", j);
1904 for (k = 0 ; k < nfds; k++)
1908 fds[k].for_read = fds[k].for_write = 0;
1912 TRACE_LOG (" oops, or not???");
1915 TRACE_LOG1 ("WFMO failed: %d", le);
1920 TRACE_LOG1 ("WFMO returned %d", code);
1926 TRACE_SEQ (dbg_help, "select OK [ ");
1927 for (i = 0; i < nfds; i++)
1929 if (fds[i].fd == -1)
1931 if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
1932 TRACE_ADD2 (dbg_help, "%c0x%x ",
1933 fds[i].for_read ? 'r' : 'w', fds[i].fd);
1935 TRACE_END (dbg_help, "]");
1940 /* FIXME: Should determine a proper error code. */
1941 gpg_err_set_errno (EIO);
1944 return TRACE_SYSRES (count);
1949 _gpgme_io_subsystem_init (void)
1951 /* Nothing to do. */
1955 /* Write the printable version of FD to the buffer BUF of length
1956 BUFLEN. The printable version is the representation on the command
1957 line that the child process expects. */
1959 _gpgme_io_fd2str (char *buf, int buflen, int fd)
1961 #ifdef HAVE_W32CE_SYSTEM
1962 /* FIXME: For now. See above. */
1963 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used
1964 || fd_table[fd].rvid == 0)
1967 fd = fd_table[fd].rvid;
1970 return snprintf (buf, buflen, "%d", fd);
1975 _gpgme_io_dup (int fd)
1978 struct reader_context_s *rd_ctx;
1979 struct writer_context_s *wt_ctx;
1982 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
1984 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1986 gpg_err_set_errno (EINVAL);
1987 return TRACE_SYSRES (-1);
1992 return TRACE_SYSRES (-1);
1994 fd_table[newfd].handle = fd_table[fd].handle;
1995 fd_table[newfd].socket = fd_table[fd].socket;
1996 fd_table[newfd].rvid = fd_table[fd].rvid;
1997 fd_table[newfd].dup_from = fd;
1999 rd_ctx = find_reader (fd, 0);
2002 /* No need for locking, as the only races are against the reader
2003 thread itself, which doesn't touch refcount. */
2006 LOCK (reader_table_lock);
2007 for (i = 0; i < reader_table_size; i++)
2008 if (!reader_table[i].used)
2011 assert (i != reader_table_size);
2012 reader_table[i].fd = newfd;
2013 reader_table[i].context = rd_ctx;
2014 reader_table[i].used = 1;
2015 UNLOCK (reader_table_lock);
2018 wt_ctx = find_writer (fd, 0);
2021 /* No need for locking, as the only races are against the writer
2022 thread itself, which doesn't touch refcount. */
2025 LOCK (writer_table_lock);
2026 for (i = 0; i < writer_table_size; i++)
2027 if (!writer_table[i].used)
2030 assert (i != writer_table_size);
2031 writer_table[i].fd = newfd;
2032 writer_table[i].context = wt_ctx;
2033 writer_table[i].used = 1;
2034 UNLOCK (writer_table_lock);
2037 return TRACE_SYSRES (newfd);
2041 /* The following interface is only useful for GPGME Glib and Qt. */
2043 /* Compatibility interface, obsolete. */
2045 gpgme_get_giochannel (int fd)
2051 /* Look up the giochannel or qiodevice for file descriptor FD. */
2053 gpgme_get_fdptr (int fd)
2066 case WSAEWOULDBLOCK:
2068 case ERROR_BROKEN_PIPE:
2070 case WSANOTINITIALISED:
2079 _gpgme_io_socket (int domain, int type, int proto)
2084 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
2085 "type=%i, protp=%i", type, proto);
2089 return TRACE_SYSRES (-1);
2091 res = socket (domain, type, proto);
2092 if (res == INVALID_SOCKET)
2095 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2096 return TRACE_SYSRES (-1);
2098 fd_table[fd].socket = res;
2100 TRACE_SUC2 ("socket=0x%x (0x%x)", fd, fd_table[fd].socket);
2107 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
2111 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
2112 "addr=%p, addrlen=%i", addr, addrlen);
2114 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
2116 gpg_err_set_errno (EBADF);
2117 return TRACE_SYSRES (-1);
2120 res = connect (fd_table[fd].socket, addr, addrlen);
2123 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2124 return TRACE_SYSRES (-1);
2127 return TRACE_SUC ();