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 ("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_LOG3 ("ASSIGN_RVID(%i, %i) failed (ignored): %i",
1571 data[0], data[1], (int) GetLastError ());
1575 if (hd != INVALID_HANDLE_VALUE)
1579 SECURITY_ATTRIBUTES sec_attr;
1581 int cr_flags = CREATE_DEFAULT_ERROR_MODE;
1589 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1594 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1598 /* We do not inherit any handles by default, and just insert those
1599 handles we want the child to have afterwards. But some handle
1600 values occur on the command line, and we need to move
1601 stdin/out/err to the right location. So we use a wrapper program
1602 which gets the information from a temporary file. */
1603 if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
1605 TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
1606 return TRACE_SYSRES (-1);
1608 TRACE_LOG1 ("tmp_name = %s", tmp_name);
1610 args = calloc (2 + i + 1, sizeof (*args));
1611 args[0] = (char *) _gpgme_get_w32spawn_path ();
1614 memcpy (&args[3], &argv[1], i * sizeof (*args));
1616 memset (&sec_attr, 0, sizeof sec_attr);
1617 sec_attr.nLength = sizeof sec_attr;
1618 sec_attr.bInheritHandle = FALSE;
1620 arg_string = build_commandline (args);
1625 DeleteFileA (tmp_name);
1626 return TRACE_SYSRES (-1);
1629 memset (&si, 0, sizeof si);
1630 si.cb = sizeof (si);
1631 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1632 si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
1633 si.hStdInput = INVALID_HANDLE_VALUE;
1634 si.hStdOutput = INVALID_HANDLE_VALUE;
1635 si.hStdError = INVALID_HANDLE_VALUE;
1637 cr_flags |= CREATE_SUSPENDED;
1638 #ifndef HAVE_W32CE_SYSTEM
1639 cr_flags |= DETACHED_PROCESS;
1640 cr_flags |= GetPriorityClass (GetCurrentProcess ());
1642 if (!CreateProcessA (_gpgme_get_w32spawn_path (),
1644 &sec_attr, /* process security attributes */
1645 &sec_attr, /* thread security attributes */
1646 FALSE, /* inherit handles */
1647 cr_flags, /* creation flags */
1648 NULL, /* environment */
1649 NULL, /* use current drive/directory */
1650 &si, /* startup information */
1651 &pi)) /* returns process information */
1653 TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1656 DeleteFileA (tmp_name);
1658 /* FIXME: Should translate the error code. */
1659 gpg_err_set_errno (EIO);
1660 return TRACE_SYSRES (-1);
1665 if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
1666 _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
1668 /* Insert the inherited handles. */
1669 for (i = 0; fd_list[i].fd != -1; i++)
1673 /* Make it inheritable for the wrapper process. */
1674 if (!DuplicateHandle (GetCurrentProcess(), fd_to_handle (fd_list[i].fd),
1675 pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
1677 TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
1678 TerminateProcess (pi.hProcess, 0);
1679 /* Just in case TerminateProcess didn't work, let the
1680 process fail on its own. */
1681 ResumeThread (pi.hThread);
1682 CloseHandle (pi.hThread);
1683 CloseHandle (pi.hProcess);
1686 DeleteFileA (tmp_name);
1688 /* FIXME: Should translate the error code. */
1689 gpg_err_set_errno (EIO);
1690 return TRACE_SYSRES (-1);
1692 /* Return the child name of this handle. */
1693 fd_list[i].peer_name = handle_to_fd (hd);
1696 /* Write the handle translation information to the temporary
1699 /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
1700 notation: "0xFEDCBA9876543210" with an extra white space after
1701 every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead
1702 for a time when a HANDLE is 64 bit. */
1703 #define BUFFER_MAX 810
1704 char line[BUFFER_MAX + 1];
1709 if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
1710 strcpy (line, "~1 \n");
1712 strcpy (line, "\n");
1713 for (i = 0; fd_list[i].fd != -1; i++)
1715 /* Strip the newline. */
1716 len = strlen (line) - 1;
1718 /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx. */
1719 snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d \n",
1720 fd_list[i].fd, fd_list[i].dup_to,
1721 fd_list[i].peer_name, fd_list[i].arg_loc);
1722 /* Rather safe than sorry. */
1723 line[BUFFER_MAX - 1] = '\n';
1724 line[BUFFER_MAX] = '\0';
1726 len = strlen (line);
1730 res = write (tmp_fd, &line[written], len - written);
1734 while (res > 0 || (res < 0 && errno == EAGAIN));
1737 /* The temporary file is deleted by the gpgme-w32spawn process
1742 TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
1743 "dwProcessID=%d, dwThreadId=%d",
1744 pi.hProcess, pi.hThread,
1745 (int) pi.dwProcessId, (int) pi.dwThreadId);
1748 *r_pid = (pid_t)pi.dwProcessId;
1751 if (ResumeThread (pi.hThread) < 0)
1752 TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
1754 if (!CloseHandle (pi.hThread))
1755 TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
1756 (int) GetLastError ());
1758 TRACE_LOG1 ("process=%p", pi.hProcess);
1760 /* We don't need to wait for the process. */
1761 if (!CloseHandle (pi.hProcess))
1762 TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
1763 (int) GetLastError ());
1765 if (! (flags & IOSPAWN_FLAG_NOCLOSE))
1767 for (i = 0; fd_list[i].fd != -1; i++)
1768 _gpgme_io_close (fd_list[i].fd);
1771 for (i = 0; fd_list[i].fd != -1; i++)
1772 if (fd_list[i].dup_to == -1)
1773 TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
1774 fd_list[i].peer_name);
1776 TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
1777 fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
1778 ((fd_list[i].dup_to == 1) ? "out" : "err"));
1780 return TRACE_SYSRES (0);
1784 /* Select on the list of fds. Returns: -1 = error, 0 = timeout or
1785 nothing to select, > 0 = number of signaled fds. */
1787 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
1789 HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1790 int waitidx[MAXIMUM_WAIT_OBJECTS];
1797 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
1798 "nfds=%u, nonblock=%u", nfds, nonblock);
1801 TRACE_SEQ (dbg_help, "select on [ ");
1805 for (i=0; i < nfds; i++)
1807 if (fds[i].fd == -1)
1809 fds[i].signaled = 0;
1810 if (fds[i].for_read || fds[i].for_write)
1812 if (fds[i].for_read)
1814 struct reader_context_s *ctx = find_reader (fds[i].fd,0);
1817 TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
1821 if (nwait >= DIM (waitbuf))
1823 TRACE_END (dbg_help, "oops ]");
1824 TRACE_LOG ("Too many objects for WFMO!");
1825 /* FIXME: Should translate the error code. */
1826 gpg_err_set_errno (EIO);
1827 return TRACE_SYSRES (-1);
1830 waitbuf[nwait++] = ctx->have_data_ev;
1832 TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
1835 else if (fds[i].for_write)
1837 struct writer_context_s *ctx = find_writer (fds[i].fd,0);
1840 TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
1844 if (nwait >= DIM (waitbuf))
1846 TRACE_END (dbg_help, "oops ]");
1847 TRACE_LOG ("Too many objects for WFMO!");
1848 /* FIXME: Should translate the error code. */
1849 gpg_err_set_errno (EIO);
1850 return TRACE_SYSRES (-1);
1853 waitbuf[nwait++] = ctx->is_empty;
1855 TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
1860 TRACE_END (dbg_help, "]");
1862 return TRACE_SYSRES (0);
1864 code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
1865 if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
1867 /* This WFMO is a really silly function: It does return either
1868 the index of the signaled object or if 2 objects have been
1869 signalled at the same time, the index of the object with the
1870 lowest object is returned - so and how do we find out how
1871 many objects have been signaled???. The only solution I can
1872 imagine is to test each object starting with the returned
1873 index individually - how dull. */
1875 for (i = code - WAIT_OBJECT_0; i < nwait; i++)
1877 if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
1879 assert (waitidx[i] >=0 && waitidx[i] < nfds);
1880 fds[waitidx[i]].signaled = 1;
1887 TRACE_LOG ("no signaled objects found after WFMO");
1891 else if (code == WAIT_TIMEOUT)
1892 TRACE_LOG ("WFMO timed out");
1893 else if (code == WAIT_FAILED)
1895 int le = (int) GetLastError ();
1897 if (le == ERROR_INVALID_HANDLE)
1900 int j = handle_to_fd (waitbuf[i]);
1902 TRACE_LOG1 ("WFMO invalid handle %d removed", j);
1903 for (k = 0 ; k < nfds; k++)
1907 fds[k].for_read = fds[k].for_write = 0;
1911 TRACE_LOG (" oops, or not???");
1914 TRACE_LOG1 ("WFMO failed: %d", le);
1919 TRACE_LOG1 ("WFMO returned %d", code);
1925 TRACE_SEQ (dbg_help, "select OK [ ");
1926 for (i = 0; i < nfds; i++)
1928 if (fds[i].fd == -1)
1930 if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
1931 TRACE_ADD2 (dbg_help, "%c0x%x ",
1932 fds[i].for_read ? 'r' : 'w', fds[i].fd);
1934 TRACE_END (dbg_help, "]");
1939 /* FIXME: Should determine a proper error code. */
1940 gpg_err_set_errno (EIO);
1943 return TRACE_SYSRES (count);
1948 _gpgme_io_subsystem_init (void)
1950 /* Nothing to do. */
1954 /* Write the printable version of FD to the buffer BUF of length
1955 BUFLEN. The printable version is the representation on the command
1956 line that the child process expects. */
1958 _gpgme_io_fd2str (char *buf, int buflen, int fd)
1960 #ifdef HAVE_W32CE_SYSTEM
1961 /* FIXME: For now. See above. */
1962 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used
1963 || fd_table[fd].rvid == 0)
1966 fd = fd_table[fd].rvid;
1969 return snprintf (buf, buflen, "%d", fd);
1974 _gpgme_io_dup (int fd)
1977 struct reader_context_s *rd_ctx;
1978 struct writer_context_s *wt_ctx;
1981 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
1983 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1985 gpg_err_set_errno (EINVAL);
1986 return TRACE_SYSRES (-1);
1991 return TRACE_SYSRES (-1);
1993 fd_table[newfd].handle = fd_table[fd].handle;
1994 fd_table[newfd].socket = fd_table[fd].socket;
1995 fd_table[newfd].rvid = fd_table[fd].rvid;
1996 fd_table[newfd].dup_from = fd;
1998 rd_ctx = find_reader (fd, 0);
2001 /* No need for locking, as the only races are against the reader
2002 thread itself, which doesn't touch refcount. */
2005 LOCK (reader_table_lock);
2006 for (i = 0; i < reader_table_size; i++)
2007 if (!reader_table[i].used)
2010 assert (i != reader_table_size);
2011 reader_table[i].fd = newfd;
2012 reader_table[i].context = rd_ctx;
2013 reader_table[i].used = 1;
2014 UNLOCK (reader_table_lock);
2017 wt_ctx = find_writer (fd, 0);
2020 /* No need for locking, as the only races are against the writer
2021 thread itself, which doesn't touch refcount. */
2024 LOCK (writer_table_lock);
2025 for (i = 0; i < writer_table_size; i++)
2026 if (!writer_table[i].used)
2029 assert (i != writer_table_size);
2030 writer_table[i].fd = newfd;
2031 writer_table[i].context = wt_ctx;
2032 writer_table[i].used = 1;
2033 UNLOCK (writer_table_lock);
2036 return TRACE_SYSRES (newfd);
2040 /* The following interface is only useful for GPGME Glib and Qt. */
2042 /* Compatibility interface, obsolete. */
2044 gpgme_get_giochannel (int fd)
2050 /* Look up the giochannel or qiodevice for file descriptor FD. */
2052 gpgme_get_fdptr (int fd)
2065 case WSAEWOULDBLOCK:
2067 case ERROR_BROKEN_PIPE:
2069 case WSANOTINITIALISED:
2078 _gpgme_io_socket (int domain, int type, int proto)
2083 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
2084 "type=%i, protp=%i", type, proto);
2088 return TRACE_SYSRES (-1);
2090 res = socket (domain, type, proto);
2091 if (res == INVALID_SOCKET)
2094 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2095 return TRACE_SYSRES (-1);
2097 fd_table[fd].socket = res;
2099 TRACE_SUC2 ("socket=0x%x (0x%x)", fd, fd_table[fd].socket);
2106 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
2110 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
2111 "addr=%p, addrlen=%i", addr, addrlen);
2113 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
2115 gpg_err_set_errno (EBADF);
2116 return TRACE_SYSRES (-1);
2119 res = connect (fd_table[fd].socket, addr, addrlen);
2122 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2123 return TRACE_SYSRES (-1);
2126 return TRACE_SUC ();