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