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