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