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