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);
564 reader_table[i].fd = fd;
565 reader_table[i].context = rd;
566 reader_table[i].used = 1;
569 UNLOCK (reader_table_lock);
579 LOCK (reader_table_lock);
580 for (i = 0; i < reader_table_size; i++)
582 if (reader_table[i].used && reader_table[i].fd == fd)
584 destroy_reader (reader_table[i].context);
585 reader_table[i].context = NULL;
586 reader_table[i].used = 0;
590 UNLOCK (reader_table_lock);
595 _gpgme_io_read (int fd, void *buffer, size_t count)
598 struct reader_context_s *ctx;
599 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
600 "buffer=%p, count=%u", buffer, count);
602 ctx = find_reader (fd, 1);
605 gpg_err_set_errno (EBADF);
606 return TRACE_SYSRES (-1);
608 if (ctx->eof_shortcut)
609 return TRACE_SYSRES (0);
612 if (ctx->readpos == ctx->writepos && !ctx->error)
614 /* No data available. */
616 TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd);
617 WaitForSingleObject (ctx->have_data_ev, INFINITE);
618 TRACE_LOG1 ("data from thread %p available", ctx->thread_hd);
622 if (ctx->readpos == ctx->writepos || ctx->error)
625 ctx->eof_shortcut = 1;
627 return TRACE_SYSRES (0);
630 TRACE_LOG ("EOF but ctx->eof flag not set");
633 gpg_err_set_errno (ctx->error_code);
634 return TRACE_SYSRES (-1);
637 nread = ctx->readpos < ctx->writepos
638 ? ctx->writepos - ctx->readpos
639 : READBUF_SIZE - ctx->readpos;
642 memcpy (buffer, ctx->buffer + ctx->readpos, nread);
643 ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
644 if (ctx->readpos == ctx->writepos && !ctx->eof)
646 if (!ResetEvent (ctx->have_data_ev))
648 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
650 /* FIXME: Should translate the error code. */
651 gpg_err_set_errno (EIO);
652 return TRACE_SYSRES (-1);
655 if (!SetEvent (ctx->have_space_ev))
657 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d",
658 ctx->have_space_ev, (int) GetLastError ());
660 /* FIXME: Should translate the error code. */
661 gpg_err_set_errno (EIO);
662 return TRACE_SYSRES (-1);
666 TRACE_LOGBUF (buffer, nread);
667 return TRACE_SYSRES (nread);
671 /* The writer does use a simple buffering strategy so that we are
672 informed about write errors as soon as possible (i. e. with the the
673 next call to the write function. */
674 static DWORD CALLBACK
677 struct writer_context_s *ctx = arg;
680 TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
681 "thread=%p", ctx->thread_hd);
683 if (ctx->file_hd != INVALID_HANDLE_VALUE)
698 if (!SetEvent (ctx->is_empty))
699 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
700 if (!ResetEvent (ctx->have_data))
701 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
704 WaitForSingleObject (ctx->have_data, INFINITE);
705 TRACE_LOG ("got data to send");
715 TRACE_LOG2 ("%s %d bytes", sock?"sending":"writing", ctx->nbytes);
717 /* Note that CTX->nbytes is not zero at this point, because
718 _gpgme_io_write always writes at least 1 byte before waking
719 us up, unless CTX->stop_me is true, which we catch above. */
722 /* We need to try send first because a socket handle can't
723 be used with WriteFile. */
726 n = send (ctx->file_sock, ctx->buffer, ctx->nbytes, 0);
729 ctx->error_code = (int) WSAGetLastError ();
731 TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
738 if (!WriteFile (ctx->file_hd, ctx->buffer,
739 ctx->nbytes, &nwritten, NULL))
741 if (GetLastError () == ERROR_BUSY)
743 /* Probably stop_me is set now. */
744 TRACE_LOG ("pipe busy (unblocked?)");
748 ctx->error_code = (int) GetLastError ();
750 TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
754 TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
757 ctx->nbytes -= nwritten;
760 /* Indicate that we have an error. */
761 if (!SetEvent (ctx->is_empty))
762 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
763 SetEvent (ctx->stopped);
769 static struct writer_context_s *
770 create_writer (int fd)
772 struct writer_context_s *ctx;
773 SECURITY_ATTRIBUTES sec_attr;
776 TRACE_BEG (DEBUG_SYSIO, "gpgme:create_writer", fd);
778 memset (&sec_attr, 0, sizeof sec_attr);
779 sec_attr.nLength = sizeof sec_attr;
780 sec_attr.bInheritHandle = FALSE;
782 ctx = calloc (1, sizeof *ctx);
785 TRACE_SYSERR (errno);
789 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
794 ctx->file_hd = fd_table[fd].handle;
795 ctx->file_sock = fd_table[fd].socket;
798 ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
800 ctx->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
802 ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
803 if (!ctx->have_data || !ctx->is_empty || !ctx->stopped)
805 TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
807 CloseHandle (ctx->have_data);
809 CloseHandle (ctx->is_empty);
811 CloseHandle (ctx->stopped);
813 /* FIXME: Translate the error code. */
818 ctx->is_empty = set_synchronize (ctx->is_empty);
819 INIT_LOCK (ctx->mutex);
821 ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
824 TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
825 DESTROY_LOCK (ctx->mutex);
827 CloseHandle (ctx->have_data);
829 CloseHandle (ctx->is_empty);
831 CloseHandle (ctx->stopped);
838 /* We set the priority of the thread higher because we know
839 that it only runs for a short time. This greatly helps to
840 increase the performance of the I/O. */
841 SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
849 destroy_writer (struct writer_context_s *ctx)
853 if (ctx->refcount != 0)
860 SetEvent (ctx->have_data);
863 #ifdef HAVE_W32CE_SYSTEM
864 /* Scenario: We never create a full pipe, but already started
865 writing more than the pipe buffer. Then we need to unblock the
866 writer in the pipe driver to make our writer thread notice that
867 we want it to go away. */
869 if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
870 NULL, 0, NULL, 0, NULL, NULL))
872 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
873 "unblock control call failed for thread %p", ctx->thread_hd);
877 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
878 "waiting for termination of thread %p", ctx->thread_hd);
879 WaitForSingleObject (ctx->stopped, INFINITE);
880 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
881 "thread %p has terminated", ctx->thread_hd);
884 CloseHandle (ctx->stopped);
886 CloseHandle (ctx->have_data);
888 CloseHandle (ctx->is_empty);
889 CloseHandle (ctx->thread_hd);
890 DESTROY_LOCK (ctx->mutex);
895 /* Find a writer context or create a new one. Note that the writer
896 context will last until a _gpgme_io_close. */
897 static struct writer_context_s *
898 find_writer (int fd, int start_it)
900 struct writer_context_s *wt = NULL;
903 LOCK (writer_table_lock);
904 for (i = 0; i < writer_table_size; i++)
905 if (writer_table[i].used && writer_table[i].fd == fd)
906 wt = writer_table[i].context;
910 UNLOCK (writer_table_lock);
914 for (i = 0; i < writer_table_size; i++)
915 if (!writer_table[i].used)
918 if (i != writer_table_size)
920 wt = create_writer (fd);
921 writer_table[i].fd = fd;
922 writer_table[i].context = wt;
923 writer_table[i].used = 1;
926 UNLOCK (writer_table_lock);
936 LOCK (writer_table_lock);
937 for (i = 0; i < writer_table_size; i++)
939 if (writer_table[i].used && writer_table[i].fd == fd)
941 destroy_writer (writer_table[i].context);
942 writer_table[i].context = NULL;
943 writer_table[i].used = 0;
947 UNLOCK (writer_table_lock);
952 _gpgme_io_write (int fd, const void *buffer, size_t count)
954 struct writer_context_s *ctx;
955 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
956 "buffer=%p, count=%u", buffer, count);
957 TRACE_LOGBUF (buffer, count);
960 return TRACE_SYSRES (0);
962 ctx = find_writer (fd, 1);
964 return TRACE_SYSRES (-1);
967 if (!ctx->error && ctx->nbytes)
969 /* Bytes are pending for send. */
971 /* Reset the is_empty event. Better safe than sorry. */
972 if (!ResetEvent (ctx->is_empty))
974 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
976 /* FIXME: Should translate the error code. */
977 gpg_err_set_errno (EIO);
978 return TRACE_SYSRES (-1);
981 TRACE_LOG1 ("waiting for empty buffer in thread %p", ctx->thread_hd);
982 WaitForSingleObject (ctx->is_empty, INFINITE);
983 TRACE_LOG1 ("thread %p buffer is empty", ctx->thread_hd);
990 if (ctx->error_code == ERROR_NO_DATA)
991 gpg_err_set_errno (EPIPE);
993 gpg_err_set_errno (EIO);
994 return TRACE_SYSRES (-1);
997 /* If no error occured, the number of bytes in the buffer must be
999 assert (!ctx->nbytes);
1001 if (count > WRITEBUF_SIZE)
1002 count = WRITEBUF_SIZE;
1003 memcpy (ctx->buffer, buffer, count);
1004 ctx->nbytes = count;
1006 /* We have to reset the is_empty event early, because it is also
1007 used by the select() implementation to probe the channel. */
1008 if (!ResetEvent (ctx->is_empty))
1010 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
1011 UNLOCK (ctx->mutex);
1012 /* FIXME: Should translate the error code. */
1013 gpg_err_set_errno (EIO);
1014 return TRACE_SYSRES (-1);
1016 if (!SetEvent (ctx->have_data))
1018 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
1019 UNLOCK (ctx->mutex);
1020 /* FIXME: Should translate the error code. */
1021 gpg_err_set_errno (EIO);
1022 return TRACE_SYSRES (-1);
1024 UNLOCK (ctx->mutex);
1026 return TRACE_SYSRES ((int) count);
1031 _gpgme_io_pipe (int filedes[2], int inherit_idx)
1035 #ifdef HAVE_W32CE_SYSTEM
1041 SECURITY_ATTRIBUTES sec_attr;
1044 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
1045 "inherit_idx=%i (GPGME uses it for %s)",
1046 inherit_idx, inherit_idx ? "reading" : "writing");
1050 return TRACE_SYSRES (-1);
1055 return TRACE_SYSRES (-1);
1058 #ifdef HAVE_W32CE_SYSTEM
1059 hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
1060 if (hd == INVALID_HANDLE_VALUE)
1062 TRACE_LOG1 ("_assuan_w32ce_prepare_pipe failed: ec=%d",
1063 (int) GetLastError ());
1066 /* FIXME: Should translate the error code. */
1067 gpg_err_set_errno (EIO);
1068 return TRACE_SYSRES (-1);
1071 if (inherit_idx == 0)
1073 fd_table[rfd].rvid = rvid;
1074 fd_table[wfd].handle = hd;
1078 fd_table[rfd].handle = hd;
1079 fd_table[wfd].rvid = rvid;
1084 memset (&sec_attr, 0, sizeof (sec_attr));
1085 sec_attr.nLength = sizeof (sec_attr);
1086 sec_attr.bInheritHandle = FALSE;
1088 if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
1090 TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
1093 /* FIXME: Should translate the error code. */
1094 gpg_err_set_errno (EIO);
1095 return TRACE_SYSRES (-1);
1098 /* Make one end inheritable. */
1099 if (inherit_idx == 0)
1102 if (!DuplicateHandle (GetCurrentProcess(), rh,
1103 GetCurrentProcess(), &hd, 0,
1104 TRUE, DUPLICATE_SAME_ACCESS))
1106 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1107 (int) GetLastError ());
1112 /* FIXME: Should translate the error code. */
1113 gpg_err_set_errno (EIO);
1114 return TRACE_SYSRES (-1);
1119 else if (inherit_idx == 1)
1122 if (!DuplicateHandle( GetCurrentProcess(), wh,
1123 GetCurrentProcess(), &hd, 0,
1124 TRUE, DUPLICATE_SAME_ACCESS))
1126 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1127 (int) GetLastError ());
1132 /* FIXME: Should translate the error code. */
1133 gpg_err_set_errno (EIO);
1134 return TRACE_SYSRES (-1);
1139 fd_table[rfd].handle = rh;
1140 fd_table[wfd].handle = wh;
1145 return TRACE_SUC6 ("read=0x%x (%p/0x%x), write=0x%x (%p/0x%x)",
1146 rfd, fd_table[rfd].handle, fd_table[rfd].rvid,
1147 wfd, fd_table[wfd].handle, fd_table[wfd].rvid);
1152 _gpgme_io_close (int fd)
1155 _gpgme_close_notify_handler_t handler = NULL;
1158 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
1162 gpg_err_set_errno (EBADF);
1163 return TRACE_SYSRES (-1);
1165 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1167 gpg_err_set_errno (EBADF);
1168 return TRACE_SYSRES (-1);
1173 LOCK (notify_table_lock);
1174 for (i = 0; i < DIM (notify_table); i++)
1176 if (notify_table[i].inuse && notify_table[i].fd == fd)
1178 handler = notify_table[i].handler;
1179 value = notify_table[i].value;
1180 notify_table[i].handler = NULL;
1181 notify_table[i].value = NULL;
1182 notify_table[i].inuse = 0;
1186 UNLOCK (notify_table_lock);
1188 handler (fd, value);
1190 if (fd_table[fd].dup_from == -1)
1192 if (fd_table[fd].handle != INVALID_HANDLE_VALUE)
1194 if (!CloseHandle (fd_table[fd].handle))
1196 TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ());
1197 /* FIXME: Should translate the error code. */
1198 gpg_err_set_errno (EIO);
1199 return TRACE_SYSRES (-1);
1202 else if (fd_table[fd].socket != INVALID_SOCKET)
1204 if (closesocket (fd_table[fd].socket))
1206 TRACE_LOG1 ("closesocket failed: ec=%d", (int) WSAGetLastError ());
1207 /* FIXME: Should translate the error code. */
1208 gpg_err_set_errno (EIO);
1209 return TRACE_SYSRES (-1);
1212 /* Nothing to do for RVIDs. */
1217 return TRACE_SYSRES (0);
1222 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
1226 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
1227 "close_handler=%p/%p", handler, value);
1231 LOCK (notify_table_lock);
1232 for (i=0; i < DIM (notify_table); i++)
1233 if (notify_table[i].inuse && notify_table[i].fd == fd)
1235 if (i == DIM (notify_table))
1236 for (i = 0; i < DIM (notify_table); i++)
1237 if (!notify_table[i].inuse)
1239 if (i == DIM (notify_table))
1241 UNLOCK (notify_table_lock);
1242 gpg_err_set_errno (EINVAL);
1243 return TRACE_SYSRES (-1);
1245 notify_table[i].fd = fd;
1246 notify_table[i].handler = handler;
1247 notify_table[i].value = value;
1248 notify_table[i].inuse = 1;
1249 UNLOCK (notify_table_lock);
1250 return TRACE_SYSRES (0);
1255 _gpgme_io_set_nonblocking (int fd)
1257 TRACE (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
1262 #ifdef HAVE_W32CE_SYSTEM
1264 build_commandline (char **argv, int fd0, int fd0_isnull,
1265 int fd1, int fd1_isnull,
1266 int fd2, int fd2_isnull)
1279 strcpy (p, "-&S0=null ");
1281 snprintf (p, 25, "-&S0=%d ", fd_table[fd0].rvid);
1287 strcpy (p, "-&S1=null ");
1289 snprintf (p, 25, "-&S1=%d ", fd_table[fd1].rvid);
1295 strcpy (p, "-&S2=null ");
1297 snprintf (p, 25, "-&S2=%d ", fd_table[fd2].rvid);
1300 strcpy (p, "-&S2=null ");
1304 for (i=0; (s = argv[i]); i++)
1307 continue; /* Ignore argv[0]. */
1308 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting) */
1311 n++; /* Need to double inner quotes. */
1314 buf = p = malloc (n);
1318 p = stpcpy (p, fdbuf);
1319 for (i = 0; argv[i]; i++)
1322 continue; /* Ignore argv[0]. */
1324 p = stpcpy (p, " ");
1326 if (! *argv[i]) /* Empty string. */
1327 p = stpcpy (p, "\"\"");
1328 else if (strpbrk (argv[i], " \t\n\v\f\""))
1330 p = stpcpy (p, "\"");
1331 for (s = argv[i]; *s; s++)
1341 p = stpcpy (p, argv[i]);
1348 build_commandline (char **argv)
1355 /* We have to quote some things because under Windows the program
1356 parses the commandline and does some unquoting. We enclose the
1357 whole argument in double-quotes, and escape literal double-quotes
1358 as well as backslashes with a backslash. We end up with a
1359 trailing space at the end of the line, but that is harmless. */
1360 for (i = 0; argv[i]; i++)
1363 /* The leading double-quote. */
1367 /* An extra one for each literal that must be escaped. */
1368 if (*p == '\\' || *p == '"')
1373 /* The trailing double-quote and the delimiter. */
1376 /* And a trailing zero. */
1379 buf = p = malloc (n);
1382 for (i = 0; argv[i]; i++)
1384 char *argvp = argv[i];
1389 if (*argvp == '\\' || *argvp == '"')
1391 *(p++) = *(argvp++);
1404 _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
1405 struct spawn_fd_item_s *fd_list,
1406 void (*atfork) (void *opaque, int reserved),
1407 void *atforkvalue, pid_t *r_pid)
1409 PROCESS_INFORMATION pi =
1411 NULL, /* returns process handle */
1412 0, /* returns primary thread handle */
1413 0, /* returns pid */
1418 #ifdef HAVE_W32CE_SYSTEM
1422 int fd_in_isnull = 1;
1423 int fd_out_isnull = 1;
1424 int fd_err_isnull = 1;
1426 HANDLE hd = INVALID_HANDLE_VALUE;
1428 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1433 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1437 for (i = 0; fd_list[i].fd != -1; i++)
1439 int fd = fd_list[i].fd;
1441 TRACE_LOG3 ("fd_list[%2i] = fd %i, dup_to %i", i, fd, fd_list[i].dup_to);
1442 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1444 TRACE_LOG1 ("invalid fd 0x%x", fd);
1445 gpg_err_set_errno (EBADF);
1446 return TRACE_SYSRES (-1);
1448 if (fd_table[fd].rvid == 0)
1450 TRACE_LOG1 ("fd 0x%x not inheritable (not an RVID)", fd);
1451 gpg_err_set_errno (EBADF);
1452 return TRACE_SYSRES (-1);
1455 if (fd_list[i].dup_to == 0)
1457 fd_in = fd_list[i].fd;
1460 else if (fd_list[i].dup_to == 1)
1462 fd_out = fd_list[i].fd;
1465 else if (fd_list[i].dup_to == 2)
1467 fd_err = fd_list[i].fd;
1472 cmdline = build_commandline (argv, fd_in, fd_in_isnull,
1473 fd_out, fd_out_isnull, fd_err, fd_err_isnull);
1476 TRACE_LOG1 ("build_commandline failed: %s", strerror (errno));
1477 return TRACE_SYSRES (-1);
1480 if (!CreateProcessA (path, /* Program to start. */
1481 cmdline, /* Command line arguments. */
1482 NULL, /* (not supported) */
1483 NULL, /* (not supported) */
1484 FALSE, /* (not supported) */
1485 (CREATE_SUSPENDED), /* Creation flags. */
1486 NULL, /* (not supported) */
1487 NULL, /* (not supported) */
1488 NULL, /* (not supported) */
1489 &pi /* Returns process information.*/
1492 TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1494 gpg_err_set_errno (EIO);
1495 return TRACE_SYSRES (-1);
1498 /* Create arbitrary pipe descriptor to send in ASSIGN_RVID
1499 commands. Errors are ignored. We don't need read or write access,
1500 as ASSIGN_RVID works without any permissions, yay! */
1501 hd = CreateFile (L"GPG1:", 0, 0,
1502 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1503 if (hd == INVALID_HANDLE_VALUE)
1505 TRACE_LOG1 ("CreateFile failed (ignored): ec=%d",
1506 (int) GetLastError ());
1509 /* Insert the inherited handles. */
1510 for (i = 0; fd_list[i].fd != -1; i++)
1512 /* Return the child name of this handle. */
1513 fd_list[i].peer_name = fd_table[fd_list[i].fd].rvid;
1515 if (hd != INVALID_HANDLE_VALUE)
1518 data[0] = (DWORD) fd_table[fd_list[i].fd].rvid;
1519 data[1] = pi.dwProcessId;
1520 if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_ASSIGN_RVID,
1521 data, sizeof (data), NULL, 0, NULL, NULL))
1523 TRACE_LOG3 ("ASSIGN_RVID(%i, %i) failed (ignored): %i",
1524 data[0], data[1], (int) GetLastError ());
1528 if (hd != INVALID_HANDLE_VALUE)
1532 SECURITY_ATTRIBUTES sec_attr;
1534 int cr_flags = CREATE_DEFAULT_ERROR_MODE;
1542 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1547 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1551 /* We do not inherit any handles by default, and just insert those
1552 handles we want the child to have afterwards. But some handle
1553 values occur on the command line, and we need to move
1554 stdin/out/err to the right location. So we use a wrapper program
1555 which gets the information from a temporary file. */
1556 if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
1558 TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
1559 return TRACE_SYSRES (-1);
1561 TRACE_LOG1 ("tmp_name = %s", tmp_name);
1563 args = calloc (2 + i + 1, sizeof (*args));
1564 args[0] = (char *) _gpgme_get_w32spawn_path ();
1567 memcpy (&args[3], &argv[1], i * sizeof (*args));
1569 memset (&sec_attr, 0, sizeof sec_attr);
1570 sec_attr.nLength = sizeof sec_attr;
1571 sec_attr.bInheritHandle = FALSE;
1573 arg_string = build_commandline (args);
1578 DeleteFileA (tmp_name);
1579 return TRACE_SYSRES (-1);
1582 memset (&si, 0, sizeof si);
1583 si.cb = sizeof (si);
1584 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1585 si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
1586 si.hStdInput = INVALID_HANDLE_VALUE;
1587 si.hStdOutput = INVALID_HANDLE_VALUE;
1588 si.hStdError = INVALID_HANDLE_VALUE;
1590 cr_flags |= CREATE_SUSPENDED;
1591 #ifndef HAVE_W32CE_SYSTEM
1592 cr_flags |= DETACHED_PROCESS;
1593 cr_flags |= GetPriorityClass (GetCurrentProcess ());
1595 if (!CreateProcessA (_gpgme_get_w32spawn_path (),
1597 &sec_attr, /* process security attributes */
1598 &sec_attr, /* thread security attributes */
1599 FALSE, /* inherit handles */
1600 cr_flags, /* creation flags */
1601 NULL, /* environment */
1602 NULL, /* use current drive/directory */
1603 &si, /* startup information */
1604 &pi)) /* returns process information */
1606 TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1609 DeleteFileA (tmp_name);
1611 /* FIXME: Should translate the error code. */
1612 gpg_err_set_errno (EIO);
1613 return TRACE_SYSRES (-1);
1618 if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
1619 _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
1621 /* Insert the inherited handles. */
1622 for (i = 0; fd_list[i].fd != -1; i++)
1626 /* Make it inheritable for the wrapper process. */
1627 if (!DuplicateHandle (GetCurrentProcess(), fd_to_handle (fd_list[i].fd),
1628 pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
1630 TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
1631 TerminateProcess (pi.hProcess, 0);
1632 /* Just in case TerminateProcess didn't work, let the
1633 process fail on its own. */
1634 ResumeThread (pi.hThread);
1635 CloseHandle (pi.hThread);
1636 CloseHandle (pi.hProcess);
1639 DeleteFileA (tmp_name);
1641 /* FIXME: Should translate the error code. */
1642 gpg_err_set_errno (EIO);
1643 return TRACE_SYSRES (-1);
1645 /* Return the child name of this handle. */
1646 fd_list[i].peer_name = handle_to_fd (hd);
1649 /* Write the handle translation information to the temporary
1652 /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
1653 notation: "0xFEDCBA9876543210" with an extra white space after
1654 every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead
1655 for a time when a HANDLE is 64 bit. */
1656 #define BUFFER_MAX 810
1657 char line[BUFFER_MAX + 1];
1662 if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
1663 strcpy (line, "~1 \n");
1665 strcpy (line, "\n");
1666 for (i = 0; fd_list[i].fd != -1; i++)
1668 /* Strip the newline. */
1669 len = strlen (line) - 1;
1671 /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx. */
1672 snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d \n",
1673 fd_list[i].fd, fd_list[i].dup_to,
1674 fd_list[i].peer_name, fd_list[i].arg_loc);
1675 /* Rather safe than sorry. */
1676 line[BUFFER_MAX - 1] = '\n';
1677 line[BUFFER_MAX] = '\0';
1679 len = strlen (line);
1683 res = write (tmp_fd, &line[written], len - written);
1687 while (res > 0 || (res < 0 && errno == EAGAIN));
1690 /* The temporary file is deleted by the gpgme-w32spawn process
1695 TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
1696 "dwProcessID=%d, dwThreadId=%d",
1697 pi.hProcess, pi.hThread,
1698 (int) pi.dwProcessId, (int) pi.dwThreadId);
1701 *r_pid = (pid_t)pi.dwProcessId;
1704 if (ResumeThread (pi.hThread) < 0)
1705 TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
1707 if (!CloseHandle (pi.hThread))
1708 TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
1709 (int) GetLastError ());
1711 TRACE_LOG1 ("process=%p", pi.hProcess);
1713 /* We don't need to wait for the process. */
1714 if (!CloseHandle (pi.hProcess))
1715 TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
1716 (int) GetLastError ());
1718 if (! (flags & IOSPAWN_FLAG_NOCLOSE))
1720 for (i = 0; fd_list[i].fd != -1; i++)
1721 _gpgme_io_close (fd_list[i].fd);
1724 for (i = 0; fd_list[i].fd != -1; i++)
1725 if (fd_list[i].dup_to == -1)
1726 TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
1727 fd_list[i].peer_name);
1729 TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
1730 fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
1731 ((fd_list[i].dup_to == 1) ? "out" : "err"));
1733 return TRACE_SYSRES (0);
1737 /* Select on the list of fds. Returns: -1 = error, 0 = timeout or
1738 nothing to select, > 0 = number of signaled fds. */
1740 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
1742 HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1743 int waitidx[MAXIMUM_WAIT_OBJECTS];
1750 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
1751 "nfds=%u, nonblock=%u", nfds, nonblock);
1754 TRACE_SEQ (dbg_help, "select on [ ");
1758 for (i=0; i < nfds; i++)
1760 if (fds[i].fd == -1)
1762 fds[i].signaled = 0;
1763 if (fds[i].for_read || fds[i].for_write)
1765 if (fds[i].for_read)
1767 struct reader_context_s *ctx = find_reader (fds[i].fd,1);
1770 TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
1774 if (nwait >= DIM (waitbuf))
1776 TRACE_END (dbg_help, "oops ]");
1777 TRACE_LOG ("Too many objects for WFMO!");
1778 /* FIXME: Should translate the error code. */
1779 gpg_err_set_errno (EIO);
1780 return TRACE_SYSRES (-1);
1783 waitbuf[nwait++] = ctx->have_data_ev;
1785 TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
1788 else if (fds[i].for_write)
1790 struct writer_context_s *ctx = find_writer (fds[i].fd,1);
1793 TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
1797 if (nwait >= DIM (waitbuf))
1799 TRACE_END (dbg_help, "oops ]");
1800 TRACE_LOG ("Too many objects for WFMO!");
1801 /* FIXME: Should translate the error code. */
1802 gpg_err_set_errno (EIO);
1803 return TRACE_SYSRES (-1);
1806 waitbuf[nwait++] = ctx->is_empty;
1808 TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
1813 TRACE_END (dbg_help, "]");
1815 return TRACE_SYSRES (0);
1817 code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
1818 if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
1820 /* This WFMO is a really silly function: It does return either
1821 the index of the signaled object or if 2 objects have been
1822 signalled at the same time, the index of the object with the
1823 lowest object is returned - so and how do we find out how
1824 many objects have been signaled???. The only solution I can
1825 imagine is to test each object starting with the returned
1826 index individually - how dull. */
1828 for (i = code - WAIT_OBJECT_0; i < nwait; i++)
1830 if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
1832 assert (waitidx[i] >=0 && waitidx[i] < nfds);
1833 fds[waitidx[i]].signaled = 1;
1840 TRACE_LOG ("no signaled objects found after WFMO");
1844 else if (code == WAIT_TIMEOUT)
1845 TRACE_LOG ("WFMO timed out");
1846 else if (code == WAIT_FAILED)
1848 int le = (int) GetLastError ();
1850 if (le == ERROR_INVALID_HANDLE)
1853 int j = handle_to_fd (waitbuf[i]);
1855 TRACE_LOG1 ("WFMO invalid handle %d removed", j);
1856 for (k = 0 ; k < nfds; k++)
1860 fds[k].for_read = fds[k].for_write = 0;
1864 TRACE_LOG (" oops, or not???");
1867 TRACE_LOG1 ("WFMO failed: %d", le);
1872 TRACE_LOG1 ("WFMO returned %d", code);
1878 TRACE_SEQ (dbg_help, "select OK [ ");
1879 for (i = 0; i < nfds; i++)
1881 if (fds[i].fd == -1)
1883 if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
1884 TRACE_ADD2 (dbg_help, "%c0x%x ",
1885 fds[i].for_read ? 'r' : 'w', fds[i].fd);
1887 TRACE_END (dbg_help, "]");
1892 /* FIXME: Should determine a proper error code. */
1893 gpg_err_set_errno (EIO);
1896 return TRACE_SYSRES (count);
1901 _gpgme_io_subsystem_init (void)
1903 /* Nothing to do. */
1907 /* Write the printable version of FD to the buffer BUF of length
1908 BUFLEN. The printable version is the representation on the command
1909 line that the child process expects. */
1911 _gpgme_io_fd2str (char *buf, int buflen, int fd)
1913 #ifdef HAVE_W32CE_SYSTEM
1914 /* FIXME: For now. See above. */
1915 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used
1916 || fd_table[fd].rvid == 0)
1919 fd = fd_table[fd].rvid;
1922 return snprintf (buf, buflen, "%d", fd);
1927 _gpgme_io_dup (int fd)
1930 struct reader_context_s *rd_ctx;
1931 struct writer_context_s *wt_ctx;
1934 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
1936 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1938 gpg_err_set_errno (EINVAL);
1939 return TRACE_SYSRES (-1);
1944 return TRACE_SYSRES (-1);
1946 fd_table[newfd].handle = fd_table[fd].handle;
1947 fd_table[newfd].socket = fd_table[fd].socket;
1948 fd_table[newfd].rvid = fd_table[fd].rvid;
1949 fd_table[newfd].dup_from = fd;
1951 rd_ctx = find_reader (fd, 1);
1954 /* No need for locking, as the only races are against the reader
1955 thread itself, which doesn't touch refcount. */
1958 LOCK (reader_table_lock);
1959 for (i = 0; i < reader_table_size; i++)
1960 if (!reader_table[i].used)
1963 assert (i != reader_table_size);
1964 reader_table[i].fd = newfd;
1965 reader_table[i].context = rd_ctx;
1966 reader_table[i].used = 1;
1967 UNLOCK (reader_table_lock);
1970 wt_ctx = find_writer (fd, 1);
1973 /* No need for locking, as the only races are against the writer
1974 thread itself, which doesn't touch refcount. */
1977 LOCK (writer_table_lock);
1978 for (i = 0; i < writer_table_size; i++)
1979 if (!writer_table[i].used)
1982 assert (i != writer_table_size);
1983 writer_table[i].fd = newfd;
1984 writer_table[i].context = wt_ctx;
1985 writer_table[i].used = 1;
1986 UNLOCK (writer_table_lock);
1989 return TRACE_SYSRES (newfd);
1993 /* The following interface is only useful for GPGME Glib and Qt. */
1995 /* Compatibility interface, obsolete. */
1997 gpgme_get_giochannel (int fd)
2003 /* Look up the giochannel or qiodevice for file descriptor FD. */
2005 gpgme_get_fdptr (int fd)
2018 case WSAEWOULDBLOCK:
2020 case ERROR_BROKEN_PIPE:
2022 case WSANOTINITIALISED:
2031 _gpgme_io_socket (int domain, int type, int proto)
2036 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
2037 "type=%i, protp=%i", type, proto);
2041 return TRACE_SYSRES (-1);
2043 res = socket (domain, type, proto);
2044 if (res == INVALID_SOCKET)
2047 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2048 return TRACE_SYSRES (-1);
2050 fd_table[fd].socket = res;
2052 TRACE_SUC2 ("socket=0x%x (0x%x)", fd, fd_table[fd].socket);
2059 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
2063 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
2064 "addr=%p, addrlen=%i", addr, addrlen);
2066 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
2068 gpg_err_set_errno (EBADF);
2069 return TRACE_SYSRES (-1);
2072 res = connect (fd_table[fd].socket, addr, addrlen);
2075 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2076 return TRACE_SYSRES (-1);
2079 return TRACE_SUC ();