f6d58f47622d2d022398cb84f98824e08414ec6e
[gpgme.git] / src / w32-io.c
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
4  *
5  * This file is part of GPGME.
6  *
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.
11  *
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.
16  *
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+
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #ifdef HAVE_SYS_TIME_H
32 # include <sys/time.h>
33 #endif
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37 #include <io.h>
38
39 #include "util.h"
40 #include "sema.h"
41 #include "priv-io.h"
42 #include "debug.h"
43 #include "sys-util.h"
44
45
46 /* The number of entries in our file table.  We may eventually use a
47  * lower value and dynamically resize the table.  */
48 #define MAX_SLAFD 512
49
50 #define handle_to_fd(a)  ((int)(a))
51
52 #define READBUF_SIZE 4096
53 #define WRITEBUF_SIZE 4096
54 #define PIPEBUF_SIZE  4096
55
56
57 /* An object to store handles or sockets.  */
58 struct hddesc_s
59 {
60   HANDLE hd;
61   SOCKET sock;
62   int refcount;
63 };
64 typedef struct hddesc_s *hddesc_t;
65
66
67
68 /* The context used by a reader thread.  */
69 struct reader_context_s
70 {
71   hddesc_t hdd;
72   HANDLE thread_hd;
73   int refcount;   /* Bumped if the FD has been duped and thus we have
74                    * another FD referencing this context.  */
75
76   DECLARE_LOCK (mutex);
77
78   int stop_me;
79   int eof;
80   int eof_shortcut;
81   int error;
82   int error_code;
83
84   /* This is manually reset.  */
85   HANDLE have_data_ev;
86   /* This is automatically reset.  */
87   HANDLE have_space_ev;
88   /* This is manually reset but actually only triggered once.  */
89   HANDLE close_ev;
90
91   size_t readpos, writepos;
92   char buffer[READBUF_SIZE];
93 };
94
95
96 /* The context used by a writer thread.  */
97 struct writer_context_s
98 {
99   hddesc_t hdd;
100   HANDLE thread_hd;
101   int refcount;
102
103   DECLARE_LOCK (mutex);
104
105   int stop_me;
106   int error;
107   int error_code;
108
109   /* This is manually reset.  */
110   HANDLE have_data;
111   HANDLE is_empty;
112   HANDLE close_ev;
113   size_t nbytes;
114   char buffer[WRITEBUF_SIZE];
115 };
116
117
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.  */
123 static struct
124 {
125   int used;
126
127   /* The handle descriptor.  */
128   hddesc_t hdd;
129
130   /* DUP_FROM is just a debug helper to show from which fd this fd was
131    * dup-ed. */
132   int dup_from;
133
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;
139
140   /* The context of an associated reader object or NULL.  */
141   struct reader_context_s *reader;
142
143   /* The context of an associated writer object or NULL.  */
144   struct writer_context_s *writer;
145
146   /* A notification hanlder.  Noet that we current support only one
147    * callback per fd.  */
148   struct {
149     _gpgme_close_notify_handler_t handler;
150     void *value;
151   } notify;
152
153 } fd_table[MAX_SLAFD];
154 static size_t fd_table_size = MAX_SLAFD;
155
156 DEFINE_STATIC_LOCK (fd_table_lock);
157
158
159 /* We use a single global lock for all hddesc_t objects.  */
160 DEFINE_STATIC_LOCK (hddesc_lock);
161
162
163 \f
164 /* Wrapper around CloseHandle to print an error.  */
165 #define close_handle(hd) _close_handle ((hd), __LINE__);
166 static void
167 _close_handle (HANDLE hd, int line)
168 {
169   if (!CloseHandle (hd))
170     {
171       TRACE2 (DEBUG_INIT, "w32-io", hd, "CloseHandle failed at line %d: ec=%d",
172               line, (int) GetLastError ());
173     }
174 }
175
176 /* Wrapper around WaitForSingleObject to print an error.  */
177 #define wait_for_single_object(hd,msec) \
178         _wait_for_single_object ((hd), (msec), __LINE__)
179 static DWORD
180 _wait_for_single_object (HANDLE hd, DWORD msec, int line)
181 {
182   DWORD res;
183
184   res = WaitForSingleObject (hd, msec);
185   if (res == WAIT_FAILED)
186     {
187       TRACE2 (DEBUG_INIT, "w32-io", hd,
188               "WFSO failed at line %d: ec=%d", line, (int) GetLastError ());
189     }
190   return res;
191 }
192
193
194 /* Create a new handle descriptor object.  */
195 static hddesc_t
196 new_hddesc (void)
197 {
198   hddesc_t hdd;
199
200   hdd = malloc (sizeof *hdd);
201   if (!hdd)
202     return NULL;
203   hdd->hd = INVALID_HANDLE_VALUE;
204   hdd->sock = INVALID_SOCKET;
205   hdd->refcount = 0;
206
207   return hdd;
208 }
209
210
211 static hddesc_t
212 ref_hddesc (hddesc_t hdd)
213 {
214   LOCK (hddesc_lock);
215   hdd->refcount++;
216   UNLOCK (hddesc_lock);
217   return hdd;
218 }
219
220
221 /* Release a handle descriptor object and close its handle or socket
222  * if needed.  */
223 static void
224 release_hddesc (hddesc_t hdd)
225 {
226   if (!hdd)
227     return;
228
229   LOCK (hddesc_lock);
230   hdd->refcount--;
231   if (hdd->refcount < 1)
232     {
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);
238
239       if (hdd->hd != INVALID_HANDLE_VALUE)
240         close_handle (hdd->hd);
241
242       if (hdd->sock != INVALID_SOCKET)
243         {
244           TRACE_LOG1 ("closing socket %d", hdd->sock);
245           if (closesocket (hdd->sock))
246             {
247               TRACE_LOG1 ("closesocket failed: ec=%d", (int)WSAGetLastError ());
248             }
249         }
250
251       free (hdd);
252       TRACE_SUC ();
253     }
254   UNLOCK (hddesc_lock);
255 }
256
257
258
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.  */
262 static int
263 new_fd (void)
264 {
265   int idx;
266
267   LOCK (fd_table_lock);
268
269   for (idx = 0; idx < fd_table_size; idx++)
270     if (! fd_table[idx].used)
271       break;
272
273   if (idx == fd_table_size)
274     {
275       gpg_err_set_errno (EIO);
276       idx = -1;
277     }
278   else
279     {
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;
289     }
290
291   UNLOCK (fd_table_lock);
292
293   return idx;
294 }
295
296
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
299  * function.  */
300 static void
301 release_fd (int fd)
302 {
303   if (fd < 0 || fd >= fd_table_size)
304     return;
305
306   LOCK (fd_table_lock);
307
308   if (fd_table[fd].used)
309     {
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;
320     }
321
322   UNLOCK (fd_table_lock);
323 }
324
325
326 static int
327 get_desired_thread_priority (void)
328 {
329   int value;
330
331   if (!_gpgme_get_conf_int ("IOThreadPriority", &value))
332     {
333       value = THREAD_PRIORITY_HIGHEST;
334       TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
335               "%d (default)", value);
336     }
337   else
338     {
339       TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
340               "%d (configured)", value);
341     }
342   return value;
343 }
344
345
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
350 reader (void *arg)
351 {
352   struct reader_context_s *ctx = arg;
353   int nbytes;
354   DWORD nread;
355   int sock;
356
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);
360
361   if (ctx->hdd->hd != INVALID_HANDLE_VALUE)
362     sock = 0;
363   else
364     sock = 1;
365
366   for (;;)
367     {
368       LOCK (ctx->mutex);
369       /* Leave a 1 byte gap so that we can see whether it is empty or
370          full.  */
371       if ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
372         {
373           /* Wait for space.  */
374           if (!ResetEvent (ctx->have_space_ev))
375             {
376               TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
377             }
378           UNLOCK (ctx->mutex);
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");
382           LOCK (ctx->mutex);
383         }
384       if (ctx->stop_me)
385         {
386           UNLOCK (ctx->mutex);
387           break;
388         }
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;
393       UNLOCK (ctx->mutex);
394
395       TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes);
396
397       if (sock)
398         {
399           int n;
400
401           n = recv (ctx->hdd->sock, ctx->buffer + ctx->writepos, nbytes, 0);
402           if (n < 0)
403             {
404               ctx->error_code = (int) WSAGetLastError ();
405               if (ctx->error_code == ERROR_BROKEN_PIPE)
406                 {
407                   ctx->eof = 1;
408                   TRACE_LOG ("got EOF (broken connection)");
409                 }
410               else
411                 {
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)
416                     {
417                       LOCK (ctx->mutex);
418                       if (ctx->stop_me)
419                         {
420                           UNLOCK (ctx->mutex);
421                           TRACE_LOG ("got shutdown");
422                           break;
423                         }
424                       UNLOCK (ctx->mutex);
425                     }
426
427                   ctx->error = 1;
428                   TRACE_LOG1 ("recv error: ec=%d", ctx->error_code);
429                 }
430               break;
431             }
432           nread = n;
433         }
434       else
435         {
436           if (!ReadFile (ctx->hdd->hd,
437                          ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
438             {
439               ctx->error_code = (int) GetLastError ();
440               if (ctx->error_code == ERROR_BROKEN_PIPE)
441                 {
442                   ctx->eof = 1;
443                   TRACE_LOG ("got EOF (broken pipe)");
444                 }
445               else if (ctx->error_code == ERROR_OPERATION_ABORTED)
446                 {
447                   ctx->eof = 1;
448                   TRACE_LOG ("got EOF (closed by us)");
449                 }
450               else
451                 {
452                   ctx->error = 1;
453                   TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
454                 }
455               break;
456             }
457         }
458       LOCK (ctx->mutex);
459       if (ctx->stop_me)
460         {
461           UNLOCK (ctx->mutex);
462           break;
463         }
464       if (!nread)
465         {
466           ctx->eof = 1;
467           TRACE_LOG ("got eof");
468           UNLOCK (ctx->mutex);
469           break;
470         }
471
472       TRACE_LOG2 ("got %u bytes (refcnt=%d)", nread, ctx->refcount);
473
474       ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
475       if (!SetEvent (ctx->have_data_ev))
476         {
477           TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
478                       (int) GetLastError ());
479         }
480       UNLOCK (ctx->mutex);
481     }
482   /* Indicate that we have an error or EOF.  */
483   if (!SetEvent (ctx->have_data_ev))
484     {
485       TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
486                 (int) GetLastError ());
487     }
488
489   TRACE_LOG ("waiting for close");
490   wait_for_single_object (ctx->close_ev, INFINITE);
491
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);
498   free (ctx);
499
500   return TRACE_SUC ();
501 }
502
503
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
507  * fd_table.  */
508 static struct reader_context_s *
509 create_reader (hddesc_t hdd)
510 {
511   struct reader_context_s *ctx;
512   SECURITY_ATTRIBUTES sec_attr;
513   DWORD tid;
514
515   TRACE_BEG3 (DEBUG_SYSIO, "gpgme:create_reader", hdd,
516               "handle=%p sock=%d refhdd=%d",
517               hdd->hd, hdd->sock, hdd->refcount);
518
519   memset (&sec_attr, 0, sizeof sec_attr);
520   sec_attr.nLength = sizeof sec_attr;
521   sec_attr.bInheritHandle = FALSE;
522
523   ctx = calloc (1, sizeof *ctx);
524   if (!ctx)
525     {
526       TRACE_SYSERR (errno);
527       return NULL;
528     }
529
530   ctx->hdd = ref_hddesc (hdd);
531
532   ctx->refcount = 1;
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)
539     {
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);
545       if (ctx->close_ev)
546         close_handle (ctx->close_ev);
547       release_hddesc (ctx->hdd);
548       free (ctx);
549       TRACE_SYSERR (EIO);
550       return NULL;
551     }
552
553   INIT_LOCK (ctx->mutex);
554
555   ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid);
556
557   if (!ctx->thread_hd)
558     {
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);
565       if (ctx->close_ev)
566         close_handle (ctx->close_ev);
567       release_hddesc (ctx->hdd);
568       free (ctx);
569       TRACE_SYSERR (EIO);
570       return NULL;
571     }
572   else
573     {
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 ());
578     }
579
580   TRACE_SUC ();
581   return ctx;
582 }
583
584
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
587    not be called.  */
588 static void
589 destroy_reader (struct reader_context_s *ctx)
590 {
591   LOCK (ctx->mutex);
592   ctx->refcount--;
593   if (ctx->refcount != 0)
594     {
595       TRACE2 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx,
596               "hdd=%p refcount now %d", ctx->hdd, ctx->refcount);
597       UNLOCK (ctx->mutex);
598       return;
599     }
600   ctx->stop_me = 1;
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);
605   UNLOCK (ctx->mutex);
606
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.  */
615   assert (ctx->hdd);
616   if (ctx->hdd && ctx->hdd->hd != INVALID_HANDLE_VALUE)
617     {
618       _gpgme_w32_cancel_synchronous_io (ctx->thread_hd);
619     }
620   else if (ctx->hdd && ctx->hdd->sock != INVALID_SOCKET)
621     {
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 ());
626     }
627
628   /* After setting this event CTX is void. */
629   SetEvent (ctx->close_ev);
630 }
631
632
633
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 *
638 find_reader (int fd)
639 {
640   struct reader_context_s *rd = NULL;
641
642   TRACE_BEG0 (DEBUG_SYSIO, "gpgme:find_reader", fd, "");
643
644   LOCK (fd_table_lock);
645   if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used)
646     {
647       UNLOCK (fd_table_lock);
648       gpg_err_set_errno (EBADF);
649       TRACE_SUC0 ("EBADF");
650       return NULL;
651     }
652
653   rd = fd_table[fd].reader;
654   if (rd)
655     {
656       UNLOCK (fd_table_lock);
657       TRACE_SUC1 ("rd=%p", rd);
658       return rd;  /* Return already initialized reader thread object.  */
659     }
660
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);
665   if (!rd)
666     gpg_err_set_errno (EIO);
667   else
668     fd_table[fd].reader = rd;
669
670   UNLOCK (fd_table_lock);
671   TRACE_SUC1 ("rd=%p (new)", rd);
672   return rd;
673 }
674
675
676 int
677 _gpgme_io_read (int fd, void *buffer, size_t count)
678 {
679   int nread;
680   struct reader_context_s *ctx;
681   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
682               "buffer=%p, count=%u", buffer, count);
683
684   ctx = find_reader (fd);
685   if (!ctx)
686     return TRACE_SYSRES (-1);
687   if (ctx->eof_shortcut)
688     return TRACE_SYSRES (0);
689
690   LOCK (ctx->mutex);
691   if (ctx->readpos == ctx->writepos && !ctx->error)
692     {
693       /* No data available.  */
694       UNLOCK (ctx->mutex);
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);
698       LOCK (ctx->mutex);
699     }
700
701   if (ctx->readpos == ctx->writepos || ctx->error)
702     {
703       UNLOCK (ctx->mutex);
704       ctx->eof_shortcut = 1;
705       if (ctx->eof)
706         return TRACE_SYSRES (0);
707       if (!ctx->error)
708         {
709           TRACE_LOG ("EOF but ctx->eof flag not set");
710           return 0;
711         }
712       gpg_err_set_errno (ctx->error_code);
713       return TRACE_SYSRES (-1);
714     }
715
716   nread = ctx->readpos < ctx->writepos
717     ? ctx->writepos - ctx->readpos
718     : READBUF_SIZE - ctx->readpos;
719   if (nread > count)
720     nread = count;
721   memcpy (buffer, ctx->buffer + ctx->readpos, nread);
722   ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
723   if (ctx->readpos == ctx->writepos && !ctx->eof)
724     {
725       if (!ResetEvent (ctx->have_data_ev))
726         {
727           TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
728           UNLOCK (ctx->mutex);
729           /* FIXME: Should translate the error code.  */
730           gpg_err_set_errno (EIO);
731           return TRACE_SYSRES (-1);
732         }
733     }
734   if (!SetEvent (ctx->have_space_ev))
735     {
736       TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d",
737                   ctx->have_space_ev, (int) GetLastError ());
738       UNLOCK (ctx->mutex);
739       /* FIXME: Should translate the error code.  */
740       gpg_err_set_errno (EIO);
741       return TRACE_SYSRES (-1);
742     }
743   UNLOCK (ctx->mutex);
744
745   TRACE_LOGBUFX (buffer, nread);
746   return TRACE_SYSRES (nread);
747 }
748
749
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
754 writer (void *arg)
755 {
756   struct writer_context_s *ctx = arg;
757   DWORD nwritten;
758   int sock;
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);
762
763   if (ctx->hdd->hd != INVALID_HANDLE_VALUE)
764     sock = 0;
765   else
766     sock = 1;
767
768   for (;;)
769     {
770       LOCK (ctx->mutex);
771       if (ctx->stop_me && !ctx->nbytes)
772         {
773           UNLOCK (ctx->mutex);
774           break;
775         }
776       if (!ctx->nbytes)
777         {
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 ());
782           UNLOCK (ctx->mutex);
783           TRACE_LOG ("idle");
784           wait_for_single_object (ctx->have_data, INFINITE);
785           TRACE_LOG ("got data to send");
786           LOCK (ctx->mutex);
787         }
788       if (ctx->stop_me && !ctx->nbytes)
789         {
790           UNLOCK (ctx->mutex);
791           break;
792         }
793       UNLOCK (ctx->mutex);
794
795       TRACE_LOG2 ("%s %d bytes", sock?"sending":"writing", ctx->nbytes);
796
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.  */
800       if (sock)
801         {
802           /* We need to try send first because a socket handle can't
803              be used with WriteFile.  */
804           int n;
805
806           n = send (ctx->hdd->sock, ctx->buffer, ctx->nbytes, 0);
807           if (n < 0)
808             {
809               ctx->error_code = (int) WSAGetLastError ();
810               ctx->error = 1;
811               TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
812               break;
813             }
814           nwritten = n;
815         }
816       else
817         {
818           if (!WriteFile (ctx->hdd->hd, ctx->buffer,
819                           ctx->nbytes, &nwritten, NULL))
820             {
821               if (GetLastError () == ERROR_BUSY)
822                 {
823                   /* Probably stop_me is set now.  */
824                   TRACE_LOG ("pipe busy (unblocked?)");
825                   continue;
826                 }
827
828               ctx->error_code = (int) GetLastError ();
829               ctx->error = 1;
830               TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
831               break;
832             }
833         }
834       TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
835
836       LOCK (ctx->mutex);
837       ctx->nbytes -= nwritten;
838       UNLOCK (ctx->mutex);
839     }
840   /* Indicate that we have an error.  */
841   if (!SetEvent (ctx->is_empty))
842     TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
843
844   TRACE_LOG ("waiting for close");
845   wait_for_single_object (ctx->close_ev, INFINITE);
846
847   if (ctx->nbytes)
848     TRACE_LOG1 ("still %d bytes in buffer at close time", ctx->nbytes);
849
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);
856   free (ctx);
857
858   return TRACE_SUC ();
859 }
860
861
862 static struct writer_context_s *
863 create_writer (hddesc_t hdd)
864 {
865   struct writer_context_s *ctx;
866   SECURITY_ATTRIBUTES sec_attr;
867   DWORD tid;
868
869
870 TRACE_BEG3 (DEBUG_SYSIO, "gpgme:create_writer", hdd,
871              "handle=%p sock=%d refhdd=%d",
872              hdd->hd, hdd->sock, hdd->refcount);
873
874   memset (&sec_attr, 0, sizeof sec_attr);
875   sec_attr.nLength = sizeof sec_attr;
876   sec_attr.bInheritHandle = FALSE;
877
878   ctx = calloc (1, sizeof *ctx);
879   if (!ctx)
880     {
881       TRACE_SYSERR (errno);
882       return NULL;
883     }
884
885   ctx->hdd = ref_hddesc (hdd);
886
887   ctx->refcount = 1;
888   ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
889   if (ctx->have_data)
890     ctx->is_empty  = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
891   if (ctx->is_empty)
892     ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
893   if (!ctx->have_data || !ctx->is_empty || !ctx->close_ev)
894     {
895       TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
896       if (ctx->have_data)
897         close_handle (ctx->have_data);
898       if (ctx->is_empty)
899         close_handle (ctx->is_empty);
900       if (ctx->close_ev)
901         close_handle (ctx->close_ev);
902       release_hddesc (ctx->hdd);
903       free (ctx);
904       /* FIXME: Translate the error code.  */
905       TRACE_SYSERR (EIO);
906       return NULL;
907     }
908
909   INIT_LOCK (ctx->mutex);
910
911   ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
912   if (!ctx->thread_hd)
913     {
914       TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
915       DESTROY_LOCK (ctx->mutex);
916       if (ctx->have_data)
917         close_handle (ctx->have_data);
918       if (ctx->is_empty)
919         close_handle (ctx->is_empty);
920       if (ctx->close_ev)
921         close_handle (ctx->close_ev);
922       release_hddesc (ctx->hdd);
923       free (ctx);
924       TRACE_SYSERR (EIO);
925       return NULL;
926     }
927   else
928     {
929       /* We set the priority of the thread higher because we know
930          that it only runs for a short time.  This greatly helps to
931          increase the performance of the I/O.  */
932       SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
933     }
934
935   TRACE_SUC ();
936   return ctx;
937 }
938
939
940 static void
941 destroy_writer (struct writer_context_s *ctx)
942 {
943   LOCK (ctx->mutex);
944   ctx->refcount--;
945   if (ctx->refcount != 0)
946     {
947       TRACE2 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx,
948               "hdd=%p refcount now %d", ctx->hdd, ctx->refcount);
949       UNLOCK (ctx->mutex);
950       return;
951     }
952   ctx->stop_me = 1;
953   if (ctx->have_data)
954     SetEvent (ctx->have_data);
955   TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx,
956           "hdd=%p close triggered", ctx->hdd);
957   UNLOCK (ctx->mutex);
958
959   /* Give the writer a chance to flush the buffer.  */
960   wait_for_single_object (ctx->is_empty, INFINITE);
961
962   /* After setting this event CTX is void.  */
963   SetEvent (ctx->close_ev);
964 }
965
966
967 /* Find a writer context or create a new one.  Note that the writer
968  * context will last until a _gpgme_io_close.  NULL is returned for a
969  * bad FD or for other errors.  */
970 static struct writer_context_s *
971 find_writer (int fd)
972 {
973   struct writer_context_s *wt = NULL;
974   HANDLE ahandle;
975
976   TRACE_BEG0 (DEBUG_SYSIO, "gpgme:find_writer", fd, "");
977
978   LOCK (fd_table_lock);
979   if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used)
980     {
981       UNLOCK (fd_table_lock);
982       gpg_err_set_errno (EBADF);
983       TRACE_SUC0 ("EBADF");
984       return NULL;
985     }
986
987   wt = fd_table[fd].writer;
988   if (wt)
989     {
990       UNLOCK (fd_table_lock);
991       TRACE_SUC1 ("wt=%p", wt);
992       return wt;  /* Return already initialized writer thread object.  */
993     }
994
995   /* Create a new writer thread.  */
996   TRACE_LOG4 ("fd=%d -> handle=%p socket=%d dupfrom=%d creating writer",
997               fd, fd_table[fd].hdd->hd, fd_table[fd].hdd->sock,
998               fd_table[fd].dup_from);
999   wt = create_writer (fd_table[fd].hdd);
1000   if (!wt)
1001     gpg_err_set_errno (EIO);
1002   else
1003     fd_table[fd].writer = wt;
1004
1005   UNLOCK (fd_table_lock);
1006   TRACE_SUC1 ("wt=%p (new)", wt);
1007   return wt;
1008 }
1009
1010
1011 int
1012 _gpgme_io_write (int fd, const void *buffer, size_t count)
1013 {
1014   struct writer_context_s *ctx;
1015   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
1016               "buffer=%p, count=%u", buffer, count);
1017   TRACE_LOGBUFX (buffer, count);
1018
1019   if (count == 0)
1020     return TRACE_SYSRES (0);
1021
1022   ctx = find_writer (fd);
1023   if (!ctx)
1024     return TRACE_SYSRES (-1);
1025
1026   LOCK (ctx->mutex);
1027   if (!ctx->error && ctx->nbytes)
1028     {
1029       /* Bytes are pending for send.  */
1030
1031       /* Reset the is_empty event.  Better safe than sorry.  */
1032       if (!ResetEvent (ctx->is_empty))
1033         {
1034           TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
1035           UNLOCK (ctx->mutex);
1036           /* FIXME: Should translate the error code.  */
1037           gpg_err_set_errno (EIO);
1038           return TRACE_SYSRES (-1);
1039         }
1040       UNLOCK (ctx->mutex);
1041       TRACE_LOG1 ("waiting for empty buffer in thread %p", ctx->thread_hd);
1042       wait_for_single_object (ctx->is_empty, INFINITE);
1043       TRACE_LOG1 ("thread %p buffer is empty", ctx->thread_hd);
1044       LOCK (ctx->mutex);
1045     }
1046
1047   if (ctx->error)
1048     {
1049       UNLOCK (ctx->mutex);
1050       if (ctx->error_code == ERROR_NO_DATA)
1051         gpg_err_set_errno (EPIPE);
1052       else
1053         gpg_err_set_errno (EIO);
1054       return TRACE_SYSRES (-1);
1055     }
1056
1057   /* If no error occurred, the number of bytes in the buffer must be
1058      zero.  */
1059   assert (!ctx->nbytes);
1060
1061   if (count > WRITEBUF_SIZE)
1062     count = WRITEBUF_SIZE;
1063   memcpy (ctx->buffer, buffer, count);
1064   ctx->nbytes = count;
1065
1066   /* We have to reset the is_empty event early, because it is also
1067    * used by the select() implementation to probe the channel.  */
1068   if (!ResetEvent (ctx->is_empty))
1069     {
1070       TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
1071       UNLOCK (ctx->mutex);
1072       /* FIXME: Should translate the error code.  */
1073       gpg_err_set_errno (EIO);
1074       return TRACE_SYSRES (-1);
1075     }
1076   if (!SetEvent (ctx->have_data))
1077     {
1078       TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
1079       UNLOCK (ctx->mutex);
1080       /* FIXME: Should translate the error code.  */
1081       gpg_err_set_errno (EIO);
1082       return TRACE_SYSRES (-1);
1083     }
1084   UNLOCK (ctx->mutex);
1085
1086   return TRACE_SYSRES ((int) count);
1087 }
1088
1089
1090 int
1091 _gpgme_io_pipe (int filedes[2], int inherit_idx)
1092 {
1093   int rfd;
1094   int wfd;
1095   HANDLE rh;
1096   HANDLE wh;
1097   hddesc_t rhdesc;
1098   hddesc_t whdesc;
1099   SECURITY_ATTRIBUTES sec_attr;
1100
1101   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
1102               "inherit_idx=%i (GPGME uses it for %s)",
1103               inherit_idx, inherit_idx ? "reading" : "writing");
1104
1105   /* Get a new empty file descriptor.  */
1106   rfd = new_fd ();
1107   if (rfd == -1)
1108     return TRACE_SYSRES (-1);
1109   wfd = new_fd ();
1110   if (wfd == -1)
1111     {
1112       release_fd (rfd);
1113       return TRACE_SYSRES (-1);
1114     }
1115   rhdesc = new_hddesc ();
1116   if (!rhdesc)
1117     {
1118       release_fd (rfd);
1119       release_fd (wfd);
1120       return TRACE_SYSRES (-1);
1121     }
1122   whdesc = new_hddesc ();
1123   if (!whdesc)
1124     {
1125       release_fd (rfd);
1126       release_fd (wfd);
1127       release_hddesc (rhdesc);
1128       return TRACE_SYSRES (-1);
1129     }
1130
1131   /* Create a pipe.  */
1132   memset (&sec_attr, 0, sizeof (sec_attr));
1133   sec_attr.nLength = sizeof (sec_attr);
1134   sec_attr.bInheritHandle = FALSE;
1135
1136   if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
1137     {
1138       TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
1139       release_fd (rfd);
1140       release_fd (wfd);
1141       release_hddesc (rhdesc);
1142       release_hddesc (whdesc);
1143       gpg_err_set_errno (EIO);
1144       return TRACE_SYSRES (-1);
1145     }
1146
1147   /* Make one end inheritable.  */
1148   if (inherit_idx == 0)
1149     {
1150       HANDLE hd;
1151       if (!DuplicateHandle (GetCurrentProcess(), rh,
1152                             GetCurrentProcess(), &hd, 0,
1153                             TRUE, DUPLICATE_SAME_ACCESS))
1154         {
1155           TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1156                       (int) GetLastError ());
1157           release_fd (rfd);
1158           release_fd (wfd);
1159           close_handle (rh);
1160           close_handle (wh);
1161           release_hddesc (rhdesc);
1162           release_hddesc (whdesc);
1163           gpg_err_set_errno (EIO);
1164           return TRACE_SYSRES (-1);
1165         }
1166       close_handle (rh);
1167       rh = hd;
1168     }
1169   else if (inherit_idx == 1)
1170     {
1171       HANDLE hd;
1172       if (!DuplicateHandle( GetCurrentProcess(), wh,
1173                             GetCurrentProcess(), &hd, 0,
1174                             TRUE, DUPLICATE_SAME_ACCESS))
1175         {
1176           TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1177                       (int) GetLastError ());
1178           release_fd (rfd);
1179           release_fd (wfd);
1180           close_handle (rh);
1181           close_handle (wh);
1182           release_hddesc (rhdesc);
1183           release_hddesc (whdesc);
1184           gpg_err_set_errno (EIO);
1185           return TRACE_SYSRES (-1);
1186         }
1187       close_handle (wh);
1188       wh = hd;
1189     }
1190
1191   /* Put the HANDLEs of the new pipe into the file descriptor table.
1192    * Note that we don't need to lock the table because we have just
1193    * acquired these two fresh fds and they are not known by any other
1194    * thread.  */
1195   fd_table[rfd].want_reader = 1;
1196   ref_hddesc (rhdesc)->hd = rh;
1197   fd_table[rfd].hdd = rhdesc;
1198
1199   fd_table[wfd].want_writer = 1;
1200   ref_hddesc (whdesc)->hd = wh;
1201   fd_table[wfd].hdd = whdesc;
1202
1203   filedes[0] = rfd;
1204   filedes[1] = wfd;
1205   return TRACE_SUC6 ("read=0x%x (hdd=%p,hd=%p), write=0x%x (hdd=%p,hd=%p)",
1206                      rfd, fd_table[rfd].hdd, fd_table[rfd].hdd->hd,
1207                      wfd, fd_table[wfd].hdd, fd_table[wfd].hdd->hd);
1208 }
1209
1210
1211 /* Close out File descriptor FD.  */
1212 int
1213 _gpgme_io_close (int fd)
1214 {
1215   _gpgme_close_notify_handler_t handler = NULL;
1216   void *value = NULL;
1217   int any_reader_or_writer = 0;
1218
1219   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
1220
1221   if (fd < 0)
1222     {
1223       gpg_err_set_errno (EBADF);
1224       return TRACE_SYSRES (-1);
1225     }
1226
1227   LOCK (fd_table_lock);
1228   /* Check the size in the locked state because we may eventually add
1229    * code to change that size.  */
1230   if (fd >= fd_table_size || !fd_table[fd].used)
1231     {
1232       UNLOCK (fd_table_lock);
1233       gpg_err_set_errno (EBADF);
1234       return TRACE_SYSRES (-1);
1235     }
1236
1237   TRACE_LOG2 ("hdd=%p dupfrom=%d", fd_table[fd].hdd, fd_table[fd].dup_from);
1238
1239   if (fd_table[fd].reader)
1240     {
1241       any_reader_or_writer = 1;
1242       TRACE_LOG1 ("destroying reader %p", fd_table[fd].reader);
1243       destroy_reader (fd_table[fd].reader);
1244       fd_table[fd].reader = NULL;
1245     }
1246
1247   if (fd_table[fd].writer)
1248     {
1249       any_reader_or_writer = 1;
1250       TRACE_LOG1 ("destroying writer %p", fd_table[fd].writer);
1251       destroy_writer (fd_table[fd].writer);
1252       fd_table[fd].writer = NULL;
1253     }
1254
1255   /* FIXME: The handler may not use any fd fucntion becuase the table
1256    * is locked.  Can we avoid this?  */
1257   handler = fd_table[fd].notify.handler;
1258   value   = fd_table[fd].notify.value;
1259
1260   /* Release our reference to the handle descripor.  Note that if no
1261    * reader or writer threads were used this release will also take
1262    * care that the handle descriptor is closed
1263    * (i.e. CloseHandle(hdd->hd) is called).  */
1264   release_hddesc (fd_table[fd].hdd);
1265   fd_table[fd].hdd = NULL;
1266
1267   UNLOCK (fd_table_lock);
1268
1269   /* Run the notification callback.  */
1270   if (handler)
1271     handler (fd, value);
1272
1273   release_fd (fd);  /* FIXME: We should have a release_fd_locked () */
1274
1275   return TRACE_SYSRES (0);
1276 }
1277
1278
1279 /* Set a close notification callback which is called right after FD
1280  * has been closed but before its slot (ie. the FD number) is beeing
1281  * released.  Tha HANDLER may thus use the provided value of the FD
1282  * but it may not pass it to any I/O functions.  Note: Only the last
1283  * handler set for an FD is used.  */
1284 int
1285 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
1286                             void *value)
1287 {
1288   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
1289               "close_handler=%p/%p", handler, value);
1290
1291   LOCK (fd_table_lock);
1292   if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used)
1293     {
1294       UNLOCK (fd_table_lock);
1295       gpg_err_set_errno (EBADF);
1296       return TRACE_SYSRES (-1);;
1297     }
1298
1299   fd_table[fd].notify.handler = handler;
1300   fd_table[fd].notify.value = value;
1301   UNLOCK (fd_table_lock);
1302   return TRACE_SYSRES (0);
1303 }
1304
1305
1306 int
1307 _gpgme_io_set_nonblocking (int fd)
1308 {
1309   TRACE (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
1310   return 0;
1311 }
1312
1313
1314 static char *
1315 build_commandline (char **argv)
1316 {
1317   int i;
1318   int n = 0;
1319   char *buf;
1320   char *p;
1321
1322   /* We have to quote some things because under Windows the program
1323      parses the commandline and does some unquoting.  We enclose the
1324      whole argument in double-quotes, and escape literal double-quotes
1325      as well as backslashes with a backslash.  We end up with a
1326      trailing space at the end of the line, but that is harmless.  */
1327   for (i = 0; argv[i]; i++)
1328     {
1329       p = argv[i];
1330       /* The leading double-quote.  */
1331       n++;
1332       while (*p)
1333         {
1334           /* An extra one for each literal that must be escaped.  */
1335           if (*p == '\\' || *p == '"')
1336             n++;
1337           n++;
1338           p++;
1339         }
1340       /* The trailing double-quote and the delimiter.  */
1341       n += 2;
1342     }
1343   /* And a trailing zero.  */
1344   n++;
1345
1346   buf = p = malloc (n);
1347   if (!buf)
1348     return NULL;
1349   for (i = 0; argv[i]; i++)
1350     {
1351       char *argvp = argv[i];
1352
1353       *(p++) = '"';
1354       while (*argvp)
1355         {
1356           if (*argvp == '\\' || *argvp == '"')
1357             *(p++) = '\\';
1358           *(p++) = *(argvp++);
1359         }
1360       *(p++) = '"';
1361       *(p++) = ' ';
1362     }
1363   *(p++) = 0;
1364
1365   return buf;
1366 }
1367
1368
1369 int
1370 _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
1371                  struct spawn_fd_item_s *fd_list,
1372                  void (*atfork) (void *opaque, int reserved),
1373                  void *atforkvalue, pid_t *r_pid)
1374 {
1375   PROCESS_INFORMATION pi =
1376     {
1377       NULL,      /* returns process handle */
1378       0,         /* returns primary thread handle */
1379       0,         /* returns pid */
1380       0          /* returns tid */
1381     };
1382   int i;
1383
1384   SECURITY_ATTRIBUTES sec_attr;
1385   STARTUPINFOA si;
1386   int cr_flags = CREATE_DEFAULT_ERROR_MODE;
1387   char **args;
1388   char *arg_string;
1389   /* FIXME.  */
1390   int debug_me = 0;
1391   int tmp_fd;
1392   char *tmp_name;
1393   const char *spawnhelper;
1394
1395   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1396               "path=%s", path);
1397
1398   (void)atfork;
1399   (void)atforkvalue;
1400
1401   i = 0;
1402   while (argv[i])
1403     {
1404       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1405       i++;
1406     }
1407
1408   /* We do not inherit any handles by default, and just insert those
1409      handles we want the child to have afterwards.  But some handle
1410      values occur on the command line, and we need to move
1411      stdin/out/err to the right location.  So we use a wrapper program
1412      which gets the information from a temporary file.  */
1413   if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
1414     {
1415       TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
1416       return TRACE_SYSRES (-1);
1417     }
1418   TRACE_LOG1 ("tmp_name = %s", tmp_name);
1419
1420   args = calloc (2 + i + 1, sizeof (*args));
1421   args[0] = (char *) _gpgme_get_w32spawn_path ();
1422   args[1] = tmp_name;
1423   args[2] = (char *)path;
1424   memcpy (&args[3], &argv[1], i * sizeof (*args));
1425
1426   memset (&sec_attr, 0, sizeof sec_attr);
1427   sec_attr.nLength = sizeof sec_attr;
1428   sec_attr.bInheritHandle = FALSE;
1429
1430   arg_string = build_commandline (args);
1431   free (args);
1432   if (!arg_string)
1433     {
1434       close (tmp_fd);
1435       DeleteFileA (tmp_name);
1436       free (tmp_name);
1437       return TRACE_SYSRES (-1);
1438     }
1439
1440   memset (&si, 0, sizeof si);
1441   si.cb = sizeof (si);
1442   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1443   si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
1444   si.hStdInput = INVALID_HANDLE_VALUE;
1445   si.hStdOutput = INVALID_HANDLE_VALUE;
1446   si.hStdError = INVALID_HANDLE_VALUE;
1447
1448   cr_flags |= CREATE_SUSPENDED;
1449   if ((flags & IOSPAWN_FLAG_DETACHED))
1450     cr_flags |= DETACHED_PROCESS;
1451   cr_flags |= GetPriorityClass (GetCurrentProcess ());
1452   spawnhelper = _gpgme_get_w32spawn_path ();
1453   if (!spawnhelper)
1454     {
1455       /* This is a common mistake for new users of gpgme not to include
1456          gpgme-w32spawn.exe with their binary. So we want to make
1457          this transparent to developers. If users have somehow messed
1458          up their installation this should also be properly communicated
1459          as otherwise calls to gnupg will result in unsupported protocol
1460          errors that do not explain a lot. */
1461       char *msg;
1462       gpgrt_asprintf (&msg, "gpgme-w32spawn.exe was not found in the "
1463                             "detected installation directory of GpgME"
1464                             "\n\t\"%s\"\n\n"
1465                             "Crypto operations will not work.\n\n"
1466                             "If you see this it indicates a problem "
1467                             "with your installation.\n"
1468                             "Please report the problem to your "
1469                             "distributor of GpgME.\n\n"
1470                             "Developer's Note: The install dir can be "
1471                             "manually set with: gpgme_set_global_flag",
1472                             _gpgme_get_inst_dir ());
1473       MessageBoxA (NULL, msg, "GpgME not installed correctly", MB_OK);
1474       gpgrt_free (msg);
1475       gpg_err_set_errno (EIO);
1476       close (tmp_fd);
1477       DeleteFileA (tmp_name);
1478       free (tmp_name);
1479       return TRACE_SYSRES (-1);
1480     }
1481   if (!CreateProcessA (spawnhelper,
1482                        arg_string,
1483                        &sec_attr,     /* process security attributes */
1484                        &sec_attr,     /* thread security attributes */
1485                        FALSE,         /* inherit handles */
1486                        cr_flags,      /* creation flags */
1487                        NULL,          /* environment */
1488                        NULL,          /* use current drive/directory */
1489                        &si,           /* startup information */
1490                        &pi))          /* returns process information */
1491     {
1492       int lasterr = (int)GetLastError ();
1493       TRACE_LOG1 ("CreateProcess failed: ec=%d", lasterr);
1494       free (arg_string);
1495       close (tmp_fd);
1496       DeleteFileA (tmp_name);
1497       free (tmp_name);
1498
1499       /* FIXME: Should translate the error code.  */
1500       gpg_err_set_errno (EIO);
1501       return TRACE_SYSRES (-1);
1502     }
1503
1504   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
1505     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
1506
1507   /* Insert the inherited handles.  */
1508   LOCK (fd_table_lock);
1509   for (i = 0; fd_list[i].fd != -1; i++)
1510     {
1511       int fd = fd_list[i].fd;
1512       HANDLE ohd = INVALID_HANDLE_VALUE;
1513       HANDLE hd = INVALID_HANDLE_VALUE;
1514
1515       /* Make it inheritable for the wrapper process.  */
1516       if (fd >= 0 && fd < fd_table_size && fd_table[fd].used
1517           && fd_table[fd].hdd)
1518         ohd = fd_table[fd].hdd->hd;
1519
1520       if (!DuplicateHandle (GetCurrentProcess(), ohd,
1521                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
1522         {
1523           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
1524           TerminateProcess (pi.hProcess, 0);
1525           /* Just in case TerminateProcess didn't work, let the
1526              process fail on its own.  */
1527           ResumeThread (pi.hThread);
1528           close_handle (pi.hThread);
1529           close_handle (pi.hProcess);
1530
1531           close (tmp_fd);
1532           DeleteFileA (tmp_name);
1533           free (tmp_name);
1534
1535           /* FIXME: Should translate the error code.  */
1536           gpg_err_set_errno (EIO);
1537           UNLOCK (fd_table_lock);
1538           return TRACE_SYSRES (-1);
1539         }
1540       /* Return the child name of this handle.  */
1541       fd_list[i].peer_name = handle_to_fd (hd);
1542     }
1543
1544   /* Write the handle translation information to the temporary
1545      file.  */
1546   {
1547     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
1548        notation: "0xFEDCBA9876543210" with an extra white space after
1549        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
1550        for a time when a HANDLE is 64 bit.  */
1551 #define BUFFER_MAX 810
1552     char line[BUFFER_MAX + 1];
1553     int res;
1554     int written;
1555     size_t len;
1556
1557     if (flags)
1558       snprintf (line, BUFFER_MAX, "~%i \n", flags);
1559     else
1560       strcpy (line, "\n");
1561     for (i = 0; fd_list[i].fd != -1; i++)
1562       {
1563         /* Strip the newline.  */
1564         len = strlen (line) - 1;
1565
1566         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
1567         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
1568                   fd_list[i].fd, fd_list[i].dup_to,
1569                   fd_list[i].peer_name, fd_list[i].arg_loc);
1570         /* Rather safe than sorry.  */
1571         line[BUFFER_MAX - 1] = '\n';
1572         line[BUFFER_MAX] = '\0';
1573       }
1574     len = strlen (line);
1575     written = 0;
1576     do
1577       {
1578         res = write (tmp_fd, &line[written], len - written);
1579         if (res > 0)
1580           written += res;
1581       }
1582     while (res > 0 || (res < 0 && errno == EAGAIN));
1583   }
1584   close (tmp_fd);
1585   /* The temporary file is deleted by the gpgme-w32spawn process
1586      (hopefully).  */
1587
1588   free (tmp_name);
1589   free (arg_string);
1590
1591   UNLOCK (fd_table_lock);
1592
1593   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
1594               "dwProcessID=%d, dwThreadId=%d",
1595               pi.hProcess, pi.hThread,
1596               (int) pi.dwProcessId, (int) pi.dwThreadId);
1597
1598   if (r_pid)
1599     *r_pid = (pid_t)pi.dwProcessId;
1600
1601
1602   if (ResumeThread (pi.hThread) < 0)
1603     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
1604
1605   close_handle (pi.hThread);
1606
1607   TRACE_LOG1 ("process=%p", pi.hProcess);
1608
1609   /* We don't need to wait for the process.  */
1610   close_handle (pi.hProcess);
1611
1612   if (! (flags & IOSPAWN_FLAG_NOCLOSE))
1613     {
1614       for (i = 0; fd_list[i].fd != -1; i++)
1615         _gpgme_io_close (fd_list[i].fd);
1616     }
1617
1618   for (i = 0; fd_list[i].fd != -1; i++)
1619     if (fd_list[i].dup_to == -1)
1620       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
1621                   fd_list[i].peer_name);
1622     else
1623       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
1624                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
1625                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
1626
1627   return TRACE_SYSRES (0);
1628 }
1629
1630
1631 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
1632    nothing to select, > 0 = number of signaled fds.  */
1633 int
1634 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
1635 {
1636   HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1637   int waitidx[MAXIMUM_WAIT_OBJECTS];
1638   int code;
1639   int nwait;
1640   int i;
1641   int any;
1642   int count;
1643   void *dbg_help;
1644   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
1645               "nfds=%u, nonblock=%u", nfds, nonblock);
1646
1647 #if 0
1648  restart:
1649 #endif
1650   TRACE_SEQ (dbg_help, "select on [ ");
1651   any = 0;
1652   nwait = 0;
1653   count = 0;
1654   for (i=0; i < nfds; i++)
1655     {
1656       if (fds[i].fd == -1)
1657         continue;
1658       fds[i].signaled = 0;
1659       if (fds[i].for_read || fds[i].for_write)
1660         {
1661           if (fds[i].for_read)
1662             {
1663               /* FIXME: A find_reader_locked() along with separate
1664                * lock calls might be a better appaoched here.  */
1665               struct reader_context_s *ctx = find_reader (fds[i].fd);
1666
1667               if (!ctx)
1668                 TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
1669                             fds[i].fd);
1670               else
1671                 {
1672                   if (nwait >= DIM (waitbuf))
1673                     {
1674                       TRACE_END (dbg_help, "oops ]");
1675                       TRACE_LOG ("Too many objects for WFMO!");
1676                       /* FIXME: Should translate the error code.  */
1677                       gpg_err_set_errno (EIO);
1678                       return TRACE_SYSRES (-1);
1679                     }
1680                   waitidx[nwait] = i;
1681                   waitbuf[nwait++] = ctx->have_data_ev;
1682                 }
1683               TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
1684               any = 1;
1685             }
1686           else if (fds[i].for_write)
1687             {
1688               struct writer_context_s *ctx = find_writer (fds[i].fd);
1689
1690               if (!ctx)
1691                 TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
1692                             fds[i].fd);
1693               else
1694                 {
1695                   if (nwait >= DIM (waitbuf))
1696                     {
1697                       TRACE_END (dbg_help, "oops ]");
1698                       TRACE_LOG ("Too many objects for WFMO!");
1699                       /* FIXME: Should translate the error code.  */
1700                       gpg_err_set_errno (EIO);
1701                       return TRACE_SYSRES (-1);
1702                     }
1703                   waitidx[nwait] = i;
1704                   waitbuf[nwait++] = ctx->is_empty;
1705                 }
1706               TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
1707               any = 1;
1708             }
1709         }
1710     }
1711   TRACE_END (dbg_help, "]");
1712   if (!any)
1713     return TRACE_SYSRES (0);
1714
1715   code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
1716   if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
1717     {
1718       /* The WFMO is a really silly function: It does return either
1719          the index of the signaled object or if 2 objects have been
1720          signalled at the same time, the index of the object with the
1721          lowest object is returned - so and how do we find out how
1722          many objects have been signaled?.  The only solution I can
1723          imagine is to test each object starting with the returned
1724          index individually - how dull.  */
1725       any = 0;
1726       for (i = code - WAIT_OBJECT_0; i < nwait; i++)
1727         {
1728           if (wait_for_single_object (waitbuf[i], 0) == WAIT_OBJECT_0)
1729             {
1730               assert (waitidx[i] >=0 && waitidx[i] < nfds);
1731               fds[waitidx[i]].signaled = 1;
1732               any = 1;
1733               count++;
1734             }
1735         }
1736       if (!any)
1737         {
1738           TRACE_LOG ("no signaled objects found after WFMO");
1739           count = -1;
1740         }
1741     }
1742   else if (code == WAIT_TIMEOUT)
1743     TRACE_LOG ("WFMO timed out");
1744   else if (code == WAIT_FAILED)
1745     {
1746       int le = (int) GetLastError ();
1747 #if 0
1748       if (le == ERROR_INVALID_HANDLE)
1749         {
1750           int k;
1751           int j = handle_to_fd (waitbuf[i]);
1752
1753           TRACE_LOG1 ("WFMO invalid handle %d removed", j);
1754           for (k = 0 ; k < nfds; k++)
1755             {
1756               if (fds[k].fd == j)
1757                 {
1758                   fds[k].for_read = fds[k].for_write = 0;
1759                   goto restart;
1760                 }
1761             }
1762           TRACE_LOG (" oops, or not???");
1763         }
1764 #endif
1765       TRACE_LOG1 ("WFMO failed: %d", le);
1766       count = -1;
1767     }
1768   else
1769     {
1770       TRACE_LOG1 ("WFMO returned %d", code);
1771       count = -1;
1772     }
1773
1774   if (count > 0)
1775     {
1776       TRACE_SEQ (dbg_help, "select OK [ ");
1777       for (i = 0; i < nfds; i++)
1778         {
1779           if (fds[i].fd == -1)
1780             continue;
1781           if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
1782             TRACE_ADD2 (dbg_help, "%c0x%x ",
1783                         fds[i].for_read ? 'r' : 'w', fds[i].fd);
1784         }
1785       TRACE_END (dbg_help, "]");
1786     }
1787
1788   if (count < 0)
1789     {
1790       /* FIXME: Should determine a proper error code.  */
1791       gpg_err_set_errno (EIO);
1792     }
1793
1794   return TRACE_SYSRES (count);
1795 }
1796
1797
1798 void
1799 _gpgme_io_subsystem_init (void)
1800 {
1801   /* Nothing to do.  */
1802 }
1803
1804
1805 /* Write the printable version of FD to BUFFER which has an allocated
1806  * length of BUFLEN.  The printable version is the representation on
1807  * the command line that the child process expects.  Note that this
1808  * works closely together with the gpgme-32spawn wrapper process which
1809  * translates these command line args to the real handles. */
1810 int
1811 _gpgme_io_fd2str (char *buffer, int buflen, int fd)
1812 {
1813   return snprintf (buffer, buflen, "%d", fd);
1814 }
1815
1816
1817 int
1818 _gpgme_io_dup (int fd)
1819 {
1820   int newfd;
1821   struct reader_context_s *rd_ctx;
1822   struct writer_context_s *wt_ctx;
1823   int want_reader, want_writer;
1824
1825   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
1826
1827   LOCK (fd_table_lock);
1828   if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used)
1829     {
1830       UNLOCK (fd_table_lock);
1831       gpg_err_set_errno (EBADF);
1832       return TRACE_SYSRES (-1);
1833     }
1834
1835   newfd = new_fd();
1836   if (newfd == -1)
1837     {
1838       UNLOCK (fd_table_lock);
1839       gpg_err_set_errno (EMFILE);
1840       return TRACE_SYSRES (-1);
1841     }
1842
1843   fd_table[newfd].hdd = ref_hddesc (fd_table[fd].hdd);
1844   fd_table[newfd].dup_from = fd;
1845   want_reader = fd_table[fd].want_reader;
1846   want_writer = fd_table[fd].want_writer;
1847
1848   UNLOCK (fd_table_lock);
1849
1850   rd_ctx = want_reader? find_reader (fd) : NULL;
1851   if (rd_ctx)
1852     {
1853       /* NEWFD initializes a freshly allocated slot and does not need
1854        * to be locked.  */
1855       LOCK (rd_ctx->mutex);
1856       rd_ctx->refcount++;
1857       UNLOCK (rd_ctx->mutex);
1858       fd_table[newfd].reader = rd_ctx;
1859     }
1860
1861   wt_ctx = want_writer? find_writer (fd) : NULL;
1862   if (wt_ctx)
1863     {
1864       LOCK (wt_ctx->mutex);
1865       wt_ctx->refcount++;
1866       UNLOCK (wt_ctx->mutex);
1867       fd_table[newfd].writer = wt_ctx;
1868     }
1869
1870   return TRACE_SYSRES (newfd);
1871 }
1872
1873 \f
1874 /* The following interface is only useful for GPGME Glib and Qt.  */
1875
1876 /* Compatibility interface, obsolete.  */
1877 void *
1878 gpgme_get_giochannel (int fd)
1879 {
1880   (void)fd;
1881   return NULL;
1882 }
1883
1884
1885 /* Look up the giochannel or qiodevice for file descriptor FD.  */
1886 void *
1887 gpgme_get_fdptr (int fd)
1888 {
1889   (void)fd;
1890   return NULL;
1891 }
1892
1893 \f
1894 static int
1895 wsa2errno (int err)
1896 {
1897   switch (err)
1898     {
1899     case WSAENOTSOCK:
1900       return EINVAL;
1901     case WSAEWOULDBLOCK:
1902       return EAGAIN;
1903     case ERROR_BROKEN_PIPE:
1904       return EPIPE;
1905     case WSANOTINITIALISED:
1906       return ENOSYS;
1907     default:
1908       return EIO;
1909     }
1910 }
1911
1912
1913 int
1914 _gpgme_io_socket (int domain, int type, int proto)
1915 {
1916   int res;
1917   int fd;
1918   hddesc_t hdd;
1919
1920   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
1921               "type=%i, protp=%i", type, proto);
1922
1923   fd = new_fd();
1924   if (fd == -1)
1925     return TRACE_SYSRES (-1);
1926   hdd = new_hddesc ();
1927   if (!hdd)
1928     {
1929       UNLOCK (fd_table_lock);
1930       release_fd (fd);
1931       gpg_err_set_errno (ENOMEM);
1932       return TRACE_SYSRES (-1);
1933     }
1934
1935   res = socket (domain, type, proto);
1936   if (res == INVALID_SOCKET)
1937     {
1938       release_fd (fd);
1939       gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
1940       return TRACE_SYSRES (-1);
1941     }
1942   ref_hddesc (hdd)->sock = res;
1943   fd_table[fd].hdd = hdd;
1944   fd_table[fd].want_reader = 1;
1945   fd_table[fd].want_writer = 1;
1946
1947   TRACE_SUC3 ("hdd=%p, socket=0x%x (0x%x)", hdd, fd, hdd->sock);
1948
1949   return fd;
1950 }
1951
1952
1953 int
1954 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
1955 {
1956   int res;
1957   int sock;
1958
1959   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
1960               "addr=%p, addrlen=%i", addr, addrlen);
1961
1962   LOCK (fd_table_lock);
1963   if (fd < 0 || fd >= fd_table_size || !fd_table[fd].used || !fd_table[fd].hdd)
1964     {
1965       gpg_err_set_errno (EBADF);
1966       UNLOCK (fd_table_lock);
1967       return TRACE_SYSRES (-1);
1968     }
1969   sock = fd_table[fd].hdd->sock;
1970   UNLOCK (fd_table_lock);
1971
1972   res = connect (sock, addr, addrlen);
1973   if (res)
1974     {
1975       gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
1976       return TRACE_SYSRES (-1);
1977     }
1978
1979   return TRACE_SUC ();
1980 }