1 /* w32-io.c - W32 API I/O functions.
2 * Copyright (C) 2000 Werner Koch (dd9jn)
3 * Copyright (C) 2001-2004, 2007, 2010, 2018 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, see <https://gnu.org/licenses/>.
19 * SPDX-License-Identifier: LGPL-2.1+
31 #ifdef HAVE_SYS_TIME_H
32 # include <sys/time.h>
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
46 /* The number of entries in our file table. We may eventually use a
47 * lower value and dynamically resize the table. */
50 #define handle_to_fd(a) ((int)(a))
52 #define READBUF_SIZE 4096
53 #define WRITEBUF_SIZE 4096
54 #define PIPEBUF_SIZE 4096
57 /* An object to store handles or sockets. */
64 typedef struct hddesc_s *hddesc_t;
68 /* The context used by a reader thread. */
69 struct reader_context_s
73 int refcount; /* Bumped if the FD has been duped and thus we have
74 * another FD referencing this context. */
84 /* This is manually reset. */
86 /* This is automatically reset. */
88 /* This is manually reset but actually only triggered once. */
91 size_t readpos, writepos;
92 char buffer[READBUF_SIZE];
96 /* The context used by a writer thread. */
97 struct writer_context_s
103 DECLARE_LOCK (mutex);
109 /* This is manually reset. */
114 char buffer[WRITEBUF_SIZE];
118 /* An object to keep track of HANDLEs and sockets and map them to an
119 * integer similar to what we use in Unix. Note that despite this
120 * integer is often named "fd", it is not a file descriptor but really
121 * only an index into this table. Never ever pass such an fd to any
122 * other function except for those implemented here. */
127 /* The handle descriptor. */
130 /* DUP_FROM is just a debug helper to show from which fd this fd was
134 /* Two flags to indicate whether a reader or writer (or both) are
135 * needed. This is so that we can delay the actual thread creation
136 * until they are needed. */
137 unsigned int want_reader:1;
138 unsigned int want_writer:1;
140 /* The context of an associated reader object or NULL. */
141 struct reader_context_s *reader;
143 /* The context of an associated writer object or NULL. */
144 struct writer_context_s *writer;
146 /* A notification hanlder. Noet that we current support only one
147 * callback per fd. */
149 _gpgme_close_notify_handler_t handler;
153 } fd_table[MAX_SLAFD];
154 static size_t fd_table_size = MAX_SLAFD;
156 DEFINE_STATIC_LOCK (fd_table_lock);
159 /* We use a single global lock for all hddesc_t objects. */
160 DEFINE_STATIC_LOCK (hddesc_lock);
164 /* Wrapper around CloseHandle to print an error. */
165 #define close_handle(hd) _close_handle ((hd), __LINE__);
167 _close_handle (HANDLE hd, int line)
169 if (!CloseHandle (hd))
171 TRACE2 (DEBUG_INIT, "w32-io", hd, "CloseHandle failed at line %d: ec=%d",
172 line, (int) GetLastError ());
176 /* Wrapper around WaitForSingleObject to print an error. */
177 #define wait_for_single_object(hd,msec) \
178 _wait_for_single_object ((hd), (msec), __LINE__)
180 _wait_for_single_object (HANDLE hd, DWORD msec, int line)
184 res = WaitForSingleObject (hd, msec);
185 if (res == WAIT_FAILED)
187 TRACE2 (DEBUG_INIT, "w32-io", hd,
188 "WFSO failed at line %d: ec=%d", line, (int) GetLastError ());
194 /* Create a new handle descriptor object. */
200 hdd = malloc (sizeof *hdd);
203 hdd->hd = INVALID_HANDLE_VALUE;
204 hdd->sock = INVALID_SOCKET;
212 ref_hddesc (hddesc_t hdd)
216 UNLOCK (hddesc_lock);
221 /* Release a handle descriptor object and close its handle or socket
224 release_hddesc (hddesc_t hdd)
231 if (hdd->refcount < 1)
233 /* Holds a valid handle or was never intialized (in which case
234 * REFCOUNT would be -1 here). */
235 TRACE_BEG3 (DEBUG_SYSIO, "gpgme:release_hddesc", hdd,
236 "hd=%p, sock=%d, refcount=%d",
237 hdd->hd, hdd->sock, hdd->refcount);
239 if (hdd->hd != INVALID_HANDLE_VALUE)
240 close_handle (hdd->hd);
242 if (hdd->sock != INVALID_SOCKET)
244 TRACE_LOG1 ("closing socket %d", hdd->sock);
245 if (closesocket (hdd->sock))
247 TRACE_LOG1 ("closesocket failed: ec=%d", (int)WSAGetLastError ());
254 UNLOCK (hddesc_lock);
259 /* Returns our FD or -1 on resource limit. The returned integer
260 * references a new object which has not been intialized but can be
261 * release with release_fd. */
267 LOCK (fd_table_lock);
269 for (idx = 0; idx < fd_table_size; idx++)
270 if (! fd_table[idx].used)
273 if (idx == fd_table_size)
275 gpg_err_set_errno (EIO);
280 fd_table[idx].used = 1;
281 fd_table[idx].hdd = NULL;
282 fd_table[idx].dup_from = -1;
283 fd_table[idx].want_reader = 0;
284 fd_table[idx].want_writer = 0;
285 fd_table[idx].reader = NULL;
286 fd_table[idx].writer = NULL;
287 fd_table[idx].notify.handler = NULL;
288 fd_table[idx].notify.value = NULL;
291 UNLOCK (fd_table_lock);
297 /* Releases our FD but it this is just this entry. No close operation
298 * is involved here; it must be done prior to calling this
303 if (fd < 0 || fd >= fd_table_size)
306 LOCK (fd_table_lock);
308 if (fd_table[fd].used)
310 release_hddesc (fd_table[fd].hdd);
311 fd_table[fd].used = 0;
312 fd_table[fd].hdd = NULL;
313 fd_table[fd].dup_from = -1;
314 fd_table[fd].want_reader = 0;
315 fd_table[fd].want_writer = 0;
316 fd_table[fd].reader = NULL;
317 fd_table[fd].writer = NULL;
318 fd_table[fd].notify.handler = NULL;
319 fd_table[fd].notify.value = NULL;
322 UNLOCK (fd_table_lock);
327 get_desired_thread_priority (void)
331 if (!_gpgme_get_conf_int ("IOThreadPriority", &value))
333 value = THREAD_PRIORITY_HIGHEST;
334 TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
335 "%d (default)", value);
339 TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
340 "%d (configured)", value);
346 /* The reader thread. Created on the fly by gpgme_io_read and
347 * destroyed by destroy_reader. Note that this functions works with a
348 * copy of the value of the HANDLE variable frm the FS_TABLE. */
349 static DWORD CALLBACK
352 struct reader_context_s *ctx = arg;
357 TRACE_BEG4 (DEBUG_SYSIO, "gpgme:reader", ctx->hdd,
358 "hd=%p, sock=%d, thread=%p, refcount=%d",
359 ctx->hdd->hd, ctx->hdd->sock, ctx->thread_hd, ctx->refcount);
361 if (ctx->hdd->hd != INVALID_HANDLE_VALUE)
369 /* Leave a 1 byte gap so that we can see whether it is empty or
371 if ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
373 /* Wait for space. */
374 if (!ResetEvent (ctx->have_space_ev))
376 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
379 TRACE_LOG1 ("waiting for space (refcnt=%d)", ctx->refcount);
380 wait_for_single_object (ctx->have_space_ev, INFINITE);
381 TRACE_LOG ("got space");
389 nbytes = (ctx->readpos + READBUF_SIZE
390 - ctx->writepos - 1) % READBUF_SIZE;
391 if (nbytes > READBUF_SIZE - ctx->writepos)
392 nbytes = READBUF_SIZE - ctx->writepos;
395 TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes);
401 n = recv (ctx->hdd->sock, ctx->buffer + ctx->writepos, nbytes, 0);
404 ctx->error_code = (int) WSAGetLastError ();
405 if (ctx->error_code == ERROR_BROKEN_PIPE)
408 TRACE_LOG ("got EOF (broken connection)");
412 /* Check whether the shutdown triggered the error -
413 no need to to print a warning in this case. */
414 if ( ctx->error_code == WSAECONNABORTED
415 || ctx->error_code == WSAECONNRESET)
421 TRACE_LOG ("got shutdown");
428 TRACE_LOG1 ("recv error: ec=%d", ctx->error_code);
436 if (!ReadFile (ctx->hdd->hd,
437 ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
439 ctx->error_code = (int) GetLastError ();
440 if (ctx->error_code == ERROR_BROKEN_PIPE)
443 TRACE_LOG ("got EOF (broken pipe)");
445 else if (ctx->error_code == ERROR_OPERATION_ABORTED)
448 TRACE_LOG ("got EOF (closed by us)");
453 TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
467 TRACE_LOG ("got eof");
472 TRACE_LOG2 ("got %u bytes (refcnt=%d)", nread, ctx->refcount);
474 ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
475 if (!SetEvent (ctx->have_data_ev))
477 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
478 (int) GetLastError ());
482 /* Indicate that we have an error or EOF. */
483 if (!SetEvent (ctx->have_data_ev))
485 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
486 (int) GetLastError ());
489 TRACE_LOG ("waiting for close");
490 wait_for_single_object (ctx->close_ev, INFINITE);
492 release_hddesc (ctx->hdd);
493 close_handle (ctx->close_ev);
494 close_handle (ctx->have_data_ev);
495 close_handle (ctx->have_space_ev);
496 close_handle (ctx->thread_hd);
497 DESTROY_LOCK (ctx->mutex);
504 /* Create a new reader thread and return its context object. The
505 * input is the handle descriptor HDD. This function may not call any
506 * fd based functions because the caller already holds a lock on the
508 static struct reader_context_s *
509 create_reader (hddesc_t hdd)
511 struct reader_context_s *ctx;
512 SECURITY_ATTRIBUTES sec_attr;
515 TRACE_BEG3 (DEBUG_SYSIO, "gpgme:create_reader", hdd,
516 "handle=%p sock=%d refhdd=%d",
517 hdd->hd, hdd->sock, hdd->refcount);
519 memset (&sec_attr, 0, sizeof sec_attr);
520 sec_attr.nLength = sizeof sec_attr;
521 sec_attr.bInheritHandle = FALSE;
523 ctx = calloc (1, sizeof *ctx);
526 TRACE_SYSERR_NR (errno);
530 ctx->hdd = ref_hddesc (hdd);
533 ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
534 if (ctx->have_data_ev)
535 ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
536 if (ctx->have_space_ev)
537 ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
538 if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->close_ev)
540 TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
541 if (ctx->have_data_ev)
542 close_handle (ctx->have_data_ev);
543 if (ctx->have_space_ev)
544 close_handle (ctx->have_space_ev);
546 close_handle (ctx->close_ev);
547 release_hddesc (ctx->hdd);
549 TRACE_SYSERR_NR (EIO);
553 INIT_LOCK (ctx->mutex);
555 ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid);
559 TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
560 DESTROY_LOCK (ctx->mutex);
561 if (ctx->have_data_ev)
562 close_handle (ctx->have_data_ev);
563 if (ctx->have_space_ev)
564 close_handle (ctx->have_space_ev);
566 close_handle (ctx->close_ev);
567 release_hddesc (ctx->hdd);
569 TRACE_SYSERR_NR (EIO);
574 /* We set the priority of the thread higher because we know that
575 it only runs for a short time. This greatly helps to
576 increase the performance of the I/O. */
577 SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
585 /* Prepare destruction of the reader thread for CTX. Returns 0 if a
586 call to this function is sufficient and destroy_reader_finish shall
589 destroy_reader (struct reader_context_s *ctx)
593 if (ctx->refcount != 0)
595 TRACE2 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx,
596 "hdd=%p refcount now %d", ctx->hdd, ctx->refcount);
601 if (ctx->have_space_ev)
602 SetEvent (ctx->have_space_ev);
603 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx,
604 "hdd=%p close triggered", ctx->hdd);
607 /* The reader thread is usually blocking in recv or ReadFile. If
608 the peer does not send an EOF or breaks the pipe the WFSO might
609 get stuck waiting for the termination of the reader thread. This
610 happens quite often with sockets, thus we definitely need to get
611 out of the recv. A shutdown does this nicely. For handles
612 (i.e. pipes) it would also be nice to cancel the operation, but
613 such a feature is only available since Vista. Thus we need to
614 dlopen that syscall. */
616 if (ctx->hdd && ctx->hdd->hd != INVALID_HANDLE_VALUE)
618 _gpgme_w32_cancel_synchronous_io (ctx->thread_hd);
620 else if (ctx->hdd && ctx->hdd->sock != INVALID_SOCKET)
622 if (shutdown (ctx->hdd->sock, 2))
623 TRACE2 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx,
624 "shutdown socket %d failed: %s",
625 ctx->hdd->sock, (int) WSAGetLastError ());
628 /* After setting this event CTX is void. */
629 SetEvent (ctx->close_ev);
634 /* Find a reader context or create a new one. Note that the reader
635 * context will last until a _gpgme_io_close. NULL is returned for a
636 * bad FD or for other errors. */
637 static struct reader_context_s *
640 struct reader_context_s *rd = NULL;
642 TRACE_BEG0 (DEBUG_SYSIO, "gpgme:find_reader", fd, "");
644 LOCK (fd_table_lock);
645 if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used)
647 UNLOCK (fd_table_lock);
648 gpg_err_set_errno (EBADF);
649 TRACE_SUC0 ("EBADF");
653 rd = fd_table[fd].reader;
656 UNLOCK (fd_table_lock);
657 TRACE_SUC1 ("rd=%p", rd);
658 return rd; /* Return already initialized reader thread object. */
661 /* Create a new reader thread. */
662 TRACE_LOG3 ("fd=%d -> hdd=%p dupfrom=%d creating reader",
663 fd, fd_table[fd].hdd, fd_table[fd].dup_from);
664 rd = create_reader (fd_table[fd].hdd);
666 gpg_err_set_errno (EIO);
668 fd_table[fd].reader = rd;
670 UNLOCK (fd_table_lock);
671 TRACE_SUC1 ("rd=%p (new)", rd);
677 _gpgme_io_read (int fd, void *buffer, size_t count)
680 struct reader_context_s *ctx;
681 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
682 "buffer=%p, count=%u", buffer, count);
684 ctx = find_reader (fd);
686 return TRACE_SYSRES (-1);
687 if (ctx->eof_shortcut)
688 return TRACE_SYSRES (0);
691 if (ctx->readpos == ctx->writepos && !ctx->error)
693 /* No data available. */
695 TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd);
696 wait_for_single_object (ctx->have_data_ev, INFINITE);
697 TRACE_LOG1 ("data from thread %p available", ctx->thread_hd);
701 if (ctx->readpos == ctx->writepos || ctx->error)
704 ctx->eof_shortcut = 1;
706 return TRACE_SYSRES (0);
709 TRACE_LOG ("EOF but ctx->eof flag not set");
712 gpg_err_set_errno (ctx->error_code);
713 return TRACE_SYSRES (-1);
716 nread = ctx->readpos < ctx->writepos
717 ? ctx->writepos - ctx->readpos
718 : READBUF_SIZE - ctx->readpos;
721 memcpy (buffer, ctx->buffer + ctx->readpos, nread);
722 ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
723 if (ctx->readpos == ctx->writepos && !ctx->eof)
725 if (!ResetEvent (ctx->have_data_ev))
727 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
729 /* FIXME: Should translate the error code. */
730 gpg_err_set_errno (EIO);
731 return TRACE_SYSRES (-1);
734 if (!SetEvent (ctx->have_space_ev))
736 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d",
737 ctx->have_space_ev, (int) GetLastError ());
739 /* FIXME: Should translate the error code. */
740 gpg_err_set_errno (EIO);
741 return TRACE_SYSRES (-1);
745 TRACE_LOGBUFX (buffer, nread);
746 return TRACE_SYSRES (nread);
750 /* The writer does use a simple buffering strategy so that we are
751 informed about write errors as soon as possible (i. e. with the the
752 next call to the write function. */
753 static DWORD CALLBACK
756 struct writer_context_s *ctx = arg;
759 TRACE_BEG4 (DEBUG_SYSIO, "gpgme:writer", ctx->hdd,
760 "hd=%p, sock=%d, thread=%p, refcount=%d",
761 ctx->hdd->hd, ctx->hdd->sock, ctx->thread_hd, ctx->refcount);
763 if (ctx->hdd->hd != INVALID_HANDLE_VALUE)
771 if (ctx->stop_me && !ctx->nbytes)
778 if (!SetEvent (ctx->is_empty))
779 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
780 if (!ResetEvent (ctx->have_data))
781 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
784 wait_for_single_object (ctx->have_data, INFINITE);
785 TRACE_LOG ("got data to send");
788 if (ctx->stop_me && !ctx->nbytes)
795 TRACE_LOG2 ("%s %d bytes", sock?"sending":"writing", ctx->nbytes);
797 /* Note that CTX->nbytes is not zero at this point, because
798 _gpgme_io_write always writes at least 1 byte before waking
799 us up, unless CTX->stop_me is true, which we catch above. */
802 /* We need to try send first because a socket handle can't
803 be used with WriteFile. */
806 n = send (ctx->hdd->sock, ctx->buffer, ctx->nbytes, 0);
809 ctx->error_code = (int) WSAGetLastError ();
811 TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
818 if (!WriteFile (ctx->hdd->hd, ctx->buffer,
819 ctx->nbytes, &nwritten, NULL))
821 if (GetLastError () == ERROR_BUSY)
823 /* Probably stop_me is set now. */
824 TRACE_LOG ("pipe busy (unblocked?)");
828 ctx->error_code = (int) GetLastError ();
830 TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
834 TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
837 ctx->nbytes -= nwritten;
840 /* Indicate that we have an error. */
841 if (!SetEvent (ctx->is_empty))
842 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
844 TRACE_LOG ("waiting for close");
845 wait_for_single_object (ctx->close_ev, INFINITE);
848 TRACE_LOG1 ("still %d bytes in buffer at close time", ctx->nbytes);
850 release_hddesc (ctx->hdd);
851 close_handle (ctx->close_ev);
852 close_handle (ctx->have_data);
853 close_handle (ctx->is_empty);
854 close_handle (ctx->thread_hd);
855 DESTROY_LOCK (ctx->mutex);
862 static struct writer_context_s *
863 create_writer (hddesc_t hdd)
865 struct writer_context_s *ctx;
866 SECURITY_ATTRIBUTES sec_attr;
870 TRACE_BEG3 (DEBUG_SYSIO, "gpgme:create_writer", hdd,
871 "handle=%p sock=%d refhdd=%d",
872 hdd->hd, hdd->sock, hdd->refcount);
874 memset (&sec_attr, 0, sizeof sec_attr);
875 sec_attr.nLength = sizeof sec_attr;
876 sec_attr.bInheritHandle = FALSE;
878 ctx = calloc (1, sizeof *ctx);
881 TRACE_SYSERR_NR (errno);
885 ctx->hdd = ref_hddesc (hdd);
888 ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
890 ctx->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
892 ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
893 if (!ctx->have_data || !ctx->is_empty || !ctx->close_ev)
895 TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
897 close_handle (ctx->have_data);
899 close_handle (ctx->is_empty);
901 close_handle (ctx->close_ev);
902 release_hddesc (ctx->hdd);
904 TRACE_SYSERR_NR (EIO);
908 INIT_LOCK (ctx->mutex);
910 ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
913 TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
914 DESTROY_LOCK (ctx->mutex);
916 close_handle (ctx->have_data);
918 close_handle (ctx->is_empty);
920 close_handle (ctx->close_ev);
921 release_hddesc (ctx->hdd);
923 TRACE_SYSERR_NR (EIO);
928 /* We set the priority of the thread higher because we know
929 that it only runs for a short time. This greatly helps to
930 increase the performance of the I/O. */
931 SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
940 destroy_writer (struct writer_context_s *ctx)
944 if (ctx->refcount != 0)
946 TRACE2 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx,
947 "hdd=%p refcount now %d", ctx->hdd, ctx->refcount);
953 SetEvent (ctx->have_data);
954 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx,
955 "hdd=%p close triggered", ctx->hdd);
958 /* Give the writer a chance to flush the buffer. */
959 wait_for_single_object (ctx->is_empty, INFINITE);
961 /* After setting this event CTX is void. */
962 SetEvent (ctx->close_ev);
966 /* Find a writer context or create a new one. Note that the writer
967 * context will last until a _gpgme_io_close. NULL is returned for a
968 * bad FD or for other errors. */
969 static struct writer_context_s *
972 struct writer_context_s *wt = NULL;
974 TRACE_BEG0 (DEBUG_SYSIO, "gpgme:find_writer", fd, "");
976 LOCK (fd_table_lock);
977 if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used)
979 UNLOCK (fd_table_lock);
980 gpg_err_set_errno (EBADF);
981 TRACE_SUC0 ("EBADF");
985 wt = fd_table[fd].writer;
988 UNLOCK (fd_table_lock);
989 TRACE_SUC1 ("wt=%p", wt);
990 return wt; /* Return already initialized writer thread object. */
993 /* Create a new writer thread. */
994 TRACE_LOG4 ("fd=%d -> handle=%p socket=%d dupfrom=%d creating writer",
995 fd, fd_table[fd].hdd->hd, fd_table[fd].hdd->sock,
996 fd_table[fd].dup_from);
997 wt = create_writer (fd_table[fd].hdd);
999 gpg_err_set_errno (EIO);
1001 fd_table[fd].writer = wt;
1003 UNLOCK (fd_table_lock);
1004 TRACE_SUC1 ("wt=%p (new)", wt);
1010 _gpgme_io_write (int fd, const void *buffer, size_t count)
1012 struct writer_context_s *ctx;
1013 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
1014 "buffer=%p, count=%u", buffer, count);
1015 TRACE_LOGBUFX (buffer, count);
1018 return TRACE_SYSRES (0);
1020 ctx = find_writer (fd);
1022 return TRACE_SYSRES (-1);
1025 if (!ctx->error && ctx->nbytes)
1027 /* Bytes are pending for send. */
1029 /* Reset the is_empty event. Better safe than sorry. */
1030 if (!ResetEvent (ctx->is_empty))
1032 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
1033 UNLOCK (ctx->mutex);
1034 /* FIXME: Should translate the error code. */
1035 gpg_err_set_errno (EIO);
1036 return TRACE_SYSRES (-1);
1038 UNLOCK (ctx->mutex);
1039 TRACE_LOG1 ("waiting for empty buffer in thread %p", ctx->thread_hd);
1040 wait_for_single_object (ctx->is_empty, INFINITE);
1041 TRACE_LOG1 ("thread %p buffer is empty", ctx->thread_hd);
1047 UNLOCK (ctx->mutex);
1048 if (ctx->error_code == ERROR_NO_DATA)
1049 gpg_err_set_errno (EPIPE);
1051 gpg_err_set_errno (EIO);
1052 return TRACE_SYSRES (-1);
1055 /* If no error occurred, the number of bytes in the buffer must be
1057 assert (!ctx->nbytes);
1059 if (count > WRITEBUF_SIZE)
1060 count = WRITEBUF_SIZE;
1061 memcpy (ctx->buffer, buffer, count);
1062 ctx->nbytes = count;
1064 /* We have to reset the is_empty event early, because it is also
1065 * used by the select() implementation to probe the channel. */
1066 if (!ResetEvent (ctx->is_empty))
1068 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
1069 UNLOCK (ctx->mutex);
1070 /* FIXME: Should translate the error code. */
1071 gpg_err_set_errno (EIO);
1072 return TRACE_SYSRES (-1);
1074 if (!SetEvent (ctx->have_data))
1076 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
1077 UNLOCK (ctx->mutex);
1078 /* FIXME: Should translate the error code. */
1079 gpg_err_set_errno (EIO);
1080 return TRACE_SYSRES (-1);
1082 UNLOCK (ctx->mutex);
1084 return TRACE_SYSRES ((int) count);
1089 _gpgme_io_pipe (int filedes[2], int inherit_idx)
1097 SECURITY_ATTRIBUTES sec_attr;
1099 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
1100 "inherit_idx=%i (GPGME uses it for %s)",
1101 inherit_idx, inherit_idx ? "reading" : "writing");
1103 /* Get a new empty file descriptor. */
1106 return TRACE_SYSRES (-1);
1111 return TRACE_SYSRES (-1);
1113 rhdesc = new_hddesc ();
1118 return TRACE_SYSRES (-1);
1120 whdesc = new_hddesc ();
1125 release_hddesc (rhdesc);
1126 return TRACE_SYSRES (-1);
1129 /* Create a pipe. */
1130 memset (&sec_attr, 0, sizeof (sec_attr));
1131 sec_attr.nLength = sizeof (sec_attr);
1132 sec_attr.bInheritHandle = FALSE;
1134 if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
1136 TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
1139 release_hddesc (rhdesc);
1140 release_hddesc (whdesc);
1141 gpg_err_set_errno (EIO);
1142 return TRACE_SYSRES (-1);
1145 /* Make one end inheritable. */
1146 if (inherit_idx == 0)
1149 if (!DuplicateHandle (GetCurrentProcess(), rh,
1150 GetCurrentProcess(), &hd, 0,
1151 TRUE, DUPLICATE_SAME_ACCESS))
1153 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1154 (int) GetLastError ());
1159 release_hddesc (rhdesc);
1160 release_hddesc (whdesc);
1161 gpg_err_set_errno (EIO);
1162 return TRACE_SYSRES (-1);
1167 else if (inherit_idx == 1)
1170 if (!DuplicateHandle( GetCurrentProcess(), wh,
1171 GetCurrentProcess(), &hd, 0,
1172 TRUE, DUPLICATE_SAME_ACCESS))
1174 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1175 (int) GetLastError ());
1180 release_hddesc (rhdesc);
1181 release_hddesc (whdesc);
1182 gpg_err_set_errno (EIO);
1183 return TRACE_SYSRES (-1);
1189 /* Put the HANDLEs of the new pipe into the file descriptor table.
1190 * Note that we don't need to lock the table because we have just
1191 * acquired these two fresh fds and they are not known by any other
1193 fd_table[rfd].want_reader = 1;
1194 ref_hddesc (rhdesc)->hd = rh;
1195 fd_table[rfd].hdd = rhdesc;
1197 fd_table[wfd].want_writer = 1;
1198 ref_hddesc (whdesc)->hd = wh;
1199 fd_table[wfd].hdd = whdesc;
1203 return TRACE_SUC6 ("read=0x%x (hdd=%p,hd=%p), write=0x%x (hdd=%p,hd=%p)",
1204 rfd, fd_table[rfd].hdd, fd_table[rfd].hdd->hd,
1205 wfd, fd_table[wfd].hdd, fd_table[wfd].hdd->hd);
1209 /* Close out File descriptor FD. */
1211 _gpgme_io_close (int fd)
1213 _gpgme_close_notify_handler_t handler = NULL;
1216 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
1220 gpg_err_set_errno (EBADF);
1221 return TRACE_SYSRES (-1);
1224 LOCK (fd_table_lock);
1225 /* Check the size in the locked state because we may eventually add
1226 * code to change that size. */
1227 if (fd >= fd_table_size || !fd_table[fd].used)
1229 UNLOCK (fd_table_lock);
1230 gpg_err_set_errno (EBADF);
1231 return TRACE_SYSRES (-1);
1234 TRACE_LOG2 ("hdd=%p dupfrom=%d", fd_table[fd].hdd, fd_table[fd].dup_from);
1236 if (fd_table[fd].reader)
1238 TRACE_LOG1 ("destroying reader %p", fd_table[fd].reader);
1239 destroy_reader (fd_table[fd].reader);
1240 fd_table[fd].reader = NULL;
1243 if (fd_table[fd].writer)
1245 TRACE_LOG1 ("destroying writer %p", fd_table[fd].writer);
1246 destroy_writer (fd_table[fd].writer);
1247 fd_table[fd].writer = NULL;
1250 /* The handler may not use any fd fucntion because the table is
1251 * locked. Can we avoid this? */
1252 handler = fd_table[fd].notify.handler;
1253 value = fd_table[fd].notify.value;
1255 /* Release our reference to the handle descripor. Note that if no
1256 * reader or writer threads were used this release will also take
1257 * care that the handle descriptor is closed
1258 * (i.e. CloseHandle(hdd->hd) is called). */
1259 release_hddesc (fd_table[fd].hdd);
1260 fd_table[fd].hdd = NULL;
1262 UNLOCK (fd_table_lock);
1264 /* Run the notification callback. */
1266 handler (fd, value);
1268 release_fd (fd); /* FIXME: We should have a release_fd_locked () */
1270 return TRACE_SYSRES (0);
1274 /* Set a close notification callback which is called right after FD
1275 * has been closed but before its slot (ie. the FD number) is beeing
1276 * released. Tha HANDLER may thus use the provided value of the FD
1277 * but it may not pass it to any I/O functions. Note: Only the last
1278 * handler set for an FD is used. */
1280 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
1283 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
1284 "close_handler=%p/%p", handler, value);
1286 LOCK (fd_table_lock);
1287 if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used)
1289 UNLOCK (fd_table_lock);
1290 gpg_err_set_errno (EBADF);
1291 return TRACE_SYSRES (-1);;
1294 fd_table[fd].notify.handler = handler;
1295 fd_table[fd].notify.value = value;
1296 UNLOCK (fd_table_lock);
1297 return TRACE_SYSRES (0);
1302 _gpgme_io_set_nonblocking (int fd)
1304 TRACE (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
1310 build_commandline (char **argv)
1317 /* We have to quote some things because under Windows the program
1318 parses the commandline and does some unquoting. We enclose the
1319 whole argument in double-quotes, and escape literal double-quotes
1320 as well as backslashes with a backslash. We end up with a
1321 trailing space at the end of the line, but that is harmless. */
1322 for (i = 0; argv[i]; i++)
1325 /* The leading double-quote. */
1329 /* An extra one for each literal that must be escaped. */
1330 if (*p == '\\' || *p == '"')
1335 /* The trailing double-quote and the delimiter. */
1338 /* And a trailing zero. */
1341 buf = p = malloc (n);
1344 for (i = 0; argv[i]; i++)
1346 char *argvp = argv[i];
1351 if (*argvp == '\\' || *argvp == '"')
1353 *(p++) = *(argvp++);
1365 _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
1366 struct spawn_fd_item_s *fd_list,
1367 void (*atfork) (void *opaque, int reserved),
1368 void *atforkvalue, pid_t *r_pid)
1370 PROCESS_INFORMATION pi =
1372 NULL, /* returns process handle */
1373 0, /* returns primary thread handle */
1374 0, /* returns pid */
1379 SECURITY_ATTRIBUTES sec_attr;
1381 int cr_flags = CREATE_DEFAULT_ERROR_MODE;
1388 const char *spawnhelper;
1390 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1399 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1403 /* We do not inherit any handles by default, and just insert those
1404 handles we want the child to have afterwards. But some handle
1405 values occur on the command line, and we need to move
1406 stdin/out/err to the right location. So we use a wrapper program
1407 which gets the information from a temporary file. */
1408 if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
1410 TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
1411 return TRACE_SYSRES (-1);
1413 TRACE_LOG1 ("tmp_name = %s", tmp_name);
1415 args = calloc (2 + i + 1, sizeof (*args));
1416 args[0] = (char *) _gpgme_get_w32spawn_path ();
1418 args[2] = (char *)path;
1419 memcpy (&args[3], &argv[1], i * sizeof (*args));
1421 memset (&sec_attr, 0, sizeof sec_attr);
1422 sec_attr.nLength = sizeof sec_attr;
1423 sec_attr.bInheritHandle = FALSE;
1425 arg_string = build_commandline (args);
1430 DeleteFileA (tmp_name);
1432 return TRACE_SYSRES (-1);
1435 memset (&si, 0, sizeof si);
1436 si.cb = sizeof (si);
1437 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1438 si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
1439 si.hStdInput = INVALID_HANDLE_VALUE;
1440 si.hStdOutput = INVALID_HANDLE_VALUE;
1441 si.hStdError = INVALID_HANDLE_VALUE;
1443 cr_flags |= CREATE_SUSPENDED;
1444 if ((flags & IOSPAWN_FLAG_DETACHED))
1445 cr_flags |= DETACHED_PROCESS;
1446 cr_flags |= GetPriorityClass (GetCurrentProcess ());
1447 spawnhelper = _gpgme_get_w32spawn_path ();
1450 /* This is a common mistake for new users of gpgme not to include
1451 gpgme-w32spawn.exe with their binary. So we want to make
1452 this transparent to developers. If users have somehow messed
1453 up their installation this should also be properly communicated
1454 as otherwise calls to gnupg will result in unsupported protocol
1455 errors that do not explain a lot. */
1457 gpgrt_asprintf (&msg, "gpgme-w32spawn.exe was not found in the "
1458 "detected installation directory of GpgME"
1460 "Crypto operations will not work.\n\n"
1461 "If you see this it indicates a problem "
1462 "with your installation.\n"
1463 "Please report the problem to your "
1464 "distributor of GpgME.\n\n"
1465 "Developer's Note: The install dir can be "
1466 "manually set with: gpgme_set_global_flag",
1467 _gpgme_get_inst_dir ());
1468 MessageBoxA (NULL, msg, "GpgME not installed correctly", MB_OK);
1470 gpg_err_set_errno (EIO);
1472 DeleteFileA (tmp_name);
1474 return TRACE_SYSRES (-1);
1476 if (!CreateProcessA (spawnhelper,
1478 &sec_attr, /* process security attributes */
1479 &sec_attr, /* thread security attributes */
1480 FALSE, /* inherit handles */
1481 cr_flags, /* creation flags */
1482 NULL, /* environment */
1483 NULL, /* use current drive/directory */
1484 &si, /* startup information */
1485 &pi)) /* returns process information */
1487 int lasterr = (int)GetLastError ();
1488 TRACE_LOG1 ("CreateProcess failed: ec=%d", lasterr);
1491 DeleteFileA (tmp_name);
1494 /* FIXME: Should translate the error code. */
1495 gpg_err_set_errno (EIO);
1496 return TRACE_SYSRES (-1);
1499 if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
1500 _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
1502 /* Insert the inherited handles. */
1503 LOCK (fd_table_lock);
1504 for (i = 0; fd_list[i].fd != -1; i++)
1506 int fd = fd_list[i].fd;
1507 HANDLE ohd = INVALID_HANDLE_VALUE;
1508 HANDLE hd = INVALID_HANDLE_VALUE;
1510 /* Make it inheritable for the wrapper process. */
1511 if (fd >= 0 && fd < fd_table_size && fd_table[fd].used
1512 && fd_table[fd].hdd)
1513 ohd = fd_table[fd].hdd->hd;
1515 if (!DuplicateHandle (GetCurrentProcess(), ohd,
1516 pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
1518 TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
1519 TerminateProcess (pi.hProcess, 0);
1520 /* Just in case TerminateProcess didn't work, let the
1521 process fail on its own. */
1522 ResumeThread (pi.hThread);
1523 close_handle (pi.hThread);
1524 close_handle (pi.hProcess);
1527 DeleteFileA (tmp_name);
1530 /* FIXME: Should translate the error code. */
1531 gpg_err_set_errno (EIO);
1532 UNLOCK (fd_table_lock);
1533 return TRACE_SYSRES (-1);
1535 /* Return the child name of this handle. */
1536 fd_list[i].peer_name = handle_to_fd (hd);
1539 /* Write the handle translation information to the temporary
1542 /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
1543 notation: "0xFEDCBA9876543210" with an extra white space after
1544 every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead
1545 for a time when a HANDLE is 64 bit. */
1546 #define BUFFER_MAX 810
1547 char line[BUFFER_MAX + 1];
1553 snprintf (line, BUFFER_MAX, "~%i \n", flags);
1555 strcpy (line, "\n");
1556 for (i = 0; fd_list[i].fd != -1; i++)
1558 /* Strip the newline. */
1559 len = strlen (line) - 1;
1561 /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx. */
1562 snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d \n",
1563 fd_list[i].fd, fd_list[i].dup_to,
1564 fd_list[i].peer_name, fd_list[i].arg_loc);
1565 /* Rather safe than sorry. */
1566 line[BUFFER_MAX - 1] = '\n';
1567 line[BUFFER_MAX] = '\0';
1569 len = strlen (line);
1573 res = write (tmp_fd, &line[written], len - written);
1577 while (res > 0 || (res < 0 && errno == EAGAIN));
1580 /* The temporary file is deleted by the gpgme-w32spawn process
1586 UNLOCK (fd_table_lock);
1588 TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
1589 "dwProcessID=%d, dwThreadId=%d",
1590 pi.hProcess, pi.hThread,
1591 (int) pi.dwProcessId, (int) pi.dwThreadId);
1594 *r_pid = (pid_t)pi.dwProcessId;
1597 if (ResumeThread (pi.hThread) == (DWORD)(-1))
1598 TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
1600 close_handle (pi.hThread);
1602 TRACE_LOG1 ("process=%p", pi.hProcess);
1604 /* We don't need to wait for the process. */
1605 close_handle (pi.hProcess);
1607 if (! (flags & IOSPAWN_FLAG_NOCLOSE))
1609 for (i = 0; fd_list[i].fd != -1; i++)
1610 _gpgme_io_close (fd_list[i].fd);
1613 for (i = 0; fd_list[i].fd != -1; i++)
1614 if (fd_list[i].dup_to == -1)
1615 TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
1616 fd_list[i].peer_name);
1618 TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
1619 fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
1620 ((fd_list[i].dup_to == 1) ? "out" : "err"));
1622 return TRACE_SYSRES (0);
1626 /* Select on the list of fds. Returns: -1 = error, 0 = timeout or
1627 nothing to select, > 0 = number of signaled fds. */
1629 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
1631 HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1632 int waitidx[MAXIMUM_WAIT_OBJECTS];
1639 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
1640 "nfds=%u, nonblock=%u", nfds, nonblock);
1645 TRACE_SEQ (dbg_help, "select on [ ");
1649 for (i=0; i < nfds; i++)
1651 if (fds[i].fd == -1)
1653 fds[i].signaled = 0;
1654 if (fds[i].for_read || fds[i].for_write)
1656 if (fds[i].for_read)
1658 /* FIXME: A find_reader_locked() along with separate
1659 * lock calls might be a better appaoched here. */
1660 struct reader_context_s *ctx = find_reader (fds[i].fd);
1663 TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
1667 if (nwait >= DIM (waitbuf))
1669 TRACE_END (dbg_help, "oops ]");
1670 TRACE_LOG ("Too many objects for WFMO!");
1671 /* FIXME: Should translate the error code. */
1672 gpg_err_set_errno (EIO);
1673 return TRACE_SYSRES (-1);
1676 waitbuf[nwait++] = ctx->have_data_ev;
1678 TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
1681 else if (fds[i].for_write)
1683 struct writer_context_s *ctx = find_writer (fds[i].fd);
1686 TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
1690 if (nwait >= DIM (waitbuf))
1692 TRACE_END (dbg_help, "oops ]");
1693 TRACE_LOG ("Too many objects for WFMO!");
1694 /* FIXME: Should translate the error code. */
1695 gpg_err_set_errno (EIO);
1696 return TRACE_SYSRES (-1);
1699 waitbuf[nwait++] = ctx->is_empty;
1701 TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
1706 TRACE_END (dbg_help, "]");
1708 return TRACE_SYSRES (0);
1710 code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
1711 if (code < WAIT_OBJECT_0 + nwait)
1713 /* The WFMO is a really silly function: It does return either
1714 the index of the signaled object or if 2 objects have been
1715 signalled at the same time, the index of the object with the
1716 lowest object is returned - so and how do we find out how
1717 many objects have been signaled?. The only solution I can
1718 imagine is to test each object starting with the returned
1719 index individually - how dull. */
1721 for (i = code - WAIT_OBJECT_0; i < nwait; i++)
1723 if (wait_for_single_object (waitbuf[i], 0) == WAIT_OBJECT_0)
1725 assert (waitidx[i] >=0 && waitidx[i] < nfds);
1726 fds[waitidx[i]].signaled = 1;
1733 TRACE_LOG ("no signaled objects found after WFMO");
1737 else if (code == WAIT_TIMEOUT)
1738 TRACE_LOG ("WFMO timed out");
1739 else if (code == WAIT_FAILED)
1741 int le = (int) GetLastError ();
1743 if (le == ERROR_INVALID_HANDLE)
1746 int j = handle_to_fd (waitbuf[i]);
1748 TRACE_LOG1 ("WFMO invalid handle %d removed", j);
1749 for (k = 0 ; k < nfds; k++)
1753 fds[k].for_read = fds[k].for_write = 0;
1757 TRACE_LOG (" oops, or not???");
1760 TRACE_LOG1 ("WFMO failed: %d", le);
1765 TRACE_LOG1 ("WFMO returned %d", code);
1771 TRACE_SEQ (dbg_help, "select OK [ ");
1772 for (i = 0; i < nfds; i++)
1774 if (fds[i].fd == -1)
1776 if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
1777 TRACE_ADD2 (dbg_help, "%c0x%x ",
1778 fds[i].for_read ? 'r' : 'w', fds[i].fd);
1780 TRACE_END (dbg_help, "]");
1785 /* FIXME: Should determine a proper error code. */
1786 gpg_err_set_errno (EIO);
1789 return TRACE_SYSRES (count);
1794 _gpgme_io_subsystem_init (void)
1796 /* Nothing to do. */
1800 /* Write the printable version of FD to BUFFER which has an allocated
1801 * length of BUFLEN. The printable version is the representation on
1802 * the command line that the child process expects. Note that this
1803 * works closely together with the gpgme-32spawn wrapper process which
1804 * translates these command line args to the real handles. */
1806 _gpgme_io_fd2str (char *buffer, int buflen, int fd)
1808 return snprintf (buffer, buflen, "%d", fd);
1813 _gpgme_io_dup (int fd)
1816 struct reader_context_s *rd_ctx;
1817 struct writer_context_s *wt_ctx;
1818 int want_reader, want_writer;
1820 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
1822 LOCK (fd_table_lock);
1823 if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used)
1825 UNLOCK (fd_table_lock);
1826 gpg_err_set_errno (EBADF);
1827 return TRACE_SYSRES (-1);
1833 UNLOCK (fd_table_lock);
1834 gpg_err_set_errno (EMFILE);
1835 return TRACE_SYSRES (-1);
1838 fd_table[newfd].hdd = ref_hddesc (fd_table[fd].hdd);
1839 fd_table[newfd].dup_from = fd;
1840 want_reader = fd_table[fd].want_reader;
1841 want_writer = fd_table[fd].want_writer;
1843 UNLOCK (fd_table_lock);
1845 rd_ctx = want_reader? find_reader (fd) : NULL;
1848 /* NEWFD initializes a freshly allocated slot and does not need
1850 LOCK (rd_ctx->mutex);
1852 UNLOCK (rd_ctx->mutex);
1853 fd_table[newfd].reader = rd_ctx;
1856 wt_ctx = want_writer? find_writer (fd) : NULL;
1859 LOCK (wt_ctx->mutex);
1861 UNLOCK (wt_ctx->mutex);
1862 fd_table[newfd].writer = wt_ctx;
1865 return TRACE_SYSRES (newfd);
1869 /* The following interface is only useful for GPGME Glib and Qt. */
1871 /* Compatibility interface, obsolete. */
1873 gpgme_get_giochannel (int fd)
1880 /* Look up the giochannel or qiodevice for file descriptor FD. */
1882 gpgme_get_fdptr (int fd)
1896 case WSAEWOULDBLOCK:
1898 case ERROR_BROKEN_PIPE:
1900 case WSANOTINITIALISED:
1909 _gpgme_io_socket (int domain, int type, int proto)
1915 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
1916 "type=%i, protp=%i", type, proto);
1920 return TRACE_SYSRES (-1);
1921 hdd = new_hddesc ();
1924 UNLOCK (fd_table_lock);
1926 gpg_err_set_errno (ENOMEM);
1927 return TRACE_SYSRES (-1);
1930 res = socket (domain, type, proto);
1931 if (res == INVALID_SOCKET)
1934 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
1935 return TRACE_SYSRES (-1);
1937 ref_hddesc (hdd)->sock = res;
1938 fd_table[fd].hdd = hdd;
1939 fd_table[fd].want_reader = 1;
1940 fd_table[fd].want_writer = 1;
1942 TRACE_SUC3 ("hdd=%p, socket=0x%x (0x%x)", hdd, fd, hdd->sock);
1949 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
1954 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
1955 "addr=%p, addrlen=%i", addr, addrlen);
1957 LOCK (fd_table_lock);
1958 if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used || !fd_table[fd].hdd)
1960 gpg_err_set_errno (EBADF);
1961 UNLOCK (fd_table_lock);
1962 return TRACE_SYSRES (-1);
1964 sock = fd_table[fd].hdd->sock;
1965 UNLOCK (fd_table_lock);
1967 res = connect (sock, addr, addrlen);
1970 gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
1971 return TRACE_SYSRES (-1);
1974 return TRACE_SUC ();