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
31 #ifdef HAVE_SYS_TIME_H
32 # include <sys/time.h>
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
41 #ifdef HAVE_W32CE_SYSTEM
44 #define GPGCEDEV_IOCTL_UNBLOCK \
45 CTL_CODE (FILE_DEVICE_STREAMS, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS)
46 #define GPGCEDEV_IOCTL_ASSIGN_RVID \
47 CTL_CODE (FILE_DEVICE_STREAMS, 2051, METHOD_BUFFERED, FILE_ANY_ACCESS)
55 /* FIXME: Optimize. */
62 /* If this is not INVALID_HANDLE_VALUE, then it's a handle. */
65 /* If this is not INVALID_SOCKET, then it's a Windows socket. */
68 /* If this is not 0, then it's a rendezvous ID for the pipe server. */
71 /* DUP_FROM is -1 if this file descriptor was allocated by pipe or
72 socket functions. Only then should the handle or socket be
73 destroyed when this FD is closed. This, together with the fact
74 that dup'ed file descriptors are closed before the file
75 descriptors from which they are dup'ed are closed, ensures that
76 the handle or socket is always valid, and shared among all file
77 descriptors refering to the same underlying object.
79 The logic behind this is that there is only one reason for us to
80 dup file descriptors anyway: to allow simpler book-keeping of
81 file descriptors shared between GPGME and libassuan, which both
82 want to close something. Using the same handle for these
83 duplicates works just fine. */
85 } fd_table[MAX_SLAFD];
88 /* Returns the FD or -1 on resource limit. */
94 for (idx = 0; idx < MAX_SLAFD; idx++)
95 if (! fd_table[idx].used)
100 gpg_err_set_errno (EIO);
104 fd_table[idx].used = 1;
105 fd_table[idx].handle = INVALID_HANDLE_VALUE;
106 fd_table[idx].socket = INVALID_SOCKET;
107 fd_table[idx].rvid = 0;
108 fd_table[idx].dup_from = -1;
117 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
120 fd_table[fd].used = 0;
121 fd_table[fd].handle = INVALID_HANDLE_VALUE;
122 fd_table[fd].socket = INVALID_SOCKET;
123 fd_table[fd].rvid = 0;
124 fd_table[fd].dup_from = -1;
128 #define handle_to_fd(a) ((int)(a))
130 #define READBUF_SIZE 4096
131 #define WRITEBUF_SIZE 4096
132 #define PIPEBUF_SIZE 4096
133 #define MAX_READERS 64
134 #define MAX_WRITERS 64
140 _gpgme_close_notify_handler_t handler;
142 } notify_table[MAX_SLAFD];
143 DEFINE_STATIC_LOCK (notify_table_lock);
146 struct reader_context_s
153 DECLARE_LOCK (mutex);
161 /* This is manually reset. */
163 /* This is automatically reset. */
164 HANDLE have_space_ev;
166 size_t readpos, writepos;
167 char buffer[READBUF_SIZE];
175 struct reader_context_s *context;
176 } reader_table[MAX_READERS];
177 static int reader_table_size= MAX_READERS;
178 DEFINE_STATIC_LOCK (reader_table_lock);
181 struct writer_context_s
188 DECLARE_LOCK (mutex);
194 /* This is manually reset. */
199 char buffer[WRITEBUF_SIZE];
207 struct writer_context_s *context;
208 } writer_table[MAX_WRITERS];
209 static int writer_table_size= MAX_WRITERS;
210 DEFINE_STATIC_LOCK (writer_table_lock);
214 get_desired_thread_priority (void)
218 if (!_gpgme_get_conf_int ("IOThreadPriority", &value))
220 value = THREAD_PRIORITY_HIGHEST;
221 TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
222 "%d (default)", value);
226 TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
227 "%d (configured)", value);
234 set_synchronize (HANDLE hd)
236 #ifdef HAVE_W32CE_SYSTEM
241 /* For NT we have to set the sync flag. It seems that the only way
242 to do it is by duplicating the handle. Tsss... */
243 if (!DuplicateHandle (GetCurrentProcess (), hd,
244 GetCurrentProcess (), &new_hd,
245 EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0))
247 TRACE1 (DEBUG_SYSIO, "gpgme:set_synchronize", hd,
248 "DuplicateHandle failed: ec=%d", (int) GetLastError ());
249 /* FIXME: Should translate the error code. */
250 gpg_err_set_errno (EIO);
251 return INVALID_HANDLE_VALUE;
260 static DWORD CALLBACK
263 struct reader_context_s *ctx = arg;
267 TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
268 "thread=%p", ctx->thread_hd);
270 if (ctx->file_hd != INVALID_HANDLE_VALUE)
278 /* Leave a 1 byte gap so that we can see whether it is empty or
280 if ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
282 /* Wait for space. */
283 if (!ResetEvent (ctx->have_space_ev))
284 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
286 TRACE_LOG ("waiting for space");
287 WaitForSingleObject (ctx->have_space_ev, INFINITE);
288 TRACE_LOG ("got space");
296 nbytes = (ctx->readpos + READBUF_SIZE
297 - ctx->writepos - 1) % READBUF_SIZE;
298 if (nbytes > READBUF_SIZE - ctx->writepos)
299 nbytes = READBUF_SIZE - ctx->writepos;
302 TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes);
308 n = recv (ctx->file_sock, ctx->buffer + ctx->writepos, nbytes, 0);
311 ctx->error_code = (int) WSAGetLastError ();
312 if (ctx->error_code == ERROR_BROKEN_PIPE)
315 TRACE_LOG ("got EOF (broken connection)");
320 TRACE_LOG1 ("recv error: ec=%d", ctx->error_code);
328 if (!ReadFile (ctx->file_hd,
329 ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
331 ctx->error_code = (int) GetLastError ();
332 /* NOTE (W32CE): Do not ignore ERROR_BUSY! Check at
333 least stop_me if that happens. */
334 if (ctx->error_code == ERROR_BROKEN_PIPE)
337 TRACE_LOG ("got EOF (broken pipe)");
342 TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
356 TRACE_LOG ("got eof");
360 TRACE_LOG1 ("got %u bytes", nread);
362 ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
363 if (!SetEvent (ctx->have_data_ev))
364 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
365 (int) GetLastError ());
368 /* Indicate that we have an error or EOF. */
369 if (!SetEvent (ctx->have_data_ev))
370 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
371 (int) GetLastError ());
372 SetEvent (ctx->stopped);
378 static struct reader_context_s *
379 create_reader (int fd)
381 struct reader_context_s *ctx;
382 SECURITY_ATTRIBUTES sec_attr;
385 TRACE_BEG (DEBUG_SYSIO, "gpgme:create_reader", fd);
387 memset (&sec_attr, 0, sizeof sec_attr);
388 sec_attr.nLength = sizeof sec_attr;
389 sec_attr.bInheritHandle = FALSE;
391 ctx = calloc (1, sizeof *ctx);
394 TRACE_SYSERR (errno);
398 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
403 ctx->file_hd = fd_table[fd].handle;
404 ctx->file_sock = fd_table[fd].socket;
407 ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
408 if (ctx->have_data_ev)
409 ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
410 if (ctx->have_space_ev)
411 ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
412 if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->stopped)
414 TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
415 if (ctx->have_data_ev)
416 CloseHandle (ctx->have_data_ev);
417 if (ctx->have_space_ev)
418 CloseHandle (ctx->have_space_ev);
420 CloseHandle (ctx->stopped);
422 /* FIXME: Translate the error code. */
427 ctx->have_data_ev = set_synchronize (ctx->have_data_ev);
428 INIT_LOCK (ctx->mutex);
430 #ifdef HAVE_W32CE_SYSTEM
431 ctx->thread_hd = CreateThread (&sec_attr, 64 * 1024, reader, ctx,
432 STACK_SIZE_PARAM_IS_A_RESERVATION, &tid);
434 ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid);
439 TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
440 DESTROY_LOCK (ctx->mutex);
441 if (ctx->have_data_ev)
442 CloseHandle (ctx->have_data_ev);
443 if (ctx->have_space_ev)
444 CloseHandle (ctx->have_space_ev);
446 CloseHandle (ctx->stopped);
453 /* We set the priority of the thread higher because we know that
454 it only runs for a short time. This greatly helps to
455 increase the performance of the I/O. */
456 SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
465 destroy_reader (struct reader_context_s *ctx)
469 if (ctx->refcount != 0)
475 if (ctx->have_space_ev)
476 SetEvent (ctx->have_space_ev);
479 #ifdef HAVE_W32CE_SYSTEM
480 /* Scenario: We never create a full pipe, but already started
481 reading. Then we need to unblock the reader in the pipe driver
482 to make our reader thread notice that we want it to go away. */
484 if (ctx->file_hd != INVALID_HANDLE_VALUE)
486 if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
487 NULL, 0, NULL, 0, NULL, NULL))
489 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
490 "unblock control call failed for thread %p", ctx->thread_hd);
495 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
496 "waiting for termination of thread %p", ctx->thread_hd);
497 WaitForSingleObject (ctx->stopped, INFINITE);
498 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
499 "thread %p has terminated", ctx->thread_hd);
502 CloseHandle (ctx->stopped);
503 if (ctx->have_data_ev)
504 CloseHandle (ctx->have_data_ev);
505 if (ctx->have_space_ev)
506 CloseHandle (ctx->have_space_ev);
507 CloseHandle (ctx->thread_hd);
508 DESTROY_LOCK (ctx->mutex);
513 /* Find a reader context or create a new one. Note that the reader
514 context will last until a _gpgme_io_close. */
515 static struct reader_context_s *
516 find_reader (int fd, int start_it)
518 struct reader_context_s *rd = NULL;
521 LOCK (reader_table_lock);
522 for (i = 0; i < reader_table_size; i++)
523 if (reader_table[i].used && reader_table[i].fd == fd)
524 rd = reader_table[i].context;
528 UNLOCK (reader_table_lock);
532 for (i = 0; i < reader_table_size; i++)
533 if (!reader_table[i].used)
536 if (i != reader_table_size)
538 rd = create_reader (fd);
539 reader_table[i].fd = fd;
540 reader_table[i].context = rd;
541 reader_table[i].used = 1;
544 UNLOCK (reader_table_lock);
554 LOCK (reader_table_lock);
555 for (i = 0; i < reader_table_size; i++)
557 if (reader_table[i].used && reader_table[i].fd == fd)
559 destroy_reader (reader_table[i].context);
560 reader_table[i].context = NULL;
561 reader_table[i].used = 0;
565 UNLOCK (reader_table_lock);
570 _gpgme_io_read (int fd, void *buffer, size_t count)
573 struct reader_context_s *ctx;
574 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
575 "buffer=%p, count=%u", buffer, count);
577 ctx = find_reader (fd, 1);
580 gpg_err_set_errno (EBADF);
581 return TRACE_SYSRES (-1);
583 if (ctx->eof_shortcut)
584 return TRACE_SYSRES (0);
587 if (ctx->readpos == ctx->writepos && !ctx->error)
589 /* No data available. */
591 TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd);
592 WaitForSingleObject (ctx->have_data_ev, INFINITE);
593 TRACE_LOG1 ("data from thread %p available", ctx->thread_hd);
597 if (ctx->readpos == ctx->writepos || ctx->error)
600 ctx->eof_shortcut = 1;
602 return TRACE_SYSRES (0);
605 TRACE_LOG ("EOF but ctx->eof flag not set");
608 gpg_err_set_errno (ctx->error_code);
609 return TRACE_SYSRES (-1);
612 nread = ctx->readpos < ctx->writepos
613 ? ctx->writepos - ctx->readpos
614 : READBUF_SIZE - ctx->readpos;
617 memcpy (buffer, ctx->buffer + ctx->readpos, nread);
618 ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
619 if (ctx->readpos == ctx->writepos && !ctx->eof)
621 if (!ResetEvent (ctx->have_data_ev))
623 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
625 /* FIXME: Should translate the error code. */
626 gpg_err_set_errno (EIO);
627 return TRACE_SYSRES (-1);
630 if (!SetEvent (ctx->have_space_ev))
632 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d",
633 ctx->have_space_ev, (int) GetLastError ());
635 /* FIXME: Should translate the error code. */
636 gpg_err_set_errno (EIO);
637 return TRACE_SYSRES (-1);
641 TRACE_LOGBUF (buffer, nread);
642 return TRACE_SYSRES (nread);
646 /* The writer does use a simple buffering strategy so that we are
647 informed about write errors as soon as possible (i. e. with the the
648 next call to the write function. */
649 static DWORD CALLBACK
652 struct writer_context_s *ctx = arg;
655 TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
656 "thread=%p", ctx->thread_hd);
658 if (ctx->file_hd != INVALID_HANDLE_VALUE)
673 if (!SetEvent (ctx->is_empty))
674 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
675 if (!ResetEvent (ctx->have_data))
676 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
679 WaitForSingleObject (ctx->have_data, INFINITE);
680 TRACE_LOG ("got data to send");
690 TRACE_LOG2 ("%s %d bytes", sock?"sending":"writing", ctx->nbytes);
692 /* Note that CTX->nbytes is not zero at this point, because
693 _gpgme_io_write always writes at least 1 byte before waking
694 us up, unless CTX->stop_me is true, which we catch above. */
697 /* We need to try send first because a socket handle can't
698 be used with WriteFile. */
701 n = send (ctx->file_sock, ctx->buffer, ctx->nbytes, 0);
704 ctx->error_code = (int) WSAGetLastError ();
706 TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
713 if (!WriteFile (ctx->file_hd, ctx->buffer,
714 ctx->nbytes, &nwritten, NULL))
716 if (GetLastError () == ERROR_BUSY)
718 /* Probably stop_me is set now. */
719 TRACE_LOG ("pipe busy (unblocked?)");
723 ctx->error_code = (int) GetLastError ();
725 TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
729 TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
732 ctx->nbytes -= nwritten;
735 /* Indicate that we have an error. */
736 if (!SetEvent (ctx->is_empty))
737 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
738 SetEvent (ctx->stopped);
744 static struct writer_context_s *
745 create_writer (int fd)
747 struct writer_context_s *ctx;
748 SECURITY_ATTRIBUTES sec_attr;
751 TRACE_BEG (DEBUG_SYSIO, "gpgme:create_writer", fd);
753 memset (&sec_attr, 0, sizeof sec_attr);
754 sec_attr.nLength = sizeof sec_attr;
755 sec_attr.bInheritHandle = FALSE;
757 ctx = calloc (1, sizeof *ctx);
760 TRACE_SYSERR (errno);
764 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
769 ctx->file_hd = fd_table[fd].handle;
770 ctx->file_sock = fd_table[fd].socket;
773 ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
775 ctx->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
777 ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
778 if (!ctx->have_data || !ctx->is_empty || !ctx->stopped)
780 TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
782 CloseHandle (ctx->have_data);
784 CloseHandle (ctx->is_empty);
786 CloseHandle (ctx->stopped);
788 /* FIXME: Translate the error code. */
793 ctx->is_empty = set_synchronize (ctx->is_empty);
794 INIT_LOCK (ctx->mutex);
796 #ifdef HAVE_W32CE_SYSTEM
797 ctx->thread_hd = CreateThread (&sec_attr, 64 * 1024, writer, ctx,
798 STACK_SIZE_PARAM_IS_A_RESERVATION, &tid);
800 ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
805 TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
806 DESTROY_LOCK (ctx->mutex);
808 CloseHandle (ctx->have_data);
810 CloseHandle (ctx->is_empty);
812 CloseHandle (ctx->stopped);
819 /* We set the priority of the thread higher because we know
820 that it only runs for a short time. This greatly helps to
821 increase the performance of the I/O. */
822 SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
830 destroy_writer (struct writer_context_s *ctx)
834 if (ctx->refcount != 0)
841 SetEvent (ctx->have_data);
844 #ifdef HAVE_W32CE_SYSTEM
845 /* Scenario: We never create a full pipe, but already started
846 writing more than the pipe buffer. Then we need to unblock the
847 writer in the pipe driver to make our writer thread notice that
848 we want it to go away. */
850 if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
851 NULL, 0, NULL, 0, NULL, NULL))
853 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
854 "unblock control call failed for thread %p", ctx->thread_hd);
858 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
859 "waiting for termination of thread %p", ctx->thread_hd);
860 WaitForSingleObject (ctx->stopped, INFINITE);
861 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
862 "thread %p has terminated", ctx->thread_hd);
865 CloseHandle (ctx->stopped);
867 CloseHandle (ctx->have_data);
869 CloseHandle (ctx->is_empty);
870 CloseHandle (ctx->thread_hd);
871 DESTROY_LOCK (ctx->mutex);
876 /* Find a writer context or create a new one. Note that the writer
877 context will last until a _gpgme_io_close. */
878 static struct writer_context_s *
879 find_writer (int fd, int start_it)
881 struct writer_context_s *wt = NULL;
884 LOCK (writer_table_lock);
885 for (i = 0; i < writer_table_size; i++)
886 if (writer_table[i].used && writer_table[i].fd == fd)
887 wt = writer_table[i].context;
891 UNLOCK (writer_table_lock);
895 for (i = 0; i < writer_table_size; i++)
896 if (!writer_table[i].used)
899 if (i != writer_table_size)
901 wt = create_writer (fd);
902 writer_table[i].fd = fd;
903 writer_table[i].context = wt;
904 writer_table[i].used = 1;
907 UNLOCK (writer_table_lock);
917 LOCK (writer_table_lock);
918 for (i = 0; i < writer_table_size; i++)
920 if (writer_table[i].used && writer_table[i].fd == fd)
922 destroy_writer (writer_table[i].context);
923 writer_table[i].context = NULL;
924 writer_table[i].used = 0;
928 UNLOCK (writer_table_lock);
933 _gpgme_io_write (int fd, const void *buffer, size_t count)
935 struct writer_context_s *ctx;
936 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
937 "buffer=%p, count=%u", buffer, count);
938 TRACE_LOGBUF (buffer, count);
941 return TRACE_SYSRES (0);
943 ctx = find_writer (fd, 1);
945 return TRACE_SYSRES (-1);
948 if (!ctx->error && ctx->nbytes)
950 /* Bytes are pending for send. */
952 /* Reset the is_empty event. Better safe than sorry. */
953 if (!ResetEvent (ctx->is_empty))
955 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
957 /* FIXME: Should translate the error code. */
958 gpg_err_set_errno (EIO);
959 return TRACE_SYSRES (-1);
962 TRACE_LOG1 ("waiting for empty buffer in thread %p", ctx->thread_hd);
963 WaitForSingleObject (ctx->is_empty, INFINITE);
964 TRACE_LOG1 ("thread %p buffer is empty", ctx->thread_hd);
971 if (ctx->error_code == ERROR_NO_DATA)
972 gpg_err_set_errno (EPIPE);
974 gpg_err_set_errno (EIO);
975 return TRACE_SYSRES (-1);
978 /* If no error occured, the number of bytes in the buffer must be
980 assert (!ctx->nbytes);
982 if (count > WRITEBUF_SIZE)
983 count = WRITEBUF_SIZE;
984 memcpy (ctx->buffer, buffer, count);
987 /* We have to reset the is_empty event early, because it is also
988 used by the select() implementation to probe the channel. */
989 if (!ResetEvent (ctx->is_empty))
991 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
993 /* FIXME: Should translate the error code. */
994 gpg_err_set_errno (EIO);
995 return TRACE_SYSRES (-1);
997 if (!SetEvent (ctx->have_data))
999 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
1000 UNLOCK (ctx->mutex);
1001 /* FIXME: Should translate the error code. */
1002 gpg_err_set_errno (EIO);
1003 return TRACE_SYSRES (-1);
1005 UNLOCK (ctx->mutex);
1007 return TRACE_SYSRES ((int) count);
1012 _gpgme_io_pipe (int filedes[2], int inherit_idx)
1016 #ifdef HAVE_W32CE_SYSTEM
1022 SECURITY_ATTRIBUTES sec_attr;
1025 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
1026 "inherit_idx=%i (GPGME uses it for %s)",
1027 inherit_idx, inherit_idx ? "reading" : "writing");
1031 return TRACE_SYSRES (-1);
1036 return TRACE_SYSRES (-1);
1039 #ifdef HAVE_W32CE_SYSTEM
1040 hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
1041 if (hd == INVALID_HANDLE_VALUE)
1043 TRACE_LOG1 ("_assuan_w32ce_prepare_pipe failed: ec=%d",
1044 (int) GetLastError ());
1047 /* FIXME: Should translate the error code. */
1048 gpg_err_set_errno (EIO);
1049 return TRACE_SYSRES (-1);
1052 if (inherit_idx == 0)
1054 fd_table[rfd].rvid = rvid;
1055 fd_table[wfd].handle = hd;
1059 fd_table[rfd].handle = hd;
1060 fd_table[wfd].rvid = rvid;
1065 memset (&sec_attr, 0, sizeof (sec_attr));
1066 sec_attr.nLength = sizeof (sec_attr);
1067 sec_attr.bInheritHandle = FALSE;
1069 if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
1071 TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
1074 /* FIXME: Should translate the error code. */
1075 gpg_err_set_errno (EIO);
1076 return TRACE_SYSRES (-1);
1079 /* Make one end inheritable. */
1080 if (inherit_idx == 0)
1083 if (!DuplicateHandle (GetCurrentProcess(), rh,
1084 GetCurrentProcess(), &hd, 0,
1085 TRUE, DUPLICATE_SAME_ACCESS))
1087 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1088 (int) GetLastError ());
1093 /* FIXME: Should translate the error code. */
1094 gpg_err_set_errno (EIO);
1095 return TRACE_SYSRES (-1);
1100 else if (inherit_idx == 1)
1103 if (!DuplicateHandle( GetCurrentProcess(), wh,
1104 GetCurrentProcess(), &hd, 0,
1105 TRUE, DUPLICATE_SAME_ACCESS))
1107 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1108 (int) GetLastError ());
1113 /* FIXME: Should translate the error code. */
1114 gpg_err_set_errno (EIO);
1115 return TRACE_SYSRES (-1);
1120 fd_table[rfd].handle = rh;
1121 fd_table[wfd].handle = wh;
1126 return TRACE_SUC6 ("read=0x%x (%p/0x%x), write=0x%x (%p/0x%x)",
1127 rfd, fd_table[rfd].handle, fd_table[rfd].rvid,
1128 wfd, fd_table[wfd].handle, fd_table[wfd].rvid);
1133 _gpgme_io_close (int fd)
1136 _gpgme_close_notify_handler_t handler = NULL;
1139 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
1143 gpg_err_set_errno (EBADF);
1144 return TRACE_SYSRES (-1);
1146 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1148 gpg_err_set_errno (EBADF);
1149 return TRACE_SYSRES (-1);
1154 LOCK (notify_table_lock);
1155 for (i = 0; i < DIM (notify_table); i++)
1157 if (notify_table[i].inuse && notify_table[i].fd == fd)
1159 handler = notify_table[i].handler;
1160 value = notify_table[i].value;
1161 notify_table[i].handler = NULL;
1162 notify_table[i].value = NULL;
1163 notify_table[i].inuse = 0;
1167 UNLOCK (notify_table_lock);
1169 handler (fd, value);
1171 if (fd_table[fd].dup_from == -1)
1173 if (fd_table[fd].handle != INVALID_HANDLE_VALUE)
1175 if (!CloseHandle (fd_table[fd].handle))
1177 TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ());
1178 /* FIXME: Should translate the error code. */
1179 gpg_err_set_errno (EIO);
1180 return TRACE_SYSRES (-1);
1183 else if (fd_table[fd].socket != INVALID_SOCKET)
1185 if (closesocket (fd_table[fd].socket))
1187 TRACE_LOG1 ("closesocket failed: ec=%d", (int) WSAGetLastError ());
1188 /* FIXME: Should translate the error code. */
1189 gpg_err_set_errno (EIO);
1190 return TRACE_SYSRES (-1);
1193 /* Nothing to do for RVIDs. */
1198 return TRACE_SYSRES (0);
1203 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
1207 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
1208 "close_handler=%p/%p", handler, value);
1212 LOCK (notify_table_lock);
1213 for (i=0; i < DIM (notify_table); i++)
1214 if (notify_table[i].inuse && notify_table[i].fd == fd)
1216 if (i == DIM (notify_table))
1217 for (i = 0; i < DIM (notify_table); i++)
1218 if (!notify_table[i].inuse)
1220 if (i == DIM (notify_table))
1222 UNLOCK (notify_table_lock);
1223 gpg_err_set_errno (EINVAL);
1224 return TRACE_SYSRES (-1);
1226 notify_table[i].fd = fd;
1227 notify_table[i].handler = handler;
1228 notify_table[i].value = value;
1229 notify_table[i].inuse = 1;
1230 UNLOCK (notify_table_lock);
1231 return TRACE_SYSRES (0);
1236 _gpgme_io_set_nonblocking (int fd)
1238 TRACE (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
1243 #ifdef HAVE_W32CE_SYSTEM
1245 build_commandline (char **argv, int fd0, int fd0_isnull,
1246 int fd1, int fd1_isnull,
1247 int fd2, int fd2_isnull)
1260 strcpy (p, "-&S0=null ");
1262 snprintf (p, 25, "-&S0=%d ", fd_table[fd0].rvid);
1268 strcpy (p, "-&S1=null ");
1270 snprintf (p, 25, "-&S1=%d ", fd_table[fd1].rvid);
1276 strcpy (p, "-&S2=null ");
1278 snprintf (p, 25, "-&S2=%d ", fd_table[fd2].rvid);
1281 strcpy (p, "-&S2=null ");
1285 for (i=0; (s = argv[i]); i++)
1288 continue; /* Ignore argv[0]. */
1289 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting) */
1292 n++; /* Need to double inner quotes. */
1295 buf = p = malloc (n);
1299 p = stpcpy (p, fdbuf);
1300 for (i = 0; argv[i]; i++)
1303 continue; /* Ignore argv[0]. */
1305 p = stpcpy (p, " ");
1307 if (! *argv[i]) /* Empty string. */
1308 p = stpcpy (p, "\"\"");
1309 else if (strpbrk (argv[i], " \t\n\v\f\""))
1311 p = stpcpy (p, "\"");
1312 for (s = argv[i]; *s; s++)
1322 p = stpcpy (p, argv[i]);
1329 build_commandline (char **argv)
1336 /* We have to quote some things because under Windows the program
1337 parses the commandline and does some unquoting. We enclose the
1338 whole argument in double-quotes, and escape literal double-quotes
1339 as well as backslashes with a backslash. We end up with a
1340 trailing space at the end of the line, but that is harmless. */
1341 for (i = 0; argv[i]; i++)
1344 /* The leading double-quote. */
1348 /* An extra one for each literal that must be escaped. */
1349 if (*p == '\\' || *p == '"')
1354 /* The trailing double-quote and the delimiter. */
1357 /* And a trailing zero. */
1360 buf = p = malloc (n);
1363 for (i = 0; argv[i]; i++)
1365 char *argvp = argv[i];
1370 if (*argvp == '\\' || *argvp == '"')
1372 *(p++) = *(argvp++);
1385 _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
1386 struct spawn_fd_item_s *fd_list,
1387 void (*atfork) (void *opaque, int reserved),
1388 void *atforkvalue, pid_t *r_pid)
1390 PROCESS_INFORMATION pi =
1392 NULL, /* returns process handle */
1393 0, /* returns primary thread handle */
1394 0, /* returns pid */
1399 #ifdef HAVE_W32CE_SYSTEM
1403 int fd_in_isnull = 1;
1404 int fd_out_isnull = 1;
1405 int fd_err_isnull = 1;
1407 HANDLE hd = INVALID_HANDLE_VALUE;
1409 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1414 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1418 for (i = 0; fd_list[i].fd != -1; i++)
1420 int fd = fd_list[i].fd;
1422 TRACE_LOG3 ("fd_list[%2i] = fd %i, dup_to %i", i, fd, fd_list[i].dup_to);
1423 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1425 TRACE_LOG1 ("invalid fd 0x%x", fd);
1426 gpg_err_set_errno (EBADF);
1427 return TRACE_SYSRES (-1);
1429 if (fd_table[fd].rvid == 0)
1431 TRACE_LOG1 ("fd 0x%x not inheritable (not an RVID)", fd);
1432 gpg_err_set_errno (EBADF);
1433 return TRACE_SYSRES (-1);
1436 if (fd_list[i].dup_to == 0)
1438 fd_in = fd_list[i].fd;
1441 else if (fd_list[i].dup_to == 1)
1443 fd_out = fd_list[i].fd;
1446 else if (fd_list[i].dup_to == 2)
1448 fd_err = fd_list[i].fd;
1453 cmdline = build_commandline (argv, fd_in, fd_in_isnull,
1454 fd_out, fd_out_isnull, fd_err, fd_err_isnull);
1457 TRACE_LOG1 ("build_commandline failed: %s", strerror (errno));
1458 return TRACE_SYSRES (-1);
1461 if (!CreateProcessA (path, /* Program to start. */
1462 cmdline, /* Command line arguments. */
1463 NULL, /* (not supported) */
1464 NULL, /* (not supported) */
1465 FALSE, /* (not supported) */
1466 (CREATE_SUSPENDED), /* Creation flags. */
1467 NULL, /* (not supported) */
1468 NULL, /* (not supported) */
1469 NULL, /* (not supported) */
1470 &pi /* Returns process information.*/
1473 TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1475 gpg_err_set_errno (EIO);
1476 return TRACE_SYSRES (-1);
1479 /* Create arbitrary pipe descriptor to send in ASSIGN_RVID
1480 commands. Errors are ignored. We don't need read or write access,
1481 as ASSIGN_RVID works without any permissions, yay! */
1482 hd = CreateFile (L"GPG1:", 0, 0,
1483 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1484 if (hd == INVALID_HANDLE_VALUE)
1486 TRACE_LOG1 ("CreateFile failed (ignored): ec=%d",
1487 (int) GetLastError ());
1490 /* Insert the inherited handles. */
1491 for (i = 0; fd_list[i].fd != -1; i++)
1493 /* Return the child name of this handle. */
1494 fd_list[i].peer_name = fd_table[fd_list[i].fd].rvid;
1496 if (hd != INVALID_HANDLE_VALUE)
1499 data[0] = (DWORD) fd_table[fd_list[i].fd].rvid;
1500 data[1] = pi.dwProcessId;
1501 if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_ASSIGN_RVID,
1502 data, sizeof (data), NULL, 0, NULL, NULL))
1504 TRACE_LOG3 ("ASSIGN_RVID(%i, %i) failed (ignored): %i",
1505 data[0], data[1], (int) GetLastError ());
1509 if (hd != INVALID_HANDLE_VALUE)
1513 SECURITY_ATTRIBUTES sec_attr;
1515 int cr_flags = CREATE_DEFAULT_ERROR_MODE;
1523 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1528 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1532 /* We do not inherit any handles by default, and just insert those
1533 handles we want the child to have afterwards. But some handle
1534 values occur on the command line, and we need to move
1535 stdin/out/err to the right location. So we use a wrapper program
1536 which gets the information from a temporary file. */
1537 if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
1539 TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
1540 return TRACE_SYSRES (-1);
1542 TRACE_LOG1 ("tmp_name = %s", tmp_name);
1544 args = calloc (2 + i + 1, sizeof (*args));
1545 args[0] = (char *) _gpgme_get_w32spawn_path ();
1548 memcpy (&args[3], &argv[1], i * sizeof (*args));
1550 memset (&sec_attr, 0, sizeof sec_attr);
1551 sec_attr.nLength = sizeof sec_attr;
1552 sec_attr.bInheritHandle = FALSE;
1554 arg_string = build_commandline (args);
1559 DeleteFileA (tmp_name);
1560 return TRACE_SYSRES (-1);
1563 memset (&si, 0, sizeof si);
1564 si.cb = sizeof (si);
1565 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1566 si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
1567 si.hStdInput = INVALID_HANDLE_VALUE;
1568 si.hStdOutput = INVALID_HANDLE_VALUE;
1569 si.hStdError = INVALID_HANDLE_VALUE;
1571 cr_flags |= CREATE_SUSPENDED;
1572 cr_flags |= DETACHED_PROCESS;
1573 cr_flags |= GetPriorityClass (GetCurrentProcess ());
1574 if (!CreateProcessA (_gpgme_get_w32spawn_path (),
1576 &sec_attr, /* process security attributes */
1577 &sec_attr, /* thread security attributes */
1578 FALSE, /* inherit handles */
1579 cr_flags, /* creation flags */
1580 NULL, /* environment */
1581 NULL, /* use current drive/directory */
1582 &si, /* startup information */
1583 &pi)) /* returns process information */
1585 TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1588 DeleteFileA (tmp_name);
1590 /* FIXME: Should translate the error code. */
1591 gpg_err_set_errno (EIO);
1592 return TRACE_SYSRES (-1);
1597 if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
1598 _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
1600 /* Insert the inherited handles. */
1601 for (i = 0; fd_list[i].fd != -1; i++)
1603 int fd = fd_list[i].fd;
1604 HANDLE ohd = INVALID_HANDLE_VALUE;
1605 HANDLE hd = INVALID_HANDLE_VALUE;
1607 /* Make it inheritable for the wrapper process. */
1608 if (fd >= 0 && fd < MAX_SLAFD && fd_table[fd].used)
1609 ohd = fd_table[fd].handle;
1611 if (!DuplicateHandle (GetCurrentProcess(), ohd,
1612 pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
1614 TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
1615 TerminateProcess (pi.hProcess, 0);
1616 /* Just in case TerminateProcess didn't work, let the
1617 process fail on its own. */
1618 ResumeThread (pi.hThread);
1619 CloseHandle (pi.hThread);
1620 CloseHandle (pi.hProcess);
1623 DeleteFileA (tmp_name);
1625 /* FIXME: Should translate the error code. */
1626 gpg_err_set_errno (EIO);
1627 return TRACE_SYSRES (-1);
1629 /* Return the child name of this handle. */
1630 fd_list[i].peer_name = handle_to_fd (hd);
1633 /* Write the handle translation information to the temporary
1636 /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
1637 notation: "0xFEDCBA9876543210" with an extra white space after
1638 every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead
1639 for a time when a HANDLE is 64 bit. */
1640 #define BUFFER_MAX 810
1641 char line[BUFFER_MAX + 1];
1646 if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
1647 strcpy (line, "~1 \n");
1649 strcpy (line, "\n");
1650 for (i = 0; fd_list[i].fd != -1; i++)
1652 /* Strip the newline. */
1653 len = strlen (line) - 1;
1655 /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx. */
1656 snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d \n",
1657 fd_list[i].fd, fd_list[i].dup_to,
1658 fd_list[i].peer_name, fd_list[i].arg_loc);
1659 /* Rather safe than sorry. */
1660 line[BUFFER_MAX - 1] = '\n';
1661 line[BUFFER_MAX] = '\0';
1663 len = strlen (line);
1667 res = write (tmp_fd, &line[written], len - written);
1671 while (res > 0 || (res < 0 && errno == EAGAIN));
1674 /* The temporary file is deleted by the gpgme-w32spawn process
1679 TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
1680 "dwProcessID=%d, dwThreadId=%d",
1681 pi.hProcess, pi.hThread,
1682 (int) pi.dwProcessId, (int) pi.dwThreadId);
1685 *r_pid = (pid_t)pi.dwProcessId;
1688 if (ResumeThread (pi.hThread) < 0)
1689 TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
1691 if (!CloseHandle (pi.hThread))
1692 TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
1693 (int) GetLastError ());
1695 TRACE_LOG1 ("process=%p", pi.hProcess);
1697 /* We don't need to wait for the process. */
1698 if (!CloseHandle (pi.hProcess))
1699 TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
1700 (int) GetLastError ());
1702 if (! (flags & IOSPAWN_FLAG_NOCLOSE))
1704 for (i = 0; fd_list[i].fd != -1; i++)
1705 _gpgme_io_close (fd_list[i].fd);
1708 for (i = 0; fd_list[i].fd != -1; i++)
1709 if (fd_list[i].dup_to == -1)
1710 TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
1711 fd_list[i].peer_name);
1713 TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
1714 fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
1715 ((fd_list[i].dup_to == 1) ? "out" : "err"));
1717 return TRACE_SYSRES (0);
1721 /* Select on the list of fds. Returns: -1 = error, 0 = timeout or
1722 nothing to select, > 0 = number of signaled fds. */
1724 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
1726 HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1727 int waitidx[MAXIMUM_WAIT_OBJECTS];
1734 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
1735 "nfds=%u, nonblock=%u", nfds, nonblock);
1738 TRACE_SEQ (dbg_help, "select on [ ");
1742 for (i=0; i < nfds; i++)
1744 if (fds[i].fd == -1)
1746 fds[i].signaled = 0;
1747 if (fds[i].for_read || fds[i].for_write)
1749 if (fds[i].for_read)
1751 struct reader_context_s *ctx = find_reader (fds[i].fd,1);
1754 TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
1758 if (nwait >= DIM (waitbuf))
1760 TRACE_END (dbg_help, "oops ]");
1761 TRACE_LOG ("Too many objects for WFMO!");
1762 /* FIXME: Should translate the error code. */
1763 gpg_err_set_errno (EIO);
1764 return TRACE_SYSRES (-1);
1767 waitbuf[nwait++] = ctx->have_data_ev;
1769 TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
1772 else if (fds[i].for_write)
1774 struct writer_context_s *ctx = find_writer (fds[i].fd,1);
1777 TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
1781 if (nwait >= DIM (waitbuf))
1783 TRACE_END (dbg_help, "oops ]");
1784 TRACE_LOG ("Too many objects for WFMO!");
1785 /* FIXME: Should translate the error code. */
1786 gpg_err_set_errno (EIO);
1787 return TRACE_SYSRES (-1);
1790 waitbuf[nwait++] = ctx->is_empty;
1792 TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
1797 TRACE_END (dbg_help, "]");
1799 return TRACE_SYSRES (0);
1801 code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
1802 if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
1804 /* This WFMO is a really silly function: It does return either
1805 the index of the signaled object or if 2 objects have been
1806 signalled at the same time, the index of the object with the
1807 lowest object is returned - so and how do we find out how
1808 many objects have been signaled???. The only solution I can
1809 imagine is to test each object starting with the returned
1810 index individually - how dull. */
1812 for (i = code - WAIT_OBJECT_0; i < nwait; i++)
1814 if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
1816 assert (waitidx[i] >=0 && waitidx[i] < nfds);
1817 fds[waitidx[i]].signaled = 1;
1824 TRACE_LOG ("no signaled objects found after WFMO");
1828 else if (code == WAIT_TIMEOUT)
1829 TRACE_LOG ("WFMO timed out");
1830 else if (code == WAIT_FAILED)
1832 int le = (int) GetLastError ();
1834 if (le == ERROR_INVALID_HANDLE)
1837 int j = handle_to_fd (waitbuf[i]);
1839 TRACE_LOG1 ("WFMO invalid handle %d removed", j);
1840 for (k = 0 ; k < nfds; k++)
1844 fds[k].for_read = fds[k].for_write = 0;
1848 TRACE_LOG (" oops, or not???");
1851 TRACE_LOG1 ("WFMO failed: %d", le);
1856 TRACE_LOG1 ("WFMO returned %d", code);
1862 TRACE_SEQ (dbg_help, "select OK [ ");
1863 for (i = 0; i < nfds; i++)
1865 if (fds[i].fd == -1)
1867 if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
1868 TRACE_ADD2 (dbg_help, "%c0x%x ",
1869 fds[i].for_read ? 'r' : 'w', fds[i].fd);
1871 TRACE_END (dbg_help, "]");
1876 /* FIXME: Should determine a proper error code. */
1877 gpg_err_set_errno (EIO);
1880 return TRACE_SYSRES (count);
1885 _gpgme_io_subsystem_init (void)
1887 /* Nothing to do. */
1891 /* Write the printable version of FD to the buffer BUF of length
1892 BUFLEN. The printable version is the representation on the command
1893 line that the child process expects. */
1895 _gpgme_io_fd2str (char *buf, int buflen, int fd)
1897 #ifdef HAVE_W32CE_SYSTEM
1898 /* FIXME: For now. See above. */
1899 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used
1900 || fd_table[fd].rvid == 0)
1903 fd = fd_table[fd].rvid;
1906 return snprintf (buf, buflen, "%d", fd);
1911 _gpgme_io_dup (int fd)
1914 struct reader_context_s *rd_ctx;
1915 struct writer_context_s *wt_ctx;
1918 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
1920 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1922 gpg_err_set_errno (EINVAL);
1923 return TRACE_SYSRES (-1);
1928 return TRACE_SYSRES (-1);
1930 fd_table[newfd].handle = fd_table[fd].handle;
1931 fd_table[newfd].socket = fd_table[fd].socket;
1932 fd_table[newfd].rvid = fd_table[fd].rvid;
1933 fd_table[newfd].dup_from = fd;
1935 rd_ctx = find_reader (fd, 1);
1938 /* No need for locking, as the only races are against the reader
1939 thread itself, which doesn't touch refcount. */
1942 LOCK (reader_table_lock);
1943 for (i = 0; i < reader_table_size; i++)
1944 if (!reader_table[i].used)
1947 assert (i != reader_table_size);
1948 reader_table[i].fd = newfd;
1949 reader_table[i].context = rd_ctx;
1950 reader_table[i].used = 1;
1951 UNLOCK (reader_table_lock);
1954 wt_ctx = find_writer (fd, 1);
1957 /* No need for locking, as the only races are against the writer
1958 thread itself, which doesn't touch refcount. */
1961 LOCK (writer_table_lock);
1962 for (i = 0; i < writer_table_size; i++)
1963 if (!writer_table[i].used)
1966 assert (i != writer_table_size);
1967 writer_table[i].fd = newfd;
1968 writer_table[i].context = wt_ctx;
1969 writer_table[i].used = 1;
1970 UNLOCK (writer_table_lock);
1973 return TRACE_SYSRES (newfd);
1977 /* The following interface is only useful for GPGME Glib and Qt. */
1979 /* Compatibility interface, obsolete. */
1981 gpgme_get_giochannel (int fd)
1987 /* Look up the giochannel or qiodevice for file descriptor FD. */
1989 gpgme_get_fdptr (int fd)
2002 case WSAEWOULDBLOCK:
2004 case ERROR_BROKEN_PIPE:
2006 case WSANOTINITIALISED:
2015 _gpgme_io_socket (int domain, int type, int proto)
2020 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
2021 "type=%i, protp=%i", type, proto);
2025 return TRACE_SYSRES (-1);
2027 res = socket (domain, type, proto);
2028 if (res == INVALID_SOCKET)
2031 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2032 return TRACE_SYSRES (-1);
2034 fd_table[fd].socket = res;
2036 TRACE_SUC2 ("socket=0x%x (0x%x)", fd, fd_table[fd].socket);
2043 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
2047 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
2048 "addr=%p, addrlen=%i", addr, addrlen);
2050 if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
2052 gpg_err_set_errno (EBADF);
2053 return TRACE_SYSRES (-1);
2056 res = connect (fd_table[fd].socket, addr, addrlen);
2059 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2060 return TRACE_SYSRES (-1);
2063 return TRACE_SUC ();