2010-09-01 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 <fcntl.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <windows.h>
34 #include <io.h>
35
36 #ifdef HAVE_W32CE_SYSTEM
37 #include <assuan.h>
38 #include <winioctl.h>
39 #define GPGCEDEV_IOCTL_UNBLOCK                                        \
40   CTL_CODE (FILE_DEVICE_STREAMS, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS)
41 #define GPGCEDEV_IOCTL_ASSIGN_RVID                                    \
42   CTL_CODE (FILE_DEVICE_STREAMS, 2051, METHOD_BUFFERED, FILE_ANY_ACCESS)
43 #endif
44
45 #include "util.h"
46 #include "sema.h"
47 #include "priv-io.h"
48 #include "debug.h"
49
50
51 /* FIXME: Optimize.  */
52 #define MAX_SLAFD 512
53
54 static struct
55 {
56   int used;
57
58   /* If this is not INVALID_HANDLE_VALUE, then it's a handle.  */
59   HANDLE handle;
60
61   /* If this is not INVALID_SOCKET, then it's a Windows socket.  */
62   int socket;
63
64   /* If this is not 0, then it's a rendezvous ID for the pipe server.  */
65   int rvid;
66
67   /* DUP_FROM is -1 if this file descriptor was allocated by pipe or
68      socket functions.  Only then should the handle or socket be
69      destroyed when this FD is closed.  This, together with the fact
70      that dup'ed file descriptors are closed before the file
71      descriptors from which they are dup'ed are closed, ensures that
72      the handle or socket is always valid, and shared among all file
73      descriptors refering to the same underlying object.
74
75      The logic behind this is that there is only one reason for us to
76      dup file descriptors anyway: to allow simpler book-keeping of
77      file descriptors shared between GPGME and libassuan, which both
78      want to close something.  Using the same handle for these
79      duplicates works just fine.  */
80   int dup_from;
81 } fd_table[MAX_SLAFD];  
82
83
84 /* Returns the FD or -1 on resource limit.  */
85 int
86 new_fd (void)
87 {
88   int idx;
89
90   for (idx = 0; idx < MAX_SLAFD; idx++)
91     if (! fd_table[idx].used)
92       break;
93
94   if (idx == MAX_SLAFD)
95     {
96       gpg_err_set_errno (EIO);
97       return -1;
98     }
99
100   fd_table[idx].used = 1;
101   fd_table[idx].handle = INVALID_HANDLE_VALUE;
102   fd_table[idx].socket = INVALID_SOCKET;
103   fd_table[idx].rvid = 0;
104   fd_table[idx].dup_from = -1;
105
106   return idx;
107 }
108
109
110 void
111 release_fd (int fd)
112 {
113   if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
114     return;
115
116   fd_table[fd].used = 0;
117   fd_table[fd].handle = INVALID_HANDLE_VALUE;
118   fd_table[fd].socket = INVALID_SOCKET;
119   fd_table[fd].rvid = 0;
120   fd_table[fd].dup_from = -1;
121 }
122
123
124 #define pid_to_handle(a) ((HANDLE)(a))
125 #define handle_to_pid(a) ((int)(a))
126
127 #define READBUF_SIZE 4096
128 #define WRITEBUF_SIZE 4096
129 #define PIPEBUF_SIZE  4096
130 #define MAX_READERS 64
131 #define MAX_WRITERS 64
132
133 static struct
134 {
135   int inuse;
136   int fd;
137   _gpgme_close_notify_handler_t handler;
138   void *value;
139 } notify_table[MAX_SLAFD];
140 DEFINE_STATIC_LOCK (notify_table_lock);
141
142
143 struct reader_context_s
144 {
145   HANDLE file_hd;
146   int file_sock;
147   HANDLE thread_hd;     
148   int refcount;
149
150   DECLARE_LOCK (mutex);
151
152   int stop_me;
153   int eof;
154   int eof_shortcut;
155   int error;
156   int error_code;
157   
158   /* This is manually reset.  */
159   HANDLE have_data_ev;
160   /* This is automatically reset.  */
161   HANDLE have_space_ev;
162   HANDLE stopped;
163   size_t readpos, writepos;
164   char buffer[READBUF_SIZE];
165 };
166
167
168 static struct
169 {
170   volatile int used;
171   int fd;
172   struct reader_context_s *context;
173 } reader_table[MAX_READERS];
174 static int reader_table_size= MAX_READERS;
175 DEFINE_STATIC_LOCK (reader_table_lock);
176
177
178 struct writer_context_s
179 {
180   HANDLE file_hd;
181   int file_sock;
182   HANDLE thread_hd;     
183   int refcount;
184
185   DECLARE_LOCK (mutex);
186   
187   int stop_me;
188   int error;
189   int error_code;
190
191   /* This is manually reset.  */
192   HANDLE have_data;
193   HANDLE is_empty;
194   HANDLE stopped;
195   size_t nbytes; 
196   char buffer[WRITEBUF_SIZE];
197 };
198
199
200 static struct
201 {
202   volatile int used;
203   int fd;
204   struct writer_context_s *context;
205 } writer_table[MAX_WRITERS];
206 static int writer_table_size= MAX_WRITERS;
207 DEFINE_STATIC_LOCK (writer_table_lock);
208
209
210 static int
211 get_desired_thread_priority (void)
212 {
213   int value;
214
215   if (!_gpgme_get_conf_int ("IOThreadPriority", &value))
216     {
217       value = THREAD_PRIORITY_HIGHEST;
218       TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
219               "%d (default)", value);
220     }
221   else
222     {
223       TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
224               "%d (configured)", value);
225     }
226   return value;
227 }
228
229
230 static HANDLE
231 set_synchronize (HANDLE hd)
232 {
233 #ifdef HAVE_W32CE_SYSTEM
234   return hd;
235 #else
236   HANDLE new_hd;
237
238   /* For NT we have to set the sync flag.  It seems that the only way
239      to do it is by duplicating the handle.  Tsss...  */
240   if (!DuplicateHandle (GetCurrentProcess (), hd,
241                         GetCurrentProcess (), &new_hd,
242                         EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0))
243     {
244       TRACE1 (DEBUG_SYSIO, "gpgme:set_synchronize", hd,
245               "DuplicateHandle failed: ec=%d", (int) GetLastError ());
246       /* FIXME: Should translate the error code.  */
247       gpg_err_set_errno (EIO);
248       return INVALID_HANDLE_VALUE;
249     }
250
251   CloseHandle (hd);
252   return new_hd;
253 #endif
254 }
255
256
257 /* Return 1 if HD refers to a socket, 0 if it does not refer to a
258    socket, and -1 for unknown (autodetect).  */
259 static int
260 is_socket (HANDLE hd)
261 {
262 #ifdef HAVE_W32CE_SYSTEM
263   return -1;
264 #else
265   /* We need to figure out whether we are working on a socket or on a
266      handle.  A trivial way would be to check for the return code of
267      recv and see if it is WSAENOTSOCK.  However the recv may block
268      after the server process died and thus the destroy_reader will
269      hang.  Another option is to use getsockopt to test whether it is
270      a socket.  The bug here is that once a socket with a certain
271      values has been opened, closed and later a CreatePipe returned
272      the same value (i.e. handle), getsockopt still believes it is a
273      socket.  What we do now is to use a combination of GetFileType
274      and GetNamedPipeInfo.  The specs say that the latter may be used
275      on anonymous pipes as well.  Note that there are claims that
276      since winsocket version 2 ReadFile may be used on a socket but
277      only if it is supported by the service provider.  Tests on a
278      stock XP using a local TCP socket show that it does not work.  */
279   DWORD dummyflags, dummyoutsize, dummyinsize, dummyinst;
280
281   if (GetFileType (hd) == FILE_TYPE_PIPE
282       && !GetNamedPipeInfo (hd, &dummyflags, &dummyoutsize,
283                             &dummyinsize, &dummyinst))
284     return 1; /* Function failed; thus we assume it is a socket.  */
285   else
286     return 0; /* Success; this is not a socket.  */
287 #endif
288 }
289
290
291 static DWORD CALLBACK 
292 reader (void *arg)
293 {
294   struct reader_context_s *ctx = arg;
295   int nbytes;
296   DWORD nread;
297   int sock;
298   TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
299               "thread=%p", ctx->thread_hd);
300
301   if (ctx->file_hd != INVALID_HANDLE_VALUE)
302     sock = 0;
303   else
304     sock = 1;
305
306   for (;;)
307     {
308       LOCK (ctx->mutex);
309       /* Leave a 1 byte gap so that we can see whether it is empty or
310          full.  */
311       if ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
312         { 
313           /* Wait for space.  */
314           if (!ResetEvent (ctx->have_space_ev))
315             TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
316           UNLOCK (ctx->mutex);
317           TRACE_LOG ("waiting for space");
318           WaitForSingleObject (ctx->have_space_ev, INFINITE);
319           TRACE_LOG ("got space");
320           LOCK (ctx->mutex);
321         }
322       if (ctx->stop_me)
323         {
324           UNLOCK (ctx->mutex);
325           break;
326         }
327       nbytes = (ctx->readpos + READBUF_SIZE
328                 - ctx->writepos - 1) % READBUF_SIZE;
329       if (nbytes > READBUF_SIZE - ctx->writepos)
330         nbytes = READBUF_SIZE - ctx->writepos;
331       UNLOCK (ctx->mutex);
332       
333       TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes);
334
335       if (sock)
336         {
337           int n;
338
339           n = recv (ctx->file_sock, ctx->buffer + ctx->writepos, nbytes, 0);
340           if (n < 0)
341             {
342               ctx->error_code = (int) WSAGetLastError ();
343               if (ctx->error_code == ERROR_BROKEN_PIPE)
344                 {
345                   ctx->eof = 1;
346                   TRACE_LOG ("got EOF (broken connection)");
347                 }
348               else
349                 {
350                   ctx->error = 1;
351                   TRACE_LOG1 ("recv error: ec=%d", ctx->error_code);
352                 }
353               break;
354             }
355           nread = n;
356         }
357       else
358         {
359           if (!ReadFile (ctx->file_hd,
360                          ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
361             {
362               ctx->error_code = (int) GetLastError ();
363               /* NOTE (W32CE): Do not ignore ERROR_BUSY!  Check at
364                  least stop_me if that happens.  */
365               if (ctx->error_code == ERROR_BROKEN_PIPE)
366                 {
367                   ctx->eof = 1;
368                   TRACE_LOG ("got EOF (broken pipe)");
369                 }
370               else
371                 {
372                   ctx->error = 1;
373                   TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
374                 }
375               break;
376             }
377         }
378       LOCK (ctx->mutex);
379       if (ctx->stop_me)
380         {
381           UNLOCK (ctx->mutex);
382           break;
383         }
384       if (!nread)
385         {
386           ctx->eof = 1;
387           TRACE_LOG ("got eof");
388           UNLOCK (ctx->mutex);
389           break;
390         }
391       TRACE_LOG1 ("got %u bytes", nread);
392       
393       ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
394       if (!SetEvent (ctx->have_data_ev))
395         TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
396                     (int) GetLastError ());
397       UNLOCK (ctx->mutex);
398     }
399   /* Indicate that we have an error or EOF.  */
400   if (!SetEvent (ctx->have_data_ev))
401         TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
402                     (int) GetLastError ());
403   SetEvent (ctx->stopped);
404   
405   return TRACE_SUC ();
406 }
407
408
409 static struct reader_context_s *
410 create_reader (int fd)
411 {
412   struct reader_context_s *ctx;
413   SECURITY_ATTRIBUTES sec_attr;
414   DWORD tid;
415
416   TRACE_BEG (DEBUG_SYSIO, "gpgme:create_reader", fd);
417
418   memset (&sec_attr, 0, sizeof sec_attr);
419   sec_attr.nLength = sizeof sec_attr;
420   sec_attr.bInheritHandle = FALSE;
421   
422   ctx = calloc (1, sizeof *ctx);
423   if (!ctx)
424     {
425       TRACE_SYSERR (errno);
426       return NULL;
427     }
428
429   if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
430     {
431       TRACE_SYSERR (EIO);
432       return NULL;
433     }
434   ctx->file_hd = fd_table[fd].handle;
435   ctx->file_sock = fd_table[fd].socket;
436
437   ctx->refcount = 1;
438   ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
439   if (ctx->have_data_ev)
440     ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
441   if (ctx->have_space_ev)
442     ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
443   if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->stopped)
444     {
445       TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
446       if (ctx->have_data_ev)
447         CloseHandle (ctx->have_data_ev);
448       if (ctx->have_space_ev)
449         CloseHandle (ctx->have_space_ev);
450       if (ctx->stopped)
451         CloseHandle (ctx->stopped);
452       free (ctx);
453       /* FIXME: Translate the error code.  */
454       TRACE_SYSERR (EIO);
455       return NULL;
456     }
457
458   ctx->have_data_ev = set_synchronize (ctx->have_data_ev);
459   INIT_LOCK (ctx->mutex);
460
461   ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid);
462   if (!ctx->thread_hd)
463     {
464       TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
465       DESTROY_LOCK (ctx->mutex);
466       if (ctx->have_data_ev)
467         CloseHandle (ctx->have_data_ev);
468       if (ctx->have_space_ev)
469         CloseHandle (ctx->have_space_ev);
470       if (ctx->stopped)
471         CloseHandle (ctx->stopped);
472       free (ctx);
473       TRACE_SYSERR (EIO);
474       return NULL;
475     }    
476   else
477     {
478       /* We set the priority of the thread higher because we know that
479          it only runs for a short time.  This greatly helps to
480          increase the performance of the I/O.  */
481       SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
482     }
483
484   TRACE_SUC ();
485   return ctx;
486 }
487
488
489 static void
490 destroy_reader (struct reader_context_s *ctx)
491 {
492   LOCK (ctx->mutex);
493   ctx->refcount--;
494   if (ctx->refcount != 0)
495     {
496       UNLOCK (ctx->mutex);
497       return;
498     }
499   ctx->stop_me = 1;
500   if (ctx->have_space_ev) 
501     SetEvent (ctx->have_space_ev);
502   UNLOCK (ctx->mutex);
503
504 #ifdef HAVE_W32CE_SYSTEM
505   /* Scenario: We never create a full pipe, but already started
506      reading.  Then we need to unblock the reader in the pipe driver
507      to make our reader thread notice that we want it to go away.  */
508
509   if (ctx->file_hd != INVALID_HANDLE_VALUE)
510     {
511       if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
512                         NULL, 0, NULL, 0, NULL, NULL))
513         {
514           TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
515                   "unblock control call failed for thread %p", ctx->thread_hd);
516         }
517     }
518 #endif
519
520   TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
521           "waiting for termination of thread %p", ctx->thread_hd);
522   WaitForSingleObject (ctx->stopped, INFINITE);
523   TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
524           "thread %p has terminated", ctx->thread_hd);
525     
526   if (ctx->stopped)
527     CloseHandle (ctx->stopped);
528   if (ctx->have_data_ev)
529     CloseHandle (ctx->have_data_ev);
530   if (ctx->have_space_ev)
531     CloseHandle (ctx->have_space_ev);
532   CloseHandle (ctx->thread_hd);
533   DESTROY_LOCK (ctx->mutex);
534   free (ctx);
535 }
536
537
538 /* Find a reader context or create a new one.  Note that the reader
539    context will last until a _gpgme_io_close.  */
540 static struct reader_context_s *
541 find_reader (int fd, int start_it)
542 {
543   struct reader_context_s *rd = NULL;
544   int i;
545
546   LOCK (reader_table_lock);
547   for (i = 0; i < reader_table_size; i++)
548     if (reader_table[i].used && reader_table[i].fd == fd)
549       rd = reader_table[i].context;
550
551   if (rd || !start_it)
552     {
553       UNLOCK (reader_table_lock);
554       return rd;
555     }
556
557   for (i = 0; i < reader_table_size; i++)
558     if (!reader_table[i].used)
559       break;
560
561   if (i != reader_table_size)
562     {
563       rd = create_reader (fd);
564       reader_table[i].fd = fd;
565       reader_table[i].context = rd;
566       reader_table[i].used = 1;
567     }
568
569   UNLOCK (reader_table_lock);
570   return rd;
571 }
572
573
574 static void
575 kill_reader (int fd)
576 {
577   int i;
578
579   LOCK (reader_table_lock);
580   for (i = 0; i < reader_table_size; i++)
581     {
582       if (reader_table[i].used && reader_table[i].fd == fd)
583         {
584           destroy_reader (reader_table[i].context);
585           reader_table[i].context = NULL;
586           reader_table[i].used = 0;
587           break;
588         }
589     }
590   UNLOCK (reader_table_lock);
591 }
592
593
594 int
595 _gpgme_io_read (int fd, void *buffer, size_t count)
596 {
597   int nread;
598   struct reader_context_s *ctx;
599   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
600               "buffer=%p, count=%u", buffer, count);
601   
602   ctx = find_reader (fd, 1);
603   if (!ctx)
604     {
605       gpg_err_set_errno (EBADF);
606       return TRACE_SYSRES (-1);
607     }
608   if (ctx->eof_shortcut)
609     return TRACE_SYSRES (0);
610
611   LOCK (ctx->mutex);
612   if (ctx->readpos == ctx->writepos && !ctx->error)
613     {
614       /* No data available.  */
615       UNLOCK (ctx->mutex);
616       TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd);
617       WaitForSingleObject (ctx->have_data_ev, INFINITE);
618       TRACE_LOG1 ("data from thread %p available", ctx->thread_hd);
619       LOCK (ctx->mutex);
620     }
621   
622   if (ctx->readpos == ctx->writepos || ctx->error)
623     {
624       UNLOCK (ctx->mutex);
625       ctx->eof_shortcut = 1;
626       if (ctx->eof)
627         return TRACE_SYSRES (0);
628       if (!ctx->error)
629         {
630           TRACE_LOG ("EOF but ctx->eof flag not set");
631           return 0;
632         }
633       gpg_err_set_errno (ctx->error_code);
634       return TRACE_SYSRES (-1);
635     }
636   
637   nread = ctx->readpos < ctx->writepos
638     ? ctx->writepos - ctx->readpos
639     : READBUF_SIZE - ctx->readpos;
640   if (nread > count)
641     nread = count;
642   memcpy (buffer, ctx->buffer + ctx->readpos, nread);
643   ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
644   if (ctx->readpos == ctx->writepos && !ctx->eof)
645     {
646       if (!ResetEvent (ctx->have_data_ev))
647         {
648           TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
649           UNLOCK (ctx->mutex);
650           /* FIXME: Should translate the error code.  */
651           gpg_err_set_errno (EIO);
652           return TRACE_SYSRES (-1);
653         }
654     }
655   if (!SetEvent (ctx->have_space_ev))
656     {
657       TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d",
658                   ctx->have_space_ev, (int) GetLastError ());
659       UNLOCK (ctx->mutex);
660       /* FIXME: Should translate the error code.  */
661       gpg_err_set_errno (EIO);
662       return TRACE_SYSRES (-1);
663     }
664   UNLOCK (ctx->mutex);
665   
666   TRACE_LOGBUF (buffer, nread);
667   return TRACE_SYSRES (nread);
668 }
669
670
671 /* The writer does use a simple buffering strategy so that we are
672    informed about write errors as soon as possible (i. e. with the the
673    next call to the write function.  */
674 static DWORD CALLBACK 
675 writer (void *arg)
676 {
677   struct writer_context_s *ctx = arg;
678   DWORD nwritten;
679   int sock;
680   TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
681               "thread=%p", ctx->thread_hd);
682
683   if (ctx->file_hd != INVALID_HANDLE_VALUE)
684     sock = 0;
685   else
686     sock = 1;
687
688   for (;;)
689     {
690       LOCK (ctx->mutex);
691       if (ctx->stop_me)
692         {
693           UNLOCK (ctx->mutex);
694           break;
695         }
696       if (!ctx->nbytes)
697         { 
698           if (!SetEvent (ctx->is_empty))
699             TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
700           if (!ResetEvent (ctx->have_data))
701             TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
702           UNLOCK (ctx->mutex);
703           TRACE_LOG ("idle");
704           WaitForSingleObject (ctx->have_data, INFINITE);
705           TRACE_LOG ("got data to send");
706           LOCK (ctx->mutex);
707         }
708       if (ctx->stop_me)
709         {
710           UNLOCK (ctx->mutex);
711           break;
712         }
713       UNLOCK (ctx->mutex);
714       
715       TRACE_LOG2 ("%s %d bytes", sock?"sending":"writing", ctx->nbytes);
716
717       /* Note that CTX->nbytes is not zero at this point, because
718          _gpgme_io_write always writes at least 1 byte before waking
719          us up, unless CTX->stop_me is true, which we catch above.  */
720       if (sock)
721         {
722           /* We need to try send first because a socket handle can't
723              be used with WriteFile.  */
724           int n;
725
726           n = send (ctx->file_sock, ctx->buffer, ctx->nbytes, 0);
727           if (n < 0)
728             {
729               ctx->error_code = (int) WSAGetLastError ();
730               ctx->error = 1;
731               TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
732               break;
733             }
734           nwritten = n;
735         }
736       else
737         {
738           if (!WriteFile (ctx->file_hd, ctx->buffer,
739                           ctx->nbytes, &nwritten, NULL))
740             {
741               if (GetLastError () == ERROR_BUSY)
742                 {
743                   /* Probably stop_me is set now.  */
744                   TRACE_LOG ("pipe busy (unblocked?)");
745                   continue;
746                 }
747
748               ctx->error_code = (int) GetLastError ();
749               ctx->error = 1;
750               TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
751               break;
752             }
753         }
754       TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
755       
756       LOCK (ctx->mutex);
757       ctx->nbytes -= nwritten;
758       UNLOCK (ctx->mutex);
759     }
760   /* Indicate that we have an error.  */
761   if (!SetEvent (ctx->is_empty))
762     TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
763   SetEvent (ctx->stopped);
764
765   return TRACE_SUC ();
766 }
767
768
769 static struct writer_context_s *
770 create_writer (int fd)
771 {
772   struct writer_context_s *ctx;
773   SECURITY_ATTRIBUTES sec_attr;
774   DWORD tid;
775
776   TRACE_BEG (DEBUG_SYSIO, "gpgme:create_writer", fd);
777
778   memset (&sec_attr, 0, sizeof sec_attr);
779   sec_attr.nLength = sizeof sec_attr;
780   sec_attr.bInheritHandle = FALSE;
781
782   ctx = calloc (1, sizeof *ctx);
783   if (!ctx)
784     {
785       TRACE_SYSERR (errno);
786       return NULL;
787     }
788   
789   if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
790     {
791       TRACE_SYSERR (EIO);
792       return NULL;
793     }
794   ctx->file_hd = fd_table[fd].handle;
795   ctx->file_sock = fd_table[fd].socket;
796
797   ctx->refcount = 1;
798   ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
799   if (ctx->have_data)
800     ctx->is_empty  = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
801   if (ctx->is_empty)
802     ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
803   if (!ctx->have_data || !ctx->is_empty || !ctx->stopped)
804     {
805       TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
806       if (ctx->have_data)
807         CloseHandle (ctx->have_data);
808       if (ctx->is_empty)
809         CloseHandle (ctx->is_empty);
810       if (ctx->stopped)
811         CloseHandle (ctx->stopped);
812       free (ctx);
813       /* FIXME: Translate the error code.  */
814       TRACE_SYSERR (EIO);
815       return NULL;
816     }
817
818   ctx->is_empty = set_synchronize (ctx->is_empty);
819   INIT_LOCK (ctx->mutex);
820
821   ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
822   if (!ctx->thread_hd)
823     {
824       TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
825       DESTROY_LOCK (ctx->mutex);
826       if (ctx->have_data)
827         CloseHandle (ctx->have_data);
828       if (ctx->is_empty)
829         CloseHandle (ctx->is_empty);
830       if (ctx->stopped)
831         CloseHandle (ctx->stopped);
832       free (ctx);
833       TRACE_SYSERR (EIO);
834       return NULL;
835     }    
836   else
837     {
838       /* We set the priority of the thread higher because we know
839          that it only runs for a short time.  This greatly helps to
840          increase the performance of the I/O.  */
841       SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
842     }
843
844   TRACE_SUC ();
845   return ctx;
846 }
847
848 static void
849 destroy_writer (struct writer_context_s *ctx)
850 {
851   LOCK (ctx->mutex);
852   ctx->refcount--;
853   if (ctx->refcount != 0)
854     {
855       UNLOCK (ctx->mutex);
856       return;
857     }
858   ctx->stop_me = 1;
859   if (ctx->have_data) 
860     SetEvent (ctx->have_data);
861   UNLOCK (ctx->mutex);
862
863 #ifdef HAVE_W32CE_SYSTEM
864   /* Scenario: We never create a full pipe, but already started
865      writing more than the pipe buffer.  Then we need to unblock the
866      writer in the pipe driver to make our writer thread notice that
867      we want it to go away.  */
868
869   if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK,
870                         NULL, 0, NULL, 0, NULL, NULL))
871     {
872       TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
873               "unblock control call failed for thread %p", ctx->thread_hd);
874     }
875 #endif
876   
877   TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
878           "waiting for termination of thread %p", ctx->thread_hd);
879   WaitForSingleObject (ctx->stopped, INFINITE);
880   TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
881           "thread %p has terminated", ctx->thread_hd);
882   
883   if (ctx->stopped)
884     CloseHandle (ctx->stopped);
885   if (ctx->have_data)
886     CloseHandle (ctx->have_data);
887   if (ctx->is_empty)
888     CloseHandle (ctx->is_empty);
889   CloseHandle (ctx->thread_hd);
890   DESTROY_LOCK (ctx->mutex);
891   free (ctx);
892 }
893
894
895 /* Find a writer context or create a new one.  Note that the writer
896    context will last until a _gpgme_io_close.  */
897 static struct writer_context_s *
898 find_writer (int fd, int start_it)
899 {
900   struct writer_context_s *wt = NULL;
901   int i;
902
903   LOCK (writer_table_lock);
904   for (i = 0; i < writer_table_size; i++)
905     if (writer_table[i].used && writer_table[i].fd == fd)
906       wt = writer_table[i].context;
907
908   if (wt || !start_it)
909     {
910       UNLOCK (writer_table_lock);
911       return wt;
912     }
913
914   for (i = 0; i < writer_table_size; i++)
915     if (!writer_table[i].used)
916       break;
917
918   if (i != writer_table_size)
919     {
920       wt = create_writer (fd);
921       writer_table[i].fd = fd;
922       writer_table[i].context = wt; 
923       writer_table[i].used = 1;
924     }
925
926   UNLOCK (writer_table_lock);
927   return wt;
928 }
929
930
931 static void
932 kill_writer (int fd)
933 {
934   int i;
935
936   LOCK (writer_table_lock);
937   for (i = 0; i < writer_table_size; i++)
938     {
939       if (writer_table[i].used && writer_table[i].fd == fd)
940         {
941           destroy_writer (writer_table[i].context);
942           writer_table[i].context = NULL;
943           writer_table[i].used = 0;
944           break;
945         }
946     }
947   UNLOCK (writer_table_lock);
948 }
949
950
951 int
952 _gpgme_io_write (int fd, const void *buffer, size_t count)
953 {
954   struct writer_context_s *ctx;
955   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
956               "buffer=%p, count=%u", buffer, count);
957   TRACE_LOGBUF (buffer, count);
958
959   if (count == 0)
960     return TRACE_SYSRES (0);
961
962   ctx = find_writer (fd, 1);
963   if (!ctx)
964     return TRACE_SYSRES (-1);
965
966   LOCK (ctx->mutex);
967   if (!ctx->error && ctx->nbytes)
968     {
969       /* Bytes are pending for send.  */
970
971       /* Reset the is_empty event.  Better safe than sorry.  */
972       if (!ResetEvent (ctx->is_empty))
973         {
974           TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
975           UNLOCK (ctx->mutex);
976           /* FIXME: Should translate the error code.  */
977           gpg_err_set_errno (EIO);
978           return TRACE_SYSRES (-1);
979         }
980       UNLOCK (ctx->mutex);
981       TRACE_LOG1 ("waiting for empty buffer in thread %p", ctx->thread_hd);
982       WaitForSingleObject (ctx->is_empty, INFINITE);
983       TRACE_LOG1 ("thread %p buffer is empty", ctx->thread_hd);
984       LOCK (ctx->mutex);
985     }
986
987   if (ctx->error)
988     {
989       UNLOCK (ctx->mutex);
990       if (ctx->error_code == ERROR_NO_DATA)
991         gpg_err_set_errno (EPIPE);
992       else
993         gpg_err_set_errno (EIO);
994       return TRACE_SYSRES (-1);
995     }
996
997   /* If no error occured, the number of bytes in the buffer must be
998      zero.  */
999   assert (!ctx->nbytes);
1000
1001   if (count > WRITEBUF_SIZE)
1002     count = WRITEBUF_SIZE;
1003   memcpy (ctx->buffer, buffer, count);
1004   ctx->nbytes = count;
1005
1006   /* We have to reset the is_empty event early, because it is also
1007      used by the select() implementation to probe the channel.  */
1008   if (!ResetEvent (ctx->is_empty))
1009     {
1010       TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
1011       UNLOCK (ctx->mutex);
1012       /* FIXME: Should translate the error code.  */
1013       gpg_err_set_errno (EIO);
1014       return TRACE_SYSRES (-1);
1015     }
1016   if (!SetEvent (ctx->have_data))
1017     {
1018       TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
1019       UNLOCK (ctx->mutex);
1020       /* FIXME: Should translate the error code.  */
1021       gpg_err_set_errno (EIO);
1022       return TRACE_SYSRES (-1);
1023     }
1024   UNLOCK (ctx->mutex);
1025
1026   return TRACE_SYSRES ((int) count);
1027 }
1028
1029
1030 int
1031 _gpgme_io_pipe (int filedes[2], int inherit_idx)
1032 {
1033   int rfd;
1034   int wfd;
1035 #ifdef HAVE_W32CE_SYSTEM
1036   HANDLE hd;
1037   int rvid;
1038 #else
1039   HANDLE rh;
1040   HANDLE wh;
1041   SECURITY_ATTRIBUTES sec_attr;
1042 #endif
1043
1044   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
1045               "inherit_idx=%i (GPGME uses it for %s)",
1046               inherit_idx, inherit_idx ? "reading" : "writing");
1047
1048   rfd = new_fd ();
1049   if (rfd == -1)
1050     return TRACE_SYSRES (-1);
1051   wfd = new_fd ();
1052   if (wfd == -1)
1053     {
1054       release_fd (rfd);
1055       return TRACE_SYSRES (-1);
1056     }
1057
1058 #ifdef HAVE_W32CE_SYSTEM
1059   hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
1060   if (hd == INVALID_HANDLE_VALUE)
1061     {
1062       TRACE_LOG1 ("_assuan_w32ce_prepare_pipe failed: ec=%d",
1063                   (int) GetLastError ());
1064       release_fd (rfd);
1065       release_fd (wfd);
1066       /* FIXME: Should translate the error code.  */
1067       gpg_err_set_errno (EIO);
1068       return TRACE_SYSRES (-1);
1069     }
1070
1071   if (inherit_idx == 0)
1072     {
1073       fd_table[rfd].rvid = rvid;
1074       fd_table[wfd].handle = hd;
1075     }
1076   else
1077     {
1078       fd_table[rfd].handle = hd;
1079       fd_table[wfd].rvid = rvid;
1080     }  
1081
1082 #else
1083
1084   memset (&sec_attr, 0, sizeof (sec_attr));
1085   sec_attr.nLength = sizeof (sec_attr);
1086   sec_attr.bInheritHandle = FALSE;
1087   
1088   if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
1089     {
1090       TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
1091       release_fd (rfd);
1092       release_fd (wfd);
1093       /* FIXME: Should translate the error code.  */
1094       gpg_err_set_errno (EIO);
1095       return TRACE_SYSRES (-1);
1096     }
1097
1098   /* Make one end inheritable.  */
1099   if (inherit_idx == 0)
1100     {
1101       HANDLE hd;
1102       if (!DuplicateHandle (GetCurrentProcess(), rh,
1103                             GetCurrentProcess(), &hd, 0,
1104                             TRUE, DUPLICATE_SAME_ACCESS))
1105         {
1106           TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1107                       (int) GetLastError ());
1108           release_fd (rfd);
1109           release_fd (wfd);
1110           CloseHandle (rh);
1111           CloseHandle (wh);
1112           /* FIXME: Should translate the error code.  */
1113           gpg_err_set_errno (EIO);
1114           return TRACE_SYSRES (-1);
1115         }
1116       CloseHandle (rh);
1117       rh = hd;
1118     }
1119   else if (inherit_idx == 1)
1120     {
1121       HANDLE hd;
1122       if (!DuplicateHandle( GetCurrentProcess(), wh,
1123                             GetCurrentProcess(), &hd, 0,
1124                             TRUE, DUPLICATE_SAME_ACCESS))
1125         {
1126           TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
1127                       (int) GetLastError ());
1128           release_fd (rfd);
1129           release_fd (wfd);
1130           CloseHandle (rh);
1131           CloseHandle (wh);
1132           /* FIXME: Should translate the error code.  */
1133           gpg_err_set_errno (EIO);
1134           return TRACE_SYSRES (-1);
1135         }
1136       CloseHandle (wh);
1137       wh = hd;
1138     }
1139   fd_table[rfd].handle = rh;
1140   fd_table[wfd].handle = wh;
1141 #endif
1142
1143   filedes[0] = rfd;
1144   filedes[1] = wfd;
1145   return TRACE_SUC6 ("read=0x%x (%p/0x%x), write=0x%x (%p/0x%x)",
1146                      rfd, fd_table[rfd].handle, fd_table[rfd].rvid,
1147                      wfd, fd_table[wfd].handle, fd_table[wfd].rvid);
1148 }
1149
1150
1151 int
1152 _gpgme_io_close (int fd)
1153 {
1154   int i;
1155   _gpgme_close_notify_handler_t handler = NULL;
1156   void *value = NULL;
1157
1158   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
1159
1160   if (fd == -1)
1161     {
1162       gpg_err_set_errno (EBADF);
1163       return TRACE_SYSRES (-1);
1164     }
1165   if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1166     {
1167       gpg_err_set_errno (EBADF);
1168       return TRACE_SYSRES (-1);
1169     }
1170
1171   kill_reader (fd);
1172   kill_writer (fd);
1173   LOCK (notify_table_lock);
1174   for (i = 0; i < DIM (notify_table); i++)
1175     {
1176       if (notify_table[i].inuse && notify_table[i].fd == fd)
1177         {
1178           handler = notify_table[i].handler;
1179           value   = notify_table[i].value;
1180           notify_table[i].handler = NULL;
1181           notify_table[i].value = NULL;
1182           notify_table[i].inuse = 0;
1183           break;
1184         }
1185     }
1186   UNLOCK (notify_table_lock);
1187   if (handler)
1188     handler (fd, value);
1189
1190   if (fd_table[fd].dup_from == -1)
1191     {
1192       if (fd_table[fd].handle != INVALID_HANDLE_VALUE)
1193         {
1194           if (!CloseHandle (fd_table[fd].handle))
1195             { 
1196               TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ());
1197               /* FIXME: Should translate the error code.  */
1198               gpg_err_set_errno (EIO);
1199               return TRACE_SYSRES (-1);
1200             }
1201         }
1202       else if (fd_table[fd].socket != INVALID_SOCKET)
1203         {
1204           if (closesocket (fd_table[fd].socket))
1205             { 
1206               TRACE_LOG1 ("closesocket failed: ec=%d", (int) WSAGetLastError ());
1207               /* FIXME: Should translate the error code.  */
1208               gpg_err_set_errno (EIO);
1209               return TRACE_SYSRES (-1);
1210             }
1211         }
1212       /* Nothing to do for RVIDs.  */
1213     }
1214
1215   release_fd (fd);
1216       
1217   return TRACE_SYSRES (0);
1218 }
1219
1220
1221 int
1222 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
1223                             void *value)
1224 {
1225   int i;
1226   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
1227               "close_handler=%p/%p", handler, value);
1228
1229   assert (fd != -1);
1230
1231   LOCK (notify_table_lock);
1232   for (i=0; i < DIM (notify_table); i++)
1233     if (notify_table[i].inuse && notify_table[i].fd == fd)
1234       break;
1235   if (i == DIM (notify_table))
1236     for (i = 0; i < DIM (notify_table); i++)
1237       if (!notify_table[i].inuse)
1238         break;
1239   if (i == DIM (notify_table))
1240     {
1241       UNLOCK (notify_table_lock);
1242       gpg_err_set_errno (EINVAL);
1243       return TRACE_SYSRES (-1);
1244     }
1245   notify_table[i].fd = fd;
1246   notify_table[i].handler = handler;
1247   notify_table[i].value = value;
1248   notify_table[i].inuse = 1;
1249   UNLOCK (notify_table_lock);
1250   return TRACE_SYSRES (0);
1251 }
1252
1253
1254 int
1255 _gpgme_io_set_nonblocking (int fd)
1256 {
1257   TRACE (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
1258   return 0;
1259 }
1260
1261
1262 #ifdef HAVE_W32CE_SYSTEM
1263 static char *
1264 build_commandline (char **argv, int fd0, int fd0_isnull,
1265                    int fd1, int fd1_isnull,
1266                    int fd2, int fd2_isnull)
1267 {
1268   int i, n;
1269   const char *s;
1270   char *buf, *p;
1271   char fdbuf[3*30];
1272
1273   p = fdbuf;
1274   *p = 0;
1275   
1276   if (fd0 != -1)
1277     {
1278       if (fd0_isnull)
1279         strcpy (p, "-&S0=null ");
1280       else
1281         snprintf (p, 25, "-&S0=%d ", fd_table[fd0].rvid);
1282       p += strlen (p);
1283     }
1284   if (fd1 != -1)
1285     {
1286       if (fd1_isnull)
1287         strcpy (p, "-&S1=null ");
1288       else
1289         snprintf (p, 25, "-&S1=%d ", fd_table[fd1].rvid);
1290       p += strlen (p);
1291     }
1292   if (fd2 != -1)
1293     {
1294       if (fd2_isnull)
1295         strcpy (p, "-&S2=null ");
1296       else
1297         snprintf (p, 25, "-&S2=%d ", fd_table[fd2].rvid);
1298       p += strlen (p);
1299     }
1300   strcpy (p, "-&S2=null ");
1301   p += strlen (p);
1302   
1303   n = strlen (fdbuf);
1304   for (i=0; (s = argv[i]); i++)
1305     {
1306       if (!i)
1307         continue; /* Ignore argv[0].  */
1308       n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting) */
1309       for (; *s; s++)
1310         if (*s == '\"')
1311           n++;  /* Need to double inner quotes.  */
1312     }
1313   n++;
1314   buf = p = malloc (n);
1315   if (! buf)
1316     return NULL;
1317
1318   p = stpcpy (p, fdbuf);
1319   for (i = 0; argv[i]; i++) 
1320     {
1321       if (!i)
1322         continue; /* Ignore argv[0].  */
1323       if (i > 1)
1324         p = stpcpy (p, " ");
1325
1326       if (! *argv[i]) /* Empty string. */
1327         p = stpcpy (p, "\"\"");
1328       else if (strpbrk (argv[i], " \t\n\v\f\""))
1329         {
1330           p = stpcpy (p, "\"");
1331           for (s = argv[i]; *s; s++)
1332             {
1333               *p++ = *s;
1334               if (*s == '\"')
1335                 *p++ = *s;
1336             }
1337           *p++ = '\"';
1338           *p = 0;
1339         }
1340       else
1341         p = stpcpy (p, argv[i]);
1342     }
1343
1344   return buf;  
1345 }
1346 #else
1347 static char *
1348 build_commandline (char **argv)
1349 {
1350   int i;
1351   int n = 0;
1352   char *buf;
1353   char *p;
1354   
1355   /* We have to quote some things because under Windows the program
1356      parses the commandline and does some unquoting.  We enclose the
1357      whole argument in double-quotes, and escape literal double-quotes
1358      as well as backslashes with a backslash.  We end up with a
1359      trailing space at the end of the line, but that is harmless.  */
1360   for (i = 0; argv[i]; i++)
1361     {
1362       p = argv[i];
1363       /* The leading double-quote.  */
1364       n++;
1365       while (*p)
1366         {
1367           /* An extra one for each literal that must be escaped.  */
1368           if (*p == '\\' || *p == '"')
1369             n++;
1370           n++;
1371           p++;
1372         }
1373       /* The trailing double-quote and the delimiter.  */
1374       n += 2;
1375     }
1376   /* And a trailing zero.  */
1377   n++;
1378
1379   buf = p = malloc (n);
1380   if (!buf)
1381     return NULL;
1382   for (i = 0; argv[i]; i++)
1383     {
1384       char *argvp = argv[i];
1385
1386       *(p++) = '"';
1387       while (*argvp)
1388         {
1389           if (*argvp == '\\' || *argvp == '"')
1390             *(p++) = '\\';
1391           *(p++) = *(argvp++);
1392         }
1393       *(p++) = '"';
1394       *(p++) = ' ';
1395     }
1396   *(p++) = 0;
1397
1398   return buf;
1399 }
1400 #endif
1401
1402
1403 int
1404 _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
1405                  struct spawn_fd_item_s *fd_list,
1406                  void (*atfork) (void *opaque, int reserved),
1407                  void *atforkvalue, pid_t *r_pid)
1408 {
1409   PROCESS_INFORMATION pi =
1410     {
1411       NULL,      /* returns process handle */
1412       0,         /* returns primary thread handle */
1413       0,         /* returns pid */
1414       0          /* returns tid */
1415     };
1416   int i;
1417
1418 #ifdef HAVE_W32CE_SYSTEM
1419   int fd_in = -1;
1420   int fd_out = -1;
1421   int fd_err = -1;
1422   int fd_in_isnull = 1;
1423   int fd_out_isnull = 1;
1424   int fd_err_isnull = 1;
1425   char *cmdline;
1426   HANDLE hd = INVALID_HANDLE_VALUE;
1427
1428   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1429               "path=%s", path);
1430   i = 0;
1431   while (argv[i])
1432     {
1433       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1434       i++;
1435     }
1436
1437   for (i = 0; fd_list[i].fd != -1; i++)
1438     {
1439       int fd = fd_list[i].fd;
1440
1441       TRACE_LOG3 ("fd_list[%2i] = fd %i, dup_to %i", i, fd, fd_list[i].dup_to);
1442       if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1443         {
1444           TRACE_LOG1 ("invalid fd 0x%x", fd);
1445           gpg_err_set_errno (EBADF);
1446           return TRACE_SYSRES (-1);
1447         }
1448       if (fd_table[fd].rvid == 0)
1449         {
1450           TRACE_LOG1 ("fd 0x%x not inheritable (not an RVID)", fd);
1451           gpg_err_set_errno (EBADF);
1452           return TRACE_SYSRES (-1);
1453         }
1454       
1455       if (fd_list[i].dup_to == 0)
1456         {
1457           fd_in = fd_list[i].fd;
1458           fd_in_isnull = 0;
1459         }
1460       else if (fd_list[i].dup_to == 1)
1461         {
1462           fd_out = fd_list[i].fd;
1463           fd_out_isnull = 0;
1464         }
1465       else if (fd_list[i].dup_to == 2)
1466         {
1467           fd_err = fd_list[i].fd;
1468           fd_err_isnull = 0;
1469         }
1470     }
1471
1472   cmdline = build_commandline (argv, fd_in, fd_in_isnull,
1473                                fd_out, fd_out_isnull, fd_err, fd_err_isnull);
1474   if (!cmdline)
1475     {
1476       TRACE_LOG1 ("build_commandline failed: %s", strerror (errno));
1477       return TRACE_SYSRES (-1);
1478     }
1479
1480   if (!CreateProcessA (path,                /* Program to start.  */
1481                        cmdline,             /* Command line arguments.  */
1482                        NULL,                 /* (not supported)  */
1483                        NULL,                 /* (not supported)  */
1484                        FALSE,                /* (not supported)  */
1485                        (CREATE_SUSPENDED),   /* Creation flags.  */
1486                        NULL,                 /* (not supported)  */
1487                        NULL,                 /* (not supported)  */
1488                        NULL,                 /* (not supported) */
1489                        &pi                   /* Returns process information.*/
1490                        ))
1491     {
1492       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1493       free (cmdline);
1494       gpg_err_set_errno (EIO);
1495       return TRACE_SYSRES (-1);
1496     }
1497
1498   /* Create arbitrary pipe descriptor to send in ASSIGN_RVID
1499      commands.  Errors are ignored.  We don't need read or write access,
1500      as ASSIGN_RVID works without any permissions, yay!  */
1501   hd = CreateFile (L"GPG1:", 0, 0,
1502                    NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1503   if (hd == INVALID_HANDLE_VALUE)
1504     {
1505       TRACE_LOG1 ("CreateFile failed (ignored): ec=%d",
1506                   (int) GetLastError ());
1507     }
1508
1509   /* Insert the inherited handles.  */
1510   for (i = 0; fd_list[i].fd != -1; i++)
1511     {
1512       /* Return the child name of this handle.  */
1513       fd_list[i].peer_name = fd_table[fd_list[i].fd].rvid;
1514
1515       if (hd != INVALID_HANDLE_VALUE)
1516         {
1517           DWORD data[2];
1518           data[0] = (DWORD) fd_table[fd_list[i].fd].rvid;
1519           data[1] = pi.dwProcessId;
1520           if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_ASSIGN_RVID,
1521                                 data, sizeof (data), NULL, 0, NULL, NULL))
1522             {
1523               TRACE_LOG3 ("ASSIGN_RVID(%i, %i) failed (ignored): %i",
1524                           data[0], data[1], (int) GetLastError ());
1525             }
1526         }
1527     }
1528   if (hd != INVALID_HANDLE_VALUE)
1529     CloseHandle (hd);
1530
1531 #else
1532   SECURITY_ATTRIBUTES sec_attr;
1533   STARTUPINFOA si;
1534   int cr_flags = CREATE_DEFAULT_ERROR_MODE;
1535   char **args;
1536   char *arg_string;
1537   /* FIXME.  */
1538   int debug_me = 0;
1539   int tmp_fd;
1540   char *tmp_name;
1541
1542   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1543               "path=%s", path);
1544   i = 0;
1545   while (argv[i])
1546     {
1547       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1548       i++;
1549     }
1550
1551   /* We do not inherit any handles by default, and just insert those
1552      handles we want the child to have afterwards.  But some handle
1553      values occur on the command line, and we need to move
1554      stdin/out/err to the right location.  So we use a wrapper program
1555      which gets the information from a temporary file.  */
1556   if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
1557     {
1558       TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
1559       return TRACE_SYSRES (-1);
1560     }
1561   TRACE_LOG1 ("tmp_name = %s", tmp_name);
1562
1563   args = calloc (2 + i + 1, sizeof (*args));
1564   args[0] = (char *) _gpgme_get_w32spawn_path ();
1565   args[1] = tmp_name;
1566   args[2] = path;
1567   memcpy (&args[3], &argv[1], i * sizeof (*args));
1568
1569   memset (&sec_attr, 0, sizeof sec_attr);
1570   sec_attr.nLength = sizeof sec_attr;
1571   sec_attr.bInheritHandle = FALSE;
1572  
1573   arg_string = build_commandline (args);
1574   free (args);
1575   if (!arg_string)
1576     {
1577       close (tmp_fd);
1578       DeleteFileA (tmp_name);
1579       return TRACE_SYSRES (-1);
1580     }
1581
1582   memset (&si, 0, sizeof si);
1583   si.cb = sizeof (si);
1584   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1585   si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
1586   si.hStdInput = INVALID_HANDLE_VALUE;
1587   si.hStdOutput = INVALID_HANDLE_VALUE;
1588   si.hStdError = INVALID_HANDLE_VALUE;
1589
1590   cr_flags |= CREATE_SUSPENDED; 
1591 #ifndef HAVE_W32CE_SYSTEM
1592   cr_flags |= DETACHED_PROCESS;
1593   cr_flags |= GetPriorityClass (GetCurrentProcess ());
1594 #endif
1595   if (!CreateProcessA (_gpgme_get_w32spawn_path (),
1596                        arg_string,
1597                        &sec_attr,     /* process security attributes */
1598                        &sec_attr,     /* thread security attributes */
1599                        FALSE,         /* inherit handles */
1600                        cr_flags,      /* creation flags */
1601                        NULL,          /* environment */
1602                        NULL,          /* use current drive/directory */
1603                        &si,           /* startup information */
1604                        &pi))          /* returns process information */
1605     {
1606       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1607       free (arg_string);
1608       close (tmp_fd);
1609       DeleteFileA (tmp_name);
1610
1611       /* FIXME: Should translate the error code.  */
1612       gpg_err_set_errno (EIO);
1613       return TRACE_SYSRES (-1);
1614     }
1615
1616   free (arg_string);
1617
1618   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
1619     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
1620
1621   /* Insert the inherited handles.  */
1622   for (i = 0; fd_list[i].fd != -1; i++)
1623     {
1624       HANDLE hd;
1625
1626       /* Make it inheritable for the wrapper process.  */
1627       if (!DuplicateHandle (GetCurrentProcess(), fd_to_handle (fd_list[i].fd),
1628                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
1629         {
1630           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
1631           TerminateProcess (pi.hProcess, 0);
1632           /* Just in case TerminateProcess didn't work, let the
1633              process fail on its own.  */
1634           ResumeThread (pi.hThread);
1635           CloseHandle (pi.hThread);
1636           CloseHandle (pi.hProcess);
1637
1638           close (tmp_fd);
1639           DeleteFileA (tmp_name);
1640
1641           /* FIXME: Should translate the error code.  */
1642           gpg_err_set_errno (EIO);
1643           return TRACE_SYSRES (-1);
1644         }
1645       /* Return the child name of this handle.  */
1646       fd_list[i].peer_name = handle_to_fd (hd);
1647     }
1648   
1649   /* Write the handle translation information to the temporary
1650      file.  */
1651   {
1652     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
1653        notation: "0xFEDCBA9876543210" with an extra white space after
1654        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
1655        for a time when a HANDLE is 64 bit.  */
1656 #define BUFFER_MAX 810
1657     char line[BUFFER_MAX + 1];
1658     int res;
1659     int written;
1660     size_t len;
1661
1662     if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
1663       strcpy (line, "~1 \n");
1664     else
1665       strcpy (line, "\n");
1666     for (i = 0; fd_list[i].fd != -1; i++)
1667       {
1668         /* Strip the newline.  */
1669         len = strlen (line) - 1;
1670         
1671         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
1672         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
1673                   fd_list[i].fd, fd_list[i].dup_to,
1674                   fd_list[i].peer_name, fd_list[i].arg_loc);
1675         /* Rather safe than sorry.  */
1676         line[BUFFER_MAX - 1] = '\n';
1677         line[BUFFER_MAX] = '\0';
1678       }
1679     len = strlen (line);
1680     written = 0;
1681     do
1682       {
1683         res = write (tmp_fd, &line[written], len - written);
1684         if (res > 0)
1685           written += res;
1686       }
1687     while (res > 0 || (res < 0 && errno == EAGAIN));
1688   }
1689   close (tmp_fd);
1690   /* The temporary file is deleted by the gpgme-w32spawn process
1691      (hopefully).  */
1692 #endif
1693
1694
1695   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
1696               "dwProcessID=%d, dwThreadId=%d",
1697               pi.hProcess, pi.hThread, 
1698               (int) pi.dwProcessId, (int) pi.dwThreadId);
1699   
1700   if (r_pid)
1701     *r_pid = (pid_t)pi.dwProcessId;
1702
1703   
1704   if (ResumeThread (pi.hThread) < 0)
1705     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
1706   
1707   if (!CloseHandle (pi.hThread))
1708     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
1709                 (int) GetLastError ());
1710
1711   TRACE_LOG1 ("process=%p", pi.hProcess);
1712
1713   /* We don't need to wait for the process.  */
1714   if (!CloseHandle (pi.hProcess))
1715     TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
1716                 (int) GetLastError ());
1717
1718   if (! (flags & IOSPAWN_FLAG_NOCLOSE))
1719     {
1720       for (i = 0; fd_list[i].fd != -1; i++)
1721         _gpgme_io_close (fd_list[i].fd);
1722     }
1723
1724   for (i = 0; fd_list[i].fd != -1; i++)
1725     if (fd_list[i].dup_to == -1)
1726       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
1727                   fd_list[i].peer_name);
1728     else
1729       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
1730                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
1731                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
1732
1733   return TRACE_SYSRES (0);
1734 }
1735
1736
1737 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
1738    nothing to select, > 0 = number of signaled fds.  */
1739 int
1740 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
1741 {
1742   HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1743   int waitidx[MAXIMUM_WAIT_OBJECTS];
1744   int code;
1745   int nwait;
1746   int i;
1747   int any;
1748   int count;
1749   void *dbg_help;
1750   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
1751               "nfds=%u, nonblock=%u", nfds, nonblock);
1752
1753  restart:
1754   TRACE_SEQ (dbg_help, "select on [ ");
1755   any = 0;
1756   nwait = 0;
1757   count = 0;
1758   for (i=0; i < nfds; i++)
1759     {
1760       if (fds[i].fd == -1)
1761         continue;
1762       fds[i].signaled = 0;
1763       if (fds[i].for_read || fds[i].for_write)
1764         {
1765           if (fds[i].for_read)
1766             {
1767               struct reader_context_s *ctx = find_reader (fds[i].fd,1);
1768               
1769               if (!ctx)
1770                 TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
1771                             fds[i].fd);
1772               else
1773                 {
1774                   if (nwait >= DIM (waitbuf))
1775                     {
1776                       TRACE_END (dbg_help, "oops ]");
1777                       TRACE_LOG ("Too many objects for WFMO!");
1778                       /* FIXME: Should translate the error code.  */
1779                       gpg_err_set_errno (EIO);
1780                       return TRACE_SYSRES (-1);
1781                     }
1782                   waitidx[nwait] = i;
1783                   waitbuf[nwait++] = ctx->have_data_ev;
1784                 }
1785               TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
1786               any = 1;
1787             }
1788           else if (fds[i].for_write)
1789             {
1790               struct writer_context_s *ctx = find_writer (fds[i].fd,1);
1791               
1792               if (!ctx)
1793                 TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
1794                             fds[i].fd);
1795               else
1796                 {
1797                   if (nwait >= DIM (waitbuf))
1798                     {
1799                       TRACE_END (dbg_help, "oops ]");
1800                       TRACE_LOG ("Too many objects for WFMO!");
1801                       /* FIXME: Should translate the error code.  */
1802                       gpg_err_set_errno (EIO);
1803                       return TRACE_SYSRES (-1);
1804                     }
1805                   waitidx[nwait] = i;
1806                   waitbuf[nwait++] = ctx->is_empty;
1807                 }
1808               TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
1809               any = 1;
1810             }
1811         }
1812     }
1813   TRACE_END (dbg_help, "]");
1814   if (!any) 
1815     return TRACE_SYSRES (0);
1816
1817   code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
1818   if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
1819     {
1820       /* This WFMO is a really silly function: It does return either
1821          the index of the signaled object or if 2 objects have been
1822          signalled at the same time, the index of the object with the
1823          lowest object is returned - so and how do we find out how
1824          many objects have been signaled???.  The only solution I can
1825          imagine is to test each object starting with the returned
1826          index individually - how dull.  */
1827       any = 0;
1828       for (i = code - WAIT_OBJECT_0; i < nwait; i++)
1829         {
1830           if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
1831             {
1832               assert (waitidx[i] >=0 && waitidx[i] < nfds);
1833               fds[waitidx[i]].signaled = 1;
1834               any = 1;
1835               count++;
1836             }
1837         }
1838       if (!any)
1839         {
1840           TRACE_LOG ("no signaled objects found after WFMO");
1841           count = -1;
1842         }
1843     }
1844   else if (code == WAIT_TIMEOUT)
1845     TRACE_LOG ("WFMO timed out");
1846   else if (code == WAIT_FAILED)
1847     {
1848       int le = (int) GetLastError ();
1849 #if 0
1850       if (le == ERROR_INVALID_HANDLE)
1851         {
1852           int k;
1853           int j = handle_to_fd (waitbuf[i]);
1854           
1855           TRACE_LOG1 ("WFMO invalid handle %d removed", j);
1856           for (k = 0 ; k < nfds; k++)
1857             {
1858               if (fds[k].fd == j)
1859                 {
1860                   fds[k].for_read = fds[k].for_write = 0;
1861                   goto restart;
1862                 }
1863             }
1864           TRACE_LOG (" oops, or not???");
1865         }
1866 #endif
1867       TRACE_LOG1 ("WFMO failed: %d", le);
1868       count = -1;
1869     }
1870   else
1871     {
1872       TRACE_LOG1 ("WFMO returned %d", code);
1873       count = -1;
1874     }
1875   
1876   if (count > 0)
1877     {
1878       TRACE_SEQ (dbg_help, "select OK [ ");
1879       for (i = 0; i < nfds; i++)
1880         {
1881           if (fds[i].fd == -1)
1882             continue;
1883           if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
1884             TRACE_ADD2 (dbg_help, "%c0x%x ",
1885                         fds[i].for_read ? 'r' : 'w', fds[i].fd);
1886         }
1887       TRACE_END (dbg_help, "]");
1888     }
1889
1890   if (count < 0)
1891     {
1892       /* FIXME: Should determine a proper error code.  */
1893       gpg_err_set_errno (EIO);
1894     }
1895   
1896   return TRACE_SYSRES (count);
1897 }
1898
1899
1900 void
1901 _gpgme_io_subsystem_init (void)
1902 {
1903   /* Nothing to do.  */
1904 }
1905
1906
1907 /* Write the printable version of FD to the buffer BUF of length
1908    BUFLEN.  The printable version is the representation on the command
1909    line that the child process expects.  */
1910 int
1911 _gpgme_io_fd2str (char *buf, int buflen, int fd)
1912 {
1913 #ifdef HAVE_W32CE_SYSTEM
1914   /* FIXME: For now. See above.  */
1915   if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used
1916       || fd_table[fd].rvid == 0)
1917     fd = -1;
1918   else
1919     fd = fd_table[fd].rvid;
1920 #endif
1921
1922   return snprintf (buf, buflen, "%d", fd);
1923 }
1924
1925
1926 int
1927 _gpgme_io_dup (int fd)
1928 {
1929   int newfd;
1930   struct reader_context_s *rd_ctx;
1931   struct writer_context_s *wt_ctx;
1932   int i;
1933
1934   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
1935
1936   if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
1937     {
1938       gpg_err_set_errno (EINVAL);
1939       return TRACE_SYSRES (-1);
1940     }
1941
1942   newfd = new_fd();
1943   if (newfd == -1)
1944     return TRACE_SYSRES (-1);
1945   
1946   fd_table[newfd].handle = fd_table[fd].handle;
1947   fd_table[newfd].socket = fd_table[fd].socket;
1948   fd_table[newfd].rvid = fd_table[fd].rvid;
1949   fd_table[newfd].dup_from = fd;
1950
1951   rd_ctx = find_reader (fd, 1);
1952   if (rd_ctx)
1953     {
1954       /* No need for locking, as the only races are against the reader
1955          thread itself, which doesn't touch refcount.  */
1956       rd_ctx->refcount++;
1957
1958       LOCK (reader_table_lock);
1959       for (i = 0; i < reader_table_size; i++)
1960         if (!reader_table[i].used)
1961           break;
1962       /* FIXME.  */
1963       assert (i != reader_table_size);
1964       reader_table[i].fd = newfd;
1965       reader_table[i].context = rd_ctx;
1966       reader_table[i].used = 1;
1967       UNLOCK (reader_table_lock);
1968     }
1969
1970   wt_ctx = find_writer (fd, 1);
1971   if (wt_ctx)
1972     {
1973       /* No need for locking, as the only races are against the writer
1974          thread itself, which doesn't touch refcount.  */
1975       wt_ctx->refcount++;
1976
1977       LOCK (writer_table_lock);
1978       for (i = 0; i < writer_table_size; i++)
1979         if (!writer_table[i].used)
1980           break;
1981       /* FIXME.  */
1982       assert (i != writer_table_size);
1983       writer_table[i].fd = newfd;
1984       writer_table[i].context = wt_ctx;
1985       writer_table[i].used = 1;
1986       UNLOCK (writer_table_lock);
1987     }
1988
1989   return TRACE_SYSRES (newfd);
1990 }
1991
1992 \f
1993 /* The following interface is only useful for GPGME Glib and Qt.  */
1994
1995 /* Compatibility interface, obsolete.  */
1996 void *
1997 gpgme_get_giochannel (int fd)
1998 {
1999   return NULL;
2000 }
2001
2002
2003 /* Look up the giochannel or qiodevice for file descriptor FD.  */
2004 void *
2005 gpgme_get_fdptr (int fd)
2006 {
2007   return NULL;
2008 }
2009
2010 \f
2011 static int
2012 wsa2errno (int err)
2013 {
2014   switch (err)
2015     {
2016     case WSAENOTSOCK:
2017       return EINVAL;
2018     case WSAEWOULDBLOCK:
2019       return EAGAIN;
2020     case ERROR_BROKEN_PIPE:
2021       return EPIPE;
2022     case WSANOTINITIALISED:
2023       return ENOSYS;
2024     default:
2025       return EIO;
2026     }
2027 }
2028
2029
2030 int
2031 _gpgme_io_socket (int domain, int type, int proto)
2032 {
2033   int res;
2034   int fd;
2035
2036   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
2037               "type=%i, protp=%i", type, proto);
2038
2039   fd = new_fd();
2040   if (fd == -1)
2041     return TRACE_SYSRES (-1);
2042       
2043   res = socket (domain, type, proto);
2044   if (res == INVALID_SOCKET)
2045     {
2046       release_fd (fd);
2047       gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2048       return TRACE_SYSRES (-1);
2049     }
2050   fd_table[fd].socket = res;
2051
2052   TRACE_SUC2 ("socket=0x%x (0x%x)", fd, fd_table[fd].socket);
2053   
2054   return res;
2055 }
2056
2057
2058 int
2059 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
2060 {
2061   int res;
2062
2063   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
2064               "addr=%p, addrlen=%i", addr, addrlen);
2065
2066   if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
2067     {
2068       gpg_err_set_errno (EBADF);
2069       return TRACE_SYSRES (-1);
2070     }
2071     
2072   res = connect (fd_table[fd].socket, addr, addrlen);
2073   if (res)
2074     {
2075       gpg_err_set_errno (wsa2errno (WSAGetLastError ()));
2076       return TRACE_SYSRES (-1);
2077     }
2078
2079   return TRACE_SUC ();
2080 }