2010-05-06 Marcus Brinkmann <marcus@g10code.de>
[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, 2002, 2003, 2004, 2007, 2010 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, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
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 <signal.h>
31 #include <fcntl.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <windows.h>
35 #include <io.h>
36
37 #include "util.h"
38 #include "sema.h"
39 #include "priv-io.h"
40 #include "debug.h"
41
42
43 /* We assume that a HANDLE can be represented by an int which should
44    be true for all i386 systems (HANDLE is defined as void *) and
45    these are the only systems for which Windows is available.  Further
46    we assume that -1 denotes an invalid handle.  */
47
48 #define fd_to_handle(a)  ((HANDLE)(a))
49 #define handle_to_fd(a)  ((int)(a))
50 #define pid_to_handle(a) ((HANDLE)(a))
51 #define handle_to_pid(a) ((int)(a))
52 #define handle_to_socket(a)  ((unsigned int)(a))
53
54 #define READBUF_SIZE 4096
55 #define WRITEBUF_SIZE 4096
56 #define PIPEBUF_SIZE  4096
57 #define MAX_READERS 40
58 #define MAX_WRITERS 40
59
60 static struct
61 {
62   int inuse;
63   int fd;
64   _gpgme_close_notify_handler_t handler;
65   void *value;
66 } notify_table[256];
67 DEFINE_STATIC_LOCK (notify_table_lock);
68
69
70 struct reader_context_s
71 {
72   HANDLE file_hd;
73   HANDLE thread_hd;     
74   int refcount;
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   HANDLE stopped;
89   size_t readpos, writepos;
90   char buffer[READBUF_SIZE];
91 };
92
93
94 static struct
95 {
96   volatile int used;
97   int fd;
98   struct reader_context_s *context;
99 } reader_table[MAX_READERS];
100 static int reader_table_size= MAX_READERS;
101 DEFINE_STATIC_LOCK (reader_table_lock);
102
103
104 struct writer_context_s
105 {
106   HANDLE file_hd;
107   HANDLE thread_hd;     
108   int refcount;
109
110   DECLARE_LOCK (mutex);
111   
112   int stop_me;
113   int error;
114   int error_code;
115
116   /* This is manually reset.  */
117   HANDLE have_data;
118   HANDLE is_empty;
119   HANDLE stopped;
120   size_t nbytes; 
121   char buffer[WRITEBUF_SIZE];
122 };
123
124
125 static struct
126 {
127   volatile int used;
128   int fd;
129   struct writer_context_s *context;
130 } writer_table[MAX_WRITERS];
131 static int writer_table_size= MAX_WRITERS;
132 DEFINE_STATIC_LOCK (writer_table_lock);
133
134
135 static int
136 get_desired_thread_priority (void)
137 {
138   int value;
139
140   if (!_gpgme_get_conf_int ("IOThreadPriority", &value))
141     {
142       value = THREAD_PRIORITY_HIGHEST;
143       TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
144               "%d (default)", value);
145     }
146   else
147     {
148       TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
149               "%d (configured)", value);
150     }
151   return value;
152 }
153
154
155 static HANDLE
156 set_synchronize (HANDLE hd)
157 {
158   HANDLE new_hd;
159
160   /* For NT we have to set the sync flag.  It seems that the only way
161      to do it is by duplicating the handle.  Tsss...  */
162   if (!DuplicateHandle (GetCurrentProcess (), hd,
163                         GetCurrentProcess (), &new_hd,
164                         EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0))
165     {
166       TRACE1 (DEBUG_SYSIO, "gpgme:set_synchronize", hd,
167               "DuplicateHandle failed: ec=%d", (int) GetLastError ());
168       /* FIXME: Should translate the error code.  */
169       gpg_err_set_errno (EIO);
170       return INVALID_HANDLE_VALUE;
171     }
172
173   CloseHandle (hd);
174   return new_hd;
175 }
176
177
178 /* Return true if HD refers to a socket.  */
179 static int
180 is_socket (HANDLE hd)
181 {
182   /* We need to figure out whether we are working on a socket or on a
183      handle.  A trivial way would be to check for the return code of
184      recv and see if it is WSAENOTSOCK.  However the recv may block
185      after the server process died and thus the destroy_reader will
186      hang.  Another option is to use getsockopt to test whether it is
187      a socket.  The bug here is that once a socket with a certain
188      values has been opened, closed and later a CreatePipe returned
189      the same value (i.e. handle), getsockopt still believes it is a
190      socket.  What we do now is to use a combination of GetFileType
191      and GetNamedPipeInfo.  The specs say that the latter may be used
192      on anonymous pipes as well.  Note that there are claims that
193      since winsocket version 2 ReadFile may be used on a socket but
194      only if it is supported by the service provider.  Tests on a
195      stock XP using a local TCP socket show that it does not work.  */
196   DWORD dummyflags, dummyoutsize, dummyinsize, dummyinst;
197   if (GetFileType (hd) == FILE_TYPE_PIPE
198       && !GetNamedPipeInfo (hd, &dummyflags, &dummyoutsize,
199                             &dummyinsize, &dummyinst))
200     return 1; /* Function failed; thus we assume it is a socket.  */
201   else
202     return 0; /* Success; this is not a socket.  */
203 }
204
205
206 static DWORD CALLBACK 
207 reader (void *arg)
208 {
209   struct reader_context_s *ctx = arg;
210   int nbytes;
211   DWORD nread;
212   int sock;
213   TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
214               "thread=%p", ctx->thread_hd);
215
216   sock = is_socket (ctx->file_hd);
217
218   for (;;)
219     {
220       LOCK (ctx->mutex);
221       /* Leave a 1 byte gap so that we can see whether it is empty or
222          full.  */
223       if ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
224         { 
225           /* Wait for space.  */
226           if (!ResetEvent (ctx->have_space_ev))
227             TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
228           UNLOCK (ctx->mutex);
229           TRACE_LOG ("waiting for space");
230           WaitForSingleObject (ctx->have_space_ev, INFINITE);
231           TRACE_LOG ("got space");
232           LOCK (ctx->mutex);
233         }
234       if (ctx->stop_me)
235         {
236           UNLOCK (ctx->mutex);
237           break;
238         }
239       nbytes = (ctx->readpos + READBUF_SIZE
240                 - ctx->writepos - 1) % READBUF_SIZE;
241       if (nbytes > READBUF_SIZE - ctx->writepos)
242         nbytes = READBUF_SIZE - ctx->writepos;
243       UNLOCK (ctx->mutex);
244       
245       TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes);
246
247       if (sock)
248         {
249           int n;
250
251           n = recv (handle_to_socket (ctx->file_hd),
252                     ctx->buffer + ctx->writepos, nbytes, 0);
253           if (n < 0)
254             {
255               ctx->error_code = (int) WSAGetLastError ();
256               if (ctx->error_code == ERROR_BROKEN_PIPE)
257                 {
258                   ctx->eof = 1;
259                   TRACE_LOG ("got EOF (broken connection)");
260                 }
261               else
262                 {
263                   ctx->error = 1;
264                   TRACE_LOG1 ("recv error: ec=%d", ctx->error_code);
265                 }
266               break;
267             }
268           nread = n;
269         }
270       else
271         {
272           if (!ReadFile (ctx->file_hd,
273                          ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
274             {
275               ctx->error_code = (int) GetLastError ();
276               if (ctx->error_code == ERROR_BROKEN_PIPE)
277                 {
278                   ctx->eof = 1;
279                   TRACE_LOG ("got EOF (broken pipe)");
280                 }
281               else
282                 {
283                   ctx->error = 1;
284                   TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
285                 }
286               break;
287             }
288         }
289       if (!nread)
290         {
291           ctx->eof = 1;
292           TRACE_LOG ("got eof");
293           break;
294         }
295       TRACE_LOG1 ("got %u bytes", nread);
296       
297       LOCK (ctx->mutex);
298       if (ctx->stop_me)
299         {
300           UNLOCK (ctx->mutex);
301           break;
302         }
303       ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
304       if (!SetEvent (ctx->have_data_ev))
305         TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
306                     (int) GetLastError ());
307       UNLOCK (ctx->mutex);
308     }
309   /* Indicate that we have an error or EOF.  */
310   if (!SetEvent (ctx->have_data_ev))
311         TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
312                     (int) GetLastError ());
313   SetEvent (ctx->stopped);
314   
315   return TRACE_SUC ();
316 }
317
318
319 static struct reader_context_s *
320 create_reader (HANDLE fd)
321 {
322   struct reader_context_s *ctx;
323   SECURITY_ATTRIBUTES sec_attr;
324   DWORD tid;
325
326   TRACE_BEG (DEBUG_SYSIO, "gpgme:create_reader", fd);
327
328   memset (&sec_attr, 0, sizeof sec_attr);
329   sec_attr.nLength = sizeof sec_attr;
330   sec_attr.bInheritHandle = FALSE;
331   
332   ctx = calloc (1, sizeof *ctx);
333   if (!ctx)
334     {
335       TRACE_SYSERR (errno);
336       return NULL;
337     }
338
339   ctx->file_hd = fd;
340   ctx->refcount = 1;
341   ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
342   if (ctx->have_data_ev)
343     ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
344   if (ctx->have_space_ev)
345     ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
346   if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->stopped)
347     {
348       TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
349       if (ctx->have_data_ev)
350         CloseHandle (ctx->have_data_ev);
351       if (ctx->have_space_ev)
352         CloseHandle (ctx->have_space_ev);
353       if (ctx->stopped)
354         CloseHandle (ctx->stopped);
355       free (ctx);
356       /* FIXME: Translate the error code.  */
357       TRACE_SYSERR (EIO);
358       return NULL;
359     }
360
361   ctx->have_data_ev = set_synchronize (ctx->have_data_ev);
362   INIT_LOCK (ctx->mutex);
363
364   ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid);
365   if (!ctx->thread_hd)
366     {
367       TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
368       DESTROY_LOCK (ctx->mutex);
369       if (ctx->have_data_ev)
370         CloseHandle (ctx->have_data_ev);
371       if (ctx->have_space_ev)
372         CloseHandle (ctx->have_space_ev);
373       if (ctx->stopped)
374         CloseHandle (ctx->stopped);
375       free (ctx);
376       TRACE_SYSERR (EIO);
377       return NULL;
378     }    
379   else
380     {
381       /* We set the priority of the thread higher because we know that
382          it only runs for a short time.  This greatly helps to
383          increase the performance of the I/O.  */
384       SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
385     }
386
387   TRACE_SUC ();
388   return ctx;
389 }
390
391
392 static void
393 destroy_reader (struct reader_context_s *ctx)
394 {
395   LOCK (ctx->mutex);
396   ctx->refcount--;
397   if (ctx->refcount != 0)
398     {
399       UNLOCK (ctx->mutex);
400       return;
401     }
402   ctx->stop_me = 1;
403   if (ctx->have_space_ev) 
404     SetEvent (ctx->have_space_ev);
405   UNLOCK (ctx->mutex);
406
407   TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
408           "waiting for termination of thread %p", ctx->thread_hd);
409   WaitForSingleObject (ctx->stopped, INFINITE);
410   TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
411           "thread %p has terminated", ctx->thread_hd);
412     
413   if (ctx->stopped)
414     CloseHandle (ctx->stopped);
415   if (ctx->have_data_ev)
416     CloseHandle (ctx->have_data_ev);
417   if (ctx->have_space_ev)
418     CloseHandle (ctx->have_space_ev);
419   CloseHandle (ctx->thread_hd);
420   DESTROY_LOCK (ctx->mutex);
421   free (ctx);
422 }
423
424
425 /* Find a reader context or create a new one.  Note that the reader
426    context will last until a _gpgme_io_close.  */
427 static struct reader_context_s *
428 find_reader (int fd, int start_it)
429 {
430   struct reader_context_s *rd = NULL;
431   int i;
432
433   LOCK (reader_table_lock);
434   for (i = 0; i < reader_table_size; i++)
435     if (reader_table[i].used && reader_table[i].fd == fd)
436       rd = reader_table[i].context;
437
438   if (rd || !start_it)
439     {
440       UNLOCK (reader_table_lock);
441       return rd;
442     }
443
444   for (i = 0; i < reader_table_size; i++)
445     if (!reader_table[i].used)
446       break;
447
448   if (i != reader_table_size)
449     {
450       rd = create_reader (fd_to_handle (fd));
451       if (rd)
452         {
453           reader_table[i].fd = fd;
454           reader_table[i].context = rd;
455           reader_table[i].used = 1;
456         }
457     }
458
459   UNLOCK (reader_table_lock);
460   return rd;
461 }
462
463
464 static void
465 kill_reader (int fd)
466 {
467   int i;
468
469   LOCK (reader_table_lock);
470   for (i = 0; i < reader_table_size; i++)
471     {
472       if (reader_table[i].used && reader_table[i].fd == fd)
473         {
474           destroy_reader (reader_table[i].context);
475           reader_table[i].context = NULL;
476           reader_table[i].used = 0;
477           break;
478         }
479     }
480   UNLOCK (reader_table_lock);
481 }
482
483
484 int
485 _gpgme_io_read (int fd, void *buffer, size_t count)
486 {
487   int nread;
488   struct reader_context_s *ctx;
489   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
490               "buffer=%p, count=%u", buffer, count);
491   
492   ctx = find_reader (fd, 1);
493   if (!ctx)
494     {
495       gpg_err_set_errno (EBADF);
496       return TRACE_SYSRES (-1);
497     }
498   if (ctx->eof_shortcut)
499     return TRACE_SYSRES (0);
500
501   LOCK (ctx->mutex);
502   if (ctx->readpos == ctx->writepos && !ctx->error)
503     {
504       /* No data available.  */
505       UNLOCK (ctx->mutex);
506       TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd);
507       WaitForSingleObject (ctx->have_data_ev, INFINITE);
508       TRACE_LOG1 ("data from thread %p available", ctx->thread_hd);
509       LOCK (ctx->mutex);
510     }
511   
512   if (ctx->readpos == ctx->writepos || ctx->error)
513     {
514       UNLOCK (ctx->mutex);
515       ctx->eof_shortcut = 1;
516       if (ctx->eof)
517         return TRACE_SYSRES (0);
518       if (!ctx->error)
519         {
520           TRACE_LOG ("EOF but ctx->eof flag not set");
521           return 0;
522         }
523       gpg_err_set_errno (ctx->error_code);
524       return TRACE_SYSRES (-1);
525     }
526   
527   nread = ctx->readpos < ctx->writepos
528     ? ctx->writepos - ctx->readpos
529     : READBUF_SIZE - ctx->readpos;
530   if (nread > count)
531     nread = count;
532   memcpy (buffer, ctx->buffer + ctx->readpos, nread);
533   ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
534   if (ctx->readpos == ctx->writepos && !ctx->eof)
535     {
536       if (!ResetEvent (ctx->have_data_ev))
537         {
538           TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
539           UNLOCK (ctx->mutex);
540           /* FIXME: Should translate the error code.  */
541           gpg_err_set_errno (EIO);
542           return TRACE_SYSRES (-1);
543         }
544     }
545   if (!SetEvent (ctx->have_space_ev))
546     {
547       TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d",
548                   ctx->have_space_ev, (int) GetLastError ());
549       UNLOCK (ctx->mutex);
550       /* FIXME: Should translate the error code.  */
551       gpg_err_set_errno (EIO);
552       return TRACE_SYSRES (-1);
553     }
554   UNLOCK (ctx->mutex);
555   
556   TRACE_LOGBUF (buffer, nread);
557   return TRACE_SYSRES (nread);
558 }
559
560
561 /* The writer does use a simple buffering strategy so that we are
562    informed about write errors as soon as possible (i. e. with the the
563    next call to the write function.  */
564 static DWORD CALLBACK 
565 writer (void *arg)
566 {
567   struct writer_context_s *ctx = arg;
568   DWORD nwritten;
569   int sock;
570   TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
571               "thread=%p", ctx->thread_hd);
572
573   sock = is_socket (ctx->file_hd);
574
575   for (;;)
576     {
577       LOCK (ctx->mutex);
578       if (ctx->stop_me)
579         {
580           UNLOCK (ctx->mutex);
581           break;
582         }
583       if (!ctx->nbytes)
584         { 
585           if (!SetEvent (ctx->is_empty))
586             TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
587           if (!ResetEvent (ctx->have_data))
588             TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
589           UNLOCK (ctx->mutex);
590           TRACE_LOG ("idle");
591           WaitForSingleObject (ctx->have_data, INFINITE);
592           TRACE_LOG ("got data to send");
593           LOCK (ctx->mutex);
594         }
595       if (ctx->stop_me)
596         {
597           UNLOCK (ctx->mutex);
598           break;
599         }
600       UNLOCK (ctx->mutex);
601       
602       TRACE_LOG2 ("%s %d bytes", sock?"sending":"writing", ctx->nbytes);
603
604       /* Note that CTX->nbytes is not zero at this point, because
605          _gpgme_io_write always writes at least 1 byte before waking
606          us up, unless CTX->stop_me is true, which we catch above.  */
607       if (sock)
608         {
609           /* We need to try send first because a socket handle can't
610              be used with WriteFile.  */
611           int n;
612           
613           n = send (handle_to_socket (ctx->file_hd),
614                     ctx->buffer, ctx->nbytes, 0);
615           if (n < 0)
616             {
617               ctx->error_code = (int) WSAGetLastError ();
618               ctx->error = 1;
619               TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
620               break;
621             }
622           nwritten = n;
623         }
624       else
625         {
626           if (!WriteFile (ctx->file_hd, ctx->buffer,
627                           ctx->nbytes, &nwritten, NULL))
628             {
629               ctx->error_code = (int) GetLastError ();
630               ctx->error = 1;
631               TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
632               break;
633             }
634         }
635       TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
636       
637       LOCK (ctx->mutex);
638       ctx->nbytes -= nwritten;
639       UNLOCK (ctx->mutex);
640     }
641   /* Indicate that we have an error.  */
642   if (!SetEvent (ctx->is_empty))
643     TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
644   SetEvent (ctx->stopped);
645
646   return TRACE_SUC ();
647 }
648
649
650 static struct writer_context_s *
651 create_writer (HANDLE fd)
652 {
653   struct writer_context_s *ctx;
654   SECURITY_ATTRIBUTES sec_attr;
655   DWORD tid;
656
657   TRACE_BEG (DEBUG_SYSIO, "gpgme:create_writer", fd);
658
659   memset (&sec_attr, 0, sizeof sec_attr);
660   sec_attr.nLength = sizeof sec_attr;
661   sec_attr.bInheritHandle = FALSE;
662
663   ctx = calloc (1, sizeof *ctx);
664   if (!ctx)
665     {
666       TRACE_SYSERR (errno);
667       return NULL;
668     }
669   
670   ctx->file_hd = fd;
671   ctx->refcount = 1;
672   ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
673   if (ctx->have_data)
674     ctx->is_empty  = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
675   if (ctx->is_empty)
676     ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
677   if (!ctx->have_data || !ctx->is_empty || !ctx->stopped)
678     {
679       TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
680       if (ctx->have_data)
681         CloseHandle (ctx->have_data);
682       if (ctx->is_empty)
683         CloseHandle (ctx->is_empty);
684       if (ctx->stopped)
685         CloseHandle (ctx->stopped);
686       free (ctx);
687       /* FIXME: Translate the error code.  */
688       TRACE_SYSERR (EIO);
689       return NULL;
690     }
691
692   ctx->is_empty = set_synchronize (ctx->is_empty);
693   INIT_LOCK (ctx->mutex);
694
695   ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
696   if (!ctx->thread_hd)
697     {
698       TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
699       DESTROY_LOCK (ctx->mutex);
700       if (ctx->have_data)
701         CloseHandle (ctx->have_data);
702       if (ctx->is_empty)
703         CloseHandle (ctx->is_empty);
704       if (ctx->stopped)
705         CloseHandle (ctx->stopped);
706       free (ctx);
707       TRACE_SYSERR (EIO);
708       return NULL;
709     }    
710   else
711     {
712       /* We set the priority of the thread higher because we know
713          that it only runs for a short time.  This greatly helps to
714          increase the performance of the I/O.  */
715       SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
716     }
717
718   TRACE_SUC ();
719   return ctx;
720 }
721
722 static void
723 destroy_writer (struct writer_context_s *ctx)
724 {
725   LOCK (ctx->mutex);
726   ctx->refcount--;
727   if (ctx->refcount != 0)
728     {
729       UNLOCK (ctx->mutex);
730       return;
731     }
732   ctx->stop_me = 1;
733   if (ctx->have_data) 
734     SetEvent (ctx->have_data);
735   UNLOCK (ctx->mutex);
736   
737   TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
738           "waiting for termination of thread %p", ctx->thread_hd);
739   WaitForSingleObject (ctx->stopped, INFINITE);
740   TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
741           "thread %p has terminated", ctx->thread_hd);
742   
743   if (ctx->stopped)
744     CloseHandle (ctx->stopped);
745   if (ctx->have_data)
746     CloseHandle (ctx->have_data);
747   if (ctx->is_empty)
748     CloseHandle (ctx->is_empty);
749   CloseHandle (ctx->thread_hd);
750   DESTROY_LOCK (ctx->mutex);
751   free (ctx);
752 }
753
754
755 /* Find a writer context or create a new one.  Note that the writer
756    context will last until a _gpgme_io_close.  */
757 static struct writer_context_s *
758 find_writer (int fd, int start_it)
759 {
760   struct writer_context_s *wt = NULL;
761   int i;
762
763   LOCK (writer_table_lock);
764   for (i = 0; i < writer_table_size; i++)
765     if (writer_table[i].used && writer_table[i].fd == fd)
766       wt = writer_table[i].context;
767
768   if (wt || !start_it)
769     {
770       UNLOCK (writer_table_lock);
771       return wt;
772     }
773
774   for (i = 0; i < writer_table_size; i++)
775     if (!writer_table[i].used)
776       break;
777
778   if (i != writer_table_size)
779     {
780       wt = create_writer (fd_to_handle (fd));
781       if (wt)
782         {
783           writer_table[i].fd = fd;
784           writer_table[i].context = wt; 
785           writer_table[i].used = 1;
786         }
787     }
788
789   UNLOCK (writer_table_lock);
790   return wt;
791 }
792
793
794 static void
795 kill_writer (int fd)
796 {
797   int i;
798
799   LOCK (writer_table_lock);
800   for (i = 0; i < writer_table_size; i++)
801     {
802       if (writer_table[i].used && writer_table[i].fd == fd)
803         {
804           destroy_writer (writer_table[i].context);
805           writer_table[i].context = NULL;
806           writer_table[i].used = 0;
807           break;
808         }
809     }
810   UNLOCK (writer_table_lock);
811 }
812
813
814 int
815 _gpgme_io_write (int fd, const void *buffer, size_t count)
816 {
817   struct writer_context_s *ctx;
818   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
819               "buffer=%p, count=%u", buffer, count);
820   TRACE_LOGBUF (buffer, count);
821
822   if (count == 0)
823     return TRACE_SYSRES (0);
824
825   ctx = find_writer (fd, 0);
826   if (!ctx)
827     return TRACE_SYSRES (-1);
828
829   LOCK (ctx->mutex);
830   if (!ctx->error && ctx->nbytes)
831     {
832       /* Bytes are pending for send.  */
833
834       /* Reset the is_empty event.  Better safe than sorry.  */
835       if (!ResetEvent (ctx->is_empty))
836         {
837           TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
838           UNLOCK (ctx->mutex);
839           /* FIXME: Should translate the error code.  */
840           gpg_err_set_errno (EIO);
841           return TRACE_SYSRES (-1);
842         }
843       UNLOCK (ctx->mutex);
844       TRACE_LOG1 ("waiting for empty buffer in thread %p", ctx->thread_hd);
845       WaitForSingleObject (ctx->is_empty, INFINITE);
846       TRACE_LOG1 ("thread %p buffer is empty", ctx->thread_hd);
847       LOCK (ctx->mutex);
848     }
849
850   if (ctx->error)
851     {
852       UNLOCK (ctx->mutex);
853       if (ctx->error_code == ERROR_NO_DATA)
854         gpg_err_set_errno (EPIPE);
855       else
856         gpg_err_set_errno (EIO);
857       return TRACE_SYSRES (-1);
858     }
859
860   /* If no error occured, the number of bytes in the buffer must be
861      zero.  */
862   assert (!ctx->nbytes);
863
864   if (count > WRITEBUF_SIZE)
865     count = WRITEBUF_SIZE;
866   memcpy (ctx->buffer, buffer, count);
867   ctx->nbytes = count;
868
869   /* We have to reset the is_empty event early, because it is also
870      used by the select() implementation to probe the channel.  */
871   if (!ResetEvent (ctx->is_empty))
872     {
873       TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
874       UNLOCK (ctx->mutex);
875       /* FIXME: Should translate the error code.  */
876       gpg_err_set_errno (EIO);
877       return TRACE_SYSRES (-1);
878     }
879   if (!SetEvent (ctx->have_data))
880     {
881       TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
882       UNLOCK (ctx->mutex);
883       /* FIXME: Should translate the error code.  */
884       gpg_err_set_errno (EIO);
885       return TRACE_SYSRES (-1);
886     }
887   UNLOCK (ctx->mutex);
888
889   return TRACE_SYSRES ((int) count);
890 }
891
892
893 int
894 _gpgme_io_pipe (int filedes[2], int inherit_idx)
895 {
896   HANDLE rh;
897   HANDLE wh;
898   SECURITY_ATTRIBUTES sec_attr;
899   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
900               "inherit_idx=%i (GPGME uses it for %s)",
901               inherit_idx, inherit_idx ? "reading" : "writing");
902
903   memset (&sec_attr, 0, sizeof (sec_attr));
904   sec_attr.nLength = sizeof (sec_attr);
905   sec_attr.bInheritHandle = FALSE;
906   
907   if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
908     {
909       TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
910       /* FIXME: Should translate the error code.  */
911       gpg_err_set_errno (EIO);
912       return TRACE_SYSRES (-1);
913     }
914
915   /* Make one end inheritable.  */
916   if (inherit_idx == 0)
917     {
918       struct writer_context_s *ctx;
919       HANDLE hd;
920       if (!DuplicateHandle (GetCurrentProcess(), rh,
921                             GetCurrentProcess(), &hd, 0,
922                             TRUE, DUPLICATE_SAME_ACCESS))
923         {
924           TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
925                       (int) GetLastError ());
926           CloseHandle (rh);
927           CloseHandle (wh);
928           /* FIXME: Should translate the error code.  */
929           gpg_err_set_errno (EIO);
930           return TRACE_SYSRES (-1);
931         }
932       CloseHandle (rh);
933       rh = hd;
934
935       ctx = find_writer (handle_to_fd (wh), 0);
936       assert (ctx == NULL);
937       ctx = find_writer (handle_to_fd (wh), 1);
938       if (!ctx)
939         {
940           CloseHandle (rh);
941           CloseHandle (wh);
942           /* FIXME: Should translate the error code.  */
943           gpg_err_set_errno (EIO);
944           return TRACE_SYSRES (-1);
945         }
946     }
947   else if (inherit_idx == 1)
948     {
949       struct reader_context_s *ctx;
950       HANDLE hd;
951       if (!DuplicateHandle( GetCurrentProcess(), wh,
952                             GetCurrentProcess(), &hd, 0,
953                             TRUE, DUPLICATE_SAME_ACCESS))
954         {
955           TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
956                       (int) GetLastError ());
957           CloseHandle (rh);
958           CloseHandle (wh);
959           /* FIXME: Should translate the error code.  */
960           gpg_err_set_errno (EIO);
961           return TRACE_SYSRES (-1);
962         }
963       CloseHandle (wh);
964       wh = hd;
965
966       ctx = find_reader (handle_to_fd (rh), 0);
967       assert (ctx == NULL);
968       ctx = find_reader (handle_to_fd (rh), 1);
969       if (!ctx)
970         {
971           CloseHandle (rh);
972           CloseHandle (wh);
973           /* FIXME: Should translate the error code.  */
974           gpg_err_set_errno (EIO);
975           return TRACE_SYSRES (-1);
976         }
977     }
978   
979   filedes[0] = handle_to_fd (rh);
980   filedes[1] = handle_to_fd (wh);
981   return TRACE_SUC2 ("read=%p, write=%p", rh, wh);
982 }
983
984
985 int
986 _gpgme_io_close (int fd)
987 {
988   int i;
989   _gpgme_close_notify_handler_t handler = NULL;
990   void *value = NULL;
991   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
992
993   if (fd == -1)
994     {
995       gpg_err_set_errno (EBADF);
996       return TRACE_SYSRES (-1);
997     }
998
999   kill_reader (fd);
1000   kill_writer (fd);
1001   LOCK (notify_table_lock);
1002   for (i = 0; i < DIM (notify_table); i++)
1003     {
1004       if (notify_table[i].inuse && notify_table[i].fd == fd)
1005         {
1006           handler = notify_table[i].handler;
1007           value   = notify_table[i].value;
1008           notify_table[i].handler = NULL;
1009           notify_table[i].value = NULL;
1010           notify_table[i].inuse = 0;
1011           break;
1012         }
1013     }
1014   UNLOCK (notify_table_lock);
1015   if (handler)
1016     handler (fd, value);
1017
1018   if (!CloseHandle (fd_to_handle (fd)))
1019     { 
1020       TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ());
1021       /* FIXME: Should translate the error code.  */
1022       gpg_err_set_errno (EIO);
1023       return TRACE_SYSRES (-1);
1024     }
1025
1026   return TRACE_SYSRES (0);
1027 }
1028
1029
1030 int
1031 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
1032                             void *value)
1033 {
1034   int i;
1035   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
1036               "close_handler=%p/%p", handler, value);
1037
1038   assert (fd != -1);
1039
1040   LOCK (notify_table_lock);
1041   for (i=0; i < DIM (notify_table); i++)
1042     if (notify_table[i].inuse && notify_table[i].fd == fd)
1043       break;
1044   if (i == DIM (notify_table))
1045     for (i = 0; i < DIM (notify_table); i++)
1046       if (!notify_table[i].inuse)
1047         break;
1048   if (i == DIM (notify_table))
1049     {
1050       UNLOCK (notify_table_lock);
1051       gpg_err_set_errno (EINVAL);
1052       return TRACE_SYSRES (-1);
1053     }
1054   notify_table[i].fd = fd;
1055   notify_table[i].handler = handler;
1056   notify_table[i].value = value;
1057   notify_table[i].inuse = 1;
1058   UNLOCK (notify_table_lock);
1059   return TRACE_SYSRES (0);
1060 }
1061
1062
1063 int
1064 _gpgme_io_set_nonblocking (int fd)
1065 {
1066   TRACE (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
1067   return 0;
1068 }
1069
1070
1071 static char *
1072 build_commandline (char **argv)
1073 {
1074   int i;
1075   int n = 0;
1076   char *buf;
1077   char *p;
1078   
1079   /* We have to quote some things because under Windows the program
1080      parses the commandline and does some unquoting.  We enclose the
1081      whole argument in double-quotes, and escape literal double-quotes
1082      as well as backslashes with a backslash.  We end up with a
1083      trailing space at the end of the line, but that is harmless.  */
1084   for (i = 0; argv[i]; i++)
1085     {
1086       p = argv[i];
1087       /* The leading double-quote.  */
1088       n++;
1089       while (*p)
1090         {
1091           /* An extra one for each literal that must be escaped.  */
1092           if (*p == '\\' || *p == '"')
1093             n++;
1094           n++;
1095           p++;
1096         }
1097       /* The trailing double-quote and the delimiter.  */
1098       n += 2;
1099     }
1100   /* And a trailing zero.  */
1101   n++;
1102
1103   buf = p = malloc (n);
1104   if (!buf)
1105     return NULL;
1106   for (i = 0; argv[i]; i++)
1107     {
1108       char *argvp = argv[i];
1109
1110       *(p++) = '"';
1111       while (*argvp)
1112         {
1113           if (*argvp == '\\' || *argvp == '"')
1114             *(p++) = '\\';
1115           *(p++) = *(argvp++);
1116         }
1117       *(p++) = '"';
1118       *(p++) = ' ';
1119     }
1120   *(p++) = 0;
1121
1122   return buf;
1123 }
1124
1125
1126 int
1127 _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
1128                  struct spawn_fd_item_s *fd_list,
1129                  void (*atfork) (void *opaque, int reserved),
1130                  void *atforkvalue, pid_t *r_pid)
1131 {
1132   SECURITY_ATTRIBUTES sec_attr;
1133   PROCESS_INFORMATION pi =
1134     {
1135       NULL,      /* returns process handle */
1136       0,         /* returns primary thread handle */
1137       0,         /* returns pid */
1138       0          /* returns tid */
1139     };
1140   STARTUPINFO si;
1141   int cr_flags = (CREATE_DEFAULT_ERROR_MODE
1142                   | GetPriorityClass (GetCurrentProcess ()));
1143   int i;
1144   char **args;
1145   char *arg_string;
1146   /* FIXME.  */
1147   int debug_me = 0;
1148   int tmp_fd;
1149   char *tmp_name;
1150
1151   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1152               "path=%s", path);
1153   i = 0;
1154   while (argv[i])
1155     {
1156       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1157       i++;
1158     }
1159
1160   /* We do not inherit any handles by default, and just insert those
1161      handles we want the child to have afterwards.  But some handle
1162      values occur on the command line, and we need to move
1163      stdin/out/err to the right location.  So we use a wrapper program
1164      which gets the information from a temporary file.  */
1165   if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
1166     {
1167       TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
1168       return TRACE_SYSRES (-1);
1169     }
1170   TRACE_LOG1 ("tmp_name = %s", tmp_name);
1171
1172   args = calloc (2 + i + 1, sizeof (*args));
1173   args[0] = (char *) _gpgme_get_w32spawn_path ();
1174   args[1] = tmp_name;
1175   args[2] = path;
1176   memcpy (&args[3], &argv[1], i * sizeof (*args));
1177
1178   memset (&sec_attr, 0, sizeof sec_attr);
1179   sec_attr.nLength = sizeof sec_attr;
1180   sec_attr.bInheritHandle = FALSE;
1181  
1182   arg_string = build_commandline (args);
1183   free (args);
1184   if (!arg_string)
1185     {
1186       close (tmp_fd);
1187       DeleteFile (tmp_name);
1188       return TRACE_SYSRES (-1);
1189     }
1190
1191   memset (&si, 0, sizeof si);
1192   si.cb = sizeof (si);
1193   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1194   si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
1195   si.hStdInput = INVALID_HANDLE_VALUE;
1196   si.hStdOutput = INVALID_HANDLE_VALUE;
1197   si.hStdError = INVALID_HANDLE_VALUE;
1198
1199   cr_flags |= CREATE_SUSPENDED; 
1200   cr_flags |= DETACHED_PROCESS;
1201   if (!CreateProcessA (_gpgme_get_w32spawn_path (),
1202                        arg_string,
1203                        &sec_attr,     /* process security attributes */
1204                        &sec_attr,     /* thread security attributes */
1205                        FALSE,         /* inherit handles */
1206                        cr_flags,      /* creation flags */
1207                        NULL,          /* environment */
1208                        NULL,          /* use current drive/directory */
1209                        &si,           /* startup information */
1210                        &pi))          /* returns process information */
1211     {
1212       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1213       free (arg_string);
1214       close (tmp_fd);
1215       DeleteFile (tmp_name);
1216
1217       /* FIXME: Should translate the error code.  */
1218       gpg_err_set_errno (EIO);
1219       return TRACE_SYSRES (-1);
1220     }
1221
1222   free (arg_string);
1223
1224   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
1225     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
1226
1227   /* Insert the inherited handles.  */
1228   for (i = 0; fd_list[i].fd != -1; i++)
1229     {
1230       HANDLE hd;
1231
1232       /* Make it inheritable for the wrapper process.  */
1233       if (!DuplicateHandle (GetCurrentProcess(), fd_to_handle (fd_list[i].fd),
1234                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
1235         {
1236           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
1237           TerminateProcess (pi.hProcess, 0);
1238           /* Just in case TerminateProcess didn't work, let the
1239              process fail on its own.  */
1240           ResumeThread (pi.hThread);
1241           CloseHandle (pi.hThread);
1242           CloseHandle (pi.hProcess);
1243
1244           close (tmp_fd);
1245           DeleteFile (tmp_name);
1246
1247           /* FIXME: Should translate the error code.  */
1248           gpg_err_set_errno (EIO);
1249           return TRACE_SYSRES (-1);
1250         }
1251       /* Return the child name of this handle.  */
1252       fd_list[i].peer_name = handle_to_fd (hd);
1253     }
1254   
1255   /* Write the handle translation information to the temporary
1256      file.  */
1257   {
1258     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
1259        notation: "0xFEDCBA9876543210" with an extra white space after
1260        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
1261        for a time when a HANDLE is 64 bit.  */
1262 #define BUFFER_MAX 810
1263     char line[BUFFER_MAX + 1];
1264     int res;
1265     int written;
1266     size_t len;
1267
1268     if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
1269       strcpy (line, "~1 \n");
1270     else
1271       strcpy (line, "\n");
1272     for (i = 0; fd_list[i].fd != -1; i++)
1273       {
1274         /* Strip the newline.  */
1275         len = strlen (line) - 1;
1276         
1277         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
1278         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
1279                   fd_list[i].fd, fd_list[i].dup_to,
1280                   fd_list[i].peer_name, fd_list[i].arg_loc);
1281         /* Rather safe than sorry.  */
1282         line[BUFFER_MAX - 1] = '\n';
1283         line[BUFFER_MAX] = '\0';
1284       }
1285     len = strlen (line);
1286     written = 0;
1287     do
1288       {
1289         res = write (tmp_fd, &line[written], len - written);
1290         if (res > 0)
1291           written += res;
1292       }
1293     while (res > 0 || (res < 0 && errno == EAGAIN));
1294   }
1295   close (tmp_fd);
1296   /* The temporary file is deleted by the gpgme-w32spawn process
1297      (hopefully).  */
1298
1299   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
1300               "dwProcessID=%d, dwThreadId=%d",
1301               pi.hProcess, pi.hThread, 
1302               (int) pi.dwProcessId, (int) pi.dwThreadId);
1303   
1304   if (r_pid)
1305     *r_pid = (pid_t)pi.dwProcessId;
1306
1307   
1308   if (ResumeThread (pi.hThread) < 0)
1309     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
1310   
1311   if (!CloseHandle (pi.hThread))
1312     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
1313                 (int) GetLastError ());
1314
1315   TRACE_LOG1 ("process=%p", pi.hProcess);
1316
1317   /* We don't need to wait for the process.  */
1318   if (!CloseHandle (pi.hProcess))
1319     TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
1320                 (int) GetLastError ());
1321
1322   if (! (flags & IOSPAWN_FLAG_NOCLOSE))
1323     {
1324       for (i = 0; fd_list[i].fd != -1; i++)
1325         _gpgme_io_close (fd_list[i].fd);
1326     }
1327
1328   for (i = 0; fd_list[i].fd != -1; i++)
1329     if (fd_list[i].dup_to == -1)
1330       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
1331                   fd_list[i].peer_name);
1332     else
1333       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
1334                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
1335                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
1336
1337   return TRACE_SYSRES (0);
1338 }
1339
1340
1341 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
1342    nothing to select, > 0 = number of signaled fds.  */
1343 int
1344 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
1345 {
1346   HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1347   int waitidx[MAXIMUM_WAIT_OBJECTS];
1348   int code;
1349   int nwait;
1350   int i;
1351   int any;
1352   int count;
1353   void *dbg_help;
1354   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
1355               "nfds=%u, nonblock=%u", nfds, nonblock);
1356
1357  restart:
1358   TRACE_SEQ (dbg_help, "select on [ ");
1359   any = 0;
1360   nwait = 0;
1361   count = 0;
1362   for (i=0; i < nfds; i++)
1363     {
1364       if (fds[i].fd == -1)
1365         continue;
1366       fds[i].signaled = 0;
1367       if (fds[i].for_read || fds[i].for_write)
1368         {
1369           if (fds[i].for_read)
1370             {
1371               struct reader_context_s *ctx = find_reader (fds[i].fd,0);
1372               
1373               if (!ctx)
1374                 TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
1375                             fds[i].fd);
1376               else
1377                 {
1378                   if (nwait >= DIM (waitbuf))
1379                     {
1380                       TRACE_END (dbg_help, "oops ]");
1381                       TRACE_LOG ("Too many objects for WFMO!");
1382                       /* FIXME: Should translate the error code.  */
1383                       gpg_err_set_errno (EIO);
1384                       return TRACE_SYSRES (-1);
1385                     }
1386                   waitidx[nwait] = i;
1387                   waitbuf[nwait++] = ctx->have_data_ev;
1388                 }
1389               TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
1390               any = 1;
1391             }
1392           else if (fds[i].for_write)
1393             {
1394               struct writer_context_s *ctx = find_writer (fds[i].fd,0);
1395               
1396               if (!ctx)
1397                 TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
1398                             fds[i].fd);
1399               else
1400                 {
1401                   if (nwait >= DIM (waitbuf))
1402                     {
1403                       TRACE_END (dbg_help, "oops ]");
1404                       TRACE_LOG ("Too many objects for WFMO!");
1405                       /* FIXME: Should translate the error code.  */
1406                       gpg_err_set_errno (EIO);
1407                       return TRACE_SYSRES (-1);
1408                     }
1409                   waitidx[nwait] = i;
1410                   waitbuf[nwait++] = ctx->is_empty;
1411                 }
1412               TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
1413               any = 1;
1414             }
1415         }
1416     }
1417   TRACE_END (dbg_help, "]");
1418   if (!any) 
1419     return TRACE_SYSRES (0);
1420
1421   code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
1422   if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
1423     {
1424       /* This WFMO is a really silly function: It does return either
1425          the index of the signaled object or if 2 objects have been
1426          signalled at the same time, the index of the object with the
1427          lowest object is returned - so and how do we find out how
1428          many objects have been signaled???.  The only solution I can
1429          imagine is to test each object starting with the returned
1430          index individually - how dull.  */
1431       any = 0;
1432       for (i = code - WAIT_OBJECT_0; i < nwait; i++)
1433         {
1434           if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
1435             {
1436               assert (waitidx[i] >=0 && waitidx[i] < nfds);
1437               fds[waitidx[i]].signaled = 1;
1438               any = 1;
1439               count++;
1440             }
1441         }
1442       if (!any)
1443         {
1444           TRACE_LOG ("no signaled objects found after WFMO");
1445           count = -1;
1446         }
1447     }
1448   else if (code == WAIT_TIMEOUT)
1449     TRACE_LOG ("WFMO timed out");
1450   else if (code == WAIT_FAILED)
1451     {
1452       int le = (int) GetLastError ();
1453       if (le == ERROR_INVALID_HANDLE)
1454         {
1455           int k;
1456           int j = handle_to_fd (waitbuf[i]);
1457           
1458           TRACE_LOG1 ("WFMO invalid handle %d removed", j);
1459           for (k = 0 ; k < nfds; k++)
1460             {
1461               if (fds[k].fd == j)
1462                 {
1463                   fds[k].for_read = fds[k].for_write = 0;
1464                   goto restart;
1465                 }
1466             }
1467           TRACE_LOG (" oops, or not???");
1468         }
1469       TRACE_LOG1 ("WFMO failed: %d", le);
1470       count = -1;
1471     }
1472   else
1473     {
1474       TRACE_LOG1 ("WFMO returned %d", code);
1475       count = -1;
1476     }
1477   
1478   if (count > 0)
1479     {
1480       TRACE_SEQ (dbg_help, "select OK [ ");
1481       for (i = 0; i < nfds; i++)
1482         {
1483           if (fds[i].fd == -1)
1484             continue;
1485           if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
1486             TRACE_ADD2 (dbg_help, "%c0x%x ",
1487                         fds[i].for_read ? 'r' : 'w', fds[i].fd);
1488         }
1489       TRACE_END (dbg_help, "]");
1490     }
1491
1492   if (count < 0)
1493     {
1494       /* FIXME: Should determine a proper error code.  */
1495       gpg_err_set_errno (EIO);
1496     }
1497   
1498   return TRACE_SYSRES (count);
1499 }
1500
1501
1502 void
1503 _gpgme_io_subsystem_init (void)
1504 {
1505   /* Nothing to do.  */
1506 }
1507
1508
1509 /* Write the printable version of FD to the buffer BUF of length
1510    BUFLEN.  The printable version is the representation on the command
1511    line that the child process expects.  */
1512 int
1513 _gpgme_io_fd2str (char *buf, int buflen, int fd)
1514 {
1515   return snprintf (buf, buflen, "%d", fd);
1516 }
1517
1518
1519 int
1520 _gpgme_io_dup (int fd)
1521 {
1522   HANDLE handle = fd_to_handle (fd);
1523   HANDLE new_handle = fd_to_handle (fd);
1524   int i;
1525   struct reader_context_s *rd_ctx;
1526   struct writer_context_s *wt_ctx;
1527
1528   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
1529
1530   if (!DuplicateHandle (GetCurrentProcess(), handle,
1531                         GetCurrentProcess(), &new_handle,
1532                         0, FALSE, DUPLICATE_SAME_ACCESS))
1533     {
1534       TRACE_LOG1 ("DuplicateHandle failed: ec=%d\n", (int) GetLastError ());
1535       /* FIXME: Translate error code.  */
1536       gpg_err_set_errno (EIO);
1537       return TRACE_SYSRES (-1);
1538     }
1539
1540   rd_ctx = find_reader (fd, 0);
1541   if (rd_ctx)
1542     {
1543       /* No need for locking, as the only races are against the reader
1544          thread itself, which doesn't touch refcount.  */
1545       rd_ctx->refcount++;
1546
1547       LOCK (reader_table_lock);
1548       for (i = 0; i < reader_table_size; i++)
1549         if (!reader_table[i].used)
1550           break;
1551       /* FIXME.  */
1552       assert (i != reader_table_size);
1553       reader_table[i].fd = handle_to_fd (new_handle);
1554       reader_table[i].context = rd_ctx;
1555       reader_table[i].used = 1;
1556       UNLOCK (reader_table_lock);
1557     }
1558
1559   wt_ctx = find_writer (fd, 0);
1560   if (wt_ctx)
1561     {
1562       /* No need for locking, as the only races are against the writer
1563          thread itself, which doesn't touch refcount.  */
1564       wt_ctx->refcount++;
1565
1566       LOCK (writer_table_lock);
1567       for (i = 0; i < writer_table_size; i++)
1568         if (!writer_table[i].used)
1569           break;
1570       /* FIXME.  */
1571       assert (i != writer_table_size);
1572       writer_table[i].fd = handle_to_fd (new_handle);
1573       writer_table[i].context = wt_ctx;
1574       writer_table[i].used = 1;
1575       UNLOCK (writer_table_lock);
1576     }
1577
1578   return TRACE_SYSRES (handle_to_fd (new_handle));
1579 }
1580
1581 \f
1582 /* The following interface is only useful for GPGME Glib and Qt.  */
1583
1584 /* Compatibility interface, obsolete.  */
1585 void *
1586 gpgme_get_giochannel (int fd)
1587 {
1588   return NULL;
1589 }
1590
1591
1592 /* Look up the giochannel or qiodevice for file descriptor FD.  */
1593 void *
1594 gpgme_get_fdptr (int fd)
1595 {
1596   return NULL;
1597 }
1598
1599 \f
1600 static int
1601 wsa2errno (int err)
1602 {
1603   switch (err)
1604     {
1605     case WSAENOTSOCK:
1606       return EINVAL;
1607     case WSAEWOULDBLOCK:
1608       return EAGAIN;
1609     case ERROR_BROKEN_PIPE:
1610       return EPIPE;
1611     case WSANOTINITIALISED:
1612       return ENOSYS;
1613     default:
1614       return EIO;
1615     }
1616 }
1617
1618
1619 int
1620 _gpgme_io_socket (int domain, int type, int proto)
1621 {
1622   int res;
1623
1624   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
1625               "type=%i, protp=%i", type, proto);
1626
1627   res = socket (domain, type, proto);
1628   if (res == INVALID_SOCKET)
1629     {
1630       gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
1631       return TRACE_SYSRES (-1);
1632     }
1633
1634   TRACE_SUC1 ("socket=0x%x", res);
1635   
1636   return res;
1637 }
1638
1639
1640 int
1641 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
1642 {
1643   int res;
1644
1645   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
1646               "addr=%p, addrlen=%i", addr, addrlen);
1647
1648   res = connect (fd, addr, addrlen);
1649   if (res)
1650     {
1651       gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
1652       return TRACE_SYSRES (-1);
1653     }
1654
1655   return TRACE_SUC ();
1656 }