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