2010-05-06 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / src / w32-glib-io.c
1 /* w32-glib-io.c - W32 Glib I/O functions
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2004, 2005 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 <unistd.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <glib.h>
35 #include <windows.h>
36 #include <io.h>
37
38 #include "util.h"
39 #include "priv-io.h"
40 #include "sema.h"
41 #include "debug.h"
42
43 #ifndef O_BINARY
44 #ifdef _O_BINARY
45 #define O_BINARY        _O_BINARY
46 #else
47 #define O_BINARY        0
48 #endif
49 #endif
50
51 \f
52 /* This file is an ugly hack to get GPGME working with glib on Windows
53    targets.  On Windows, you can not select() on file descriptors.
54    The only way to check if there is something to read is to read
55    something.  This means that GPGME can not let glib check for data
56    without letting glib also handle the data on Windows targets.
57
58    The ugly consequence is that we need to work on GIOChannels in
59    GPGME, creating a glib dependency.  Also, we need to export an
60    interface for the application to get at GPGME's GIOChannel.  There
61    is no good way to abstract all this with callbacks, because the
62    whole thing is also interconnected with the creation of pipes and
63    child processes.
64
65    The following rule applies only to this I/O backend:
66
67    * ALL operations must use the user defined event loop.  GPGME can
68    not anymore provide its own event loop.  This is mostly a sanity
69    requirement: Although we have in theory all information we need to
70    make the GPGME W32 code for select still work, it would be a big
71    complication and require changes throughout GPGME.
72
73    Eventually, we probably have to bite the bullet and make some
74    really nice callback interfaces to let the user control all this at
75    a per-context level.  */
76
77 \f
78 #define MAX_SLAFD 256
79
80 static struct 
81 {
82   int used;
83
84   /* If this is not -1, then it's a libc file descriptor.  */
85   int fd;
86   /* If fd is -1, this is the Windows socket handle.  */
87   int socket;
88
89   GIOChannel *chan;
90   /* The boolean PRIMARY is true if this file descriptor caused the
91      allocation of CHAN.  Only then should CHAN be destroyed when this
92      FD is closed.  This, together with the fact that dup'ed file
93      descriptors are closed before the file descriptors from which
94      they are dup'ed are closed, ensures that CHAN is always valid,
95      and shared among all file descriptors refering to the same
96      underlying object.
97
98      The logic behind this is that there is only one reason for us to
99      dup file descriptors anyway: to allow simpler book-keeping of
100      file descriptors shared between GPGME and libassuan, which both
101      want to close something.  Using the same channel for these
102      duplicates works just fine (and in fact, using different channels
103      does not work because the W32 backend in glib does not support
104      that: One would end up with several competing reader/writer
105      threads.  */
106   int primary;
107 } giochannel_table[MAX_SLAFD];
108
109
110 static GIOChannel *
111 find_channel (int fd)
112 {
113   if (fd < 0 || fd >= MAX_SLAFD)
114     return NULL;
115
116   return giochannel_table[fd].chan;
117 }
118
119
120 /* Returns the FD or -1 on resource limit.  */
121 int
122 new_dummy_channel_from_fd (int cfd)
123 {
124   int idx;
125
126   for (idx = 0; idx < MAX_SLAFD; idx++)
127     if (! giochannel_table[idx].used)
128       break;
129
130   if (idx == MAX_SLAFD)
131     {
132       errno = EIO;
133       return -1;
134     }
135
136   giochannel_table[idx].used = 1;
137   giochannel_table[idx].chan = NULL;
138   giochannel_table[idx].fd = cfd;
139   giochannel_table[idx].socket = INVALID_SOCKET;
140   giochannel_table[idx].primary = 1;
141
142   return idx;
143 }
144
145
146 /* Returns the FD or -1 on resource limit.  */
147 int
148 new_channel_from_fd (int cfd)
149 {
150   int idx;
151
152   for (idx = 0; idx < MAX_SLAFD; idx++)
153     if (! giochannel_table[idx].used)
154       break;
155
156   if (idx == MAX_SLAFD)
157     {
158       errno = EIO;
159       return -1;
160     }
161
162   giochannel_table[idx].used = 1;
163   giochannel_table[idx].chan = g_io_channel_win32_new_fd (cfd);
164   giochannel_table[idx].fd = cfd;
165   giochannel_table[idx].socket = INVALID_SOCKET;
166   giochannel_table[idx].primary = 1;
167
168   g_io_channel_set_encoding (giochannel_table[idx].chan, NULL, NULL);
169   g_io_channel_set_buffered (giochannel_table[idx].chan, FALSE);
170
171   return idx;
172 }
173
174
175 /* Returns the FD or -1 on resource limit.  */
176 int
177 new_channel_from_socket (int sock)
178 {
179   int idx;
180
181   for (idx = 0; idx < MAX_SLAFD; idx++)
182     if (! giochannel_table[idx].used)
183       break;
184
185   if (idx == MAX_SLAFD)
186     {
187       errno = EIO;
188       return -1;
189     }
190
191   giochannel_table[idx].used = 1;
192   giochannel_table[idx].chan = g_io_channel_win32_new_socket (sock);
193   giochannel_table[idx].fd = -1;
194   giochannel_table[idx].socket = sock;
195   giochannel_table[idx].primary = 1;
196
197   g_io_channel_set_encoding (giochannel_table[idx].chan, NULL, NULL);
198   g_io_channel_set_buffered (giochannel_table[idx].chan, FALSE);
199
200   return idx;
201 }
202
203
204 /* Compatibility interface.  Obsolete.  */
205 void *
206 gpgme_get_giochannel (int fd)
207 {
208   return find_channel (fd);
209 }
210
211
212 /* Look up the giochannel for "file descriptor" FD.  */
213 void *
214 gpgme_get_fdptr (int fd)
215 {
216   return find_channel (fd);
217 }
218
219
220 /* Write the printable version of FD to the buffer BUF of length
221    BUFLEN.  The printable version is the representation on the command
222    line that the child process expects.  */
223 int
224 _gpgme_io_fd2str (char *buf, int buflen, int fd)
225 {
226   HANDLE hndl;
227     
228   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_fd2str", fd, "fd=%d", fd);
229   if (giochannel_table[fd].fd != -1)
230     hndl = (HANDLE) _get_osfhandle (giochannel_table[fd].fd);
231   else
232     hndl = (HANDLE) giochannel_table[fd].socket;
233
234   TRACE_SUC1 ("syshd=%p", hndl);
235   
236   return snprintf (buf, buflen, "%d", (int) hndl);
237 }
238
239 \f
240 void
241 _gpgme_io_subsystem_init (void)
242 {
243 }
244
245 \f
246 static struct
247 {
248   _gpgme_close_notify_handler_t handler;
249   void *value;
250 } notify_table[MAX_SLAFD];
251
252
253 int
254 _gpgme_io_read (int fd, void *buffer, size_t count)
255 {
256   int saved_errno = 0;
257   gsize nread;
258   GIOChannel *chan;
259   GIOStatus status;
260   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
261               "buffer=%p, count=%u", buffer, count);
262
263   chan = find_channel (fd);
264   if (!chan)
265     {
266       TRACE_LOG ("no channel registered");
267       errno = EINVAL;
268       return TRACE_SYSRES (-1);
269     }
270   TRACE_LOG1 ("channel %p", chan);
271
272   {
273     GError *err = NULL;
274     status = g_io_channel_read_chars (chan, (gchar *) buffer,
275                                       count, &nread, &err);
276     if (err)
277       {
278         TRACE_LOG2 ("status %i, err %s", status, err->message);
279         g_error_free (err);
280       }
281   }
282
283   if (status == G_IO_STATUS_EOF)
284     nread = 0;
285   else if (status == G_IO_STATUS_AGAIN)
286     {
287       nread = -1;
288       saved_errno = EAGAIN;
289     }
290   else if (status != G_IO_STATUS_NORMAL)
291     {
292       TRACE_LOG1 ("status %d", status);
293       nread = -1;
294       saved_errno = EIO;
295     }
296   
297   if (nread != 0 && nread != -1)
298     TRACE_LOGBUF (buffer, nread);
299
300   errno = saved_errno;
301   return TRACE_SYSRES (nread);
302 }
303
304
305 int
306 _gpgme_io_write (int fd, const void *buffer, size_t count)
307 {
308   int saved_errno = 0;
309   gsize nwritten;
310   GIOChannel *chan;
311   GIOStatus status;
312   GError *err = NULL;
313
314   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
315               "buffer=%p, count=%u", buffer, count);
316   TRACE_LOGBUF (buffer, count);
317
318   chan = find_channel (fd);
319   if (!chan)
320     {
321       TRACE_LOG ("fd %d: no channel registered");
322       errno = EINVAL;
323       return -1;
324     }
325
326   status = g_io_channel_write_chars (chan, (gchar *) buffer, count,
327                                      &nwritten, &err);
328   if (err)
329     {
330       TRACE_LOG1 ("write error: %s", err->message);
331       g_error_free (err);
332     }
333
334   if (status == G_IO_STATUS_AGAIN)
335     {
336       nwritten = -1;
337       saved_errno = EAGAIN;
338     }
339   else if (status != G_IO_STATUS_NORMAL)
340     {
341       nwritten = -1;
342       saved_errno = EIO;
343     }
344   errno = saved_errno;
345
346   return TRACE_SYSRES (nwritten);
347 }
348
349
350 int
351 _gpgme_io_pipe (int filedes[2], int inherit_idx)
352 {
353   int fds[2];
354
355   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
356               "inherit_idx=%i (GPGME uses it for %s)",
357               inherit_idx, inherit_idx ? "reading" : "writing");
358
359 #define PIPEBUF_SIZE  4096
360   if (_pipe (fds, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
361     return TRACE_SYSRES (-1);
362
363   /* Make one end inheritable. */
364   if (inherit_idx == 0)
365     {
366       int new_read;
367
368       new_read = _dup (fds[0]);
369       _close (fds[0]);
370       fds[0] = new_read;
371
372       if (new_read < 0)
373         {
374           _close (fds[1]);
375           return TRACE_SYSRES (-1);
376         }
377     }
378   else if (inherit_idx == 1)
379     {
380       int new_write;
381
382       new_write = _dup (fds[1]);
383       _close (fds[1]);
384       fds[1] = new_write;
385
386       if (new_write < 0)
387         {
388           _close (fds[0]);
389           return TRACE_SYSRES (-1);
390         }
391     }
392
393   /* For _gpgme_io_close.  */
394   filedes[inherit_idx] = new_dummy_channel_from_fd (fds[inherit_idx]);
395   if (filedes[inherit_idx] < 0)
396     {
397       int saved_errno = errno;
398       
399       _close (fds[0]);
400       _close (fds[1]);
401       errno = saved_errno;
402       return TRACE_SYSRES (-1);
403     }
404
405   /* Now we have a pipe with the correct end inheritable.  The other end
406      should have a giochannel.  */
407   filedes[1 - inherit_idx] = new_channel_from_fd (fds[1 - inherit_idx]);
408   if (filedes[1 - inherit_idx] < 0)
409     {
410       int saved_errno = errno;
411       
412       _gpgme_io_close (fds[inherit_idx]);
413       _close (fds[1 - inherit_idx]);
414       errno = saved_errno;
415       return TRACE_SYSRES (-1);
416     }
417   
418   return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p",
419                      filedes[0],
420                      (HANDLE) _get_osfhandle (giochannel_table[filedes[0]].fd),
421                      filedes[1],
422                      (HANDLE) _get_osfhandle (giochannel_table[filedes[1]].fd),
423                      giochannel_table[1 - inherit_idx].chan);
424 }
425
426
427 int
428 _gpgme_io_close (int fd)
429 {
430   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
431
432   if (fd < 0 || fd >= MAX_SLAFD)
433     {
434       errno = EBADF;
435       return TRACE_SYSRES (-1);
436     }
437
438   assert (giochannel_table[fd].used);
439
440   /* First call the notify handler.  */
441   if (notify_table[fd].handler)
442     {
443       notify_table[fd].handler (fd, notify_table[fd].value);
444       notify_table[fd].handler = NULL;
445       notify_table[fd].value = NULL;
446     }
447
448   /* Then do the close.  */
449   if (giochannel_table[fd].chan)
450     {
451       if (giochannel_table[fd].primary)
452         g_io_channel_shutdown (giochannel_table[fd].chan, 1, NULL);
453       
454       g_io_channel_unref (giochannel_table[fd].chan);
455     }
456   else
457     {
458       /* Dummy entry, just close.  */
459       assert (giochannel_table[fd].fd != -1);
460       _close (giochannel_table[fd].fd);
461     }
462         
463   giochannel_table[fd].used = 0;
464   giochannel_table[fd].fd = -1;
465   giochannel_table[fd].socket = INVALID_SOCKET;
466   giochannel_table[fd].chan = NULL;
467   giochannel_table[fd].primary = 0;
468
469   TRACE_SUC ();
470   return 0;
471 }
472
473
474 int
475 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
476                             void *value)
477 {
478   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
479               "close_handler=%p/%p", handler, value);
480
481   assert (fd != -1);
482
483   if (fd < 0 || fd >= (int) DIM (notify_table))
484     {
485       errno = EINVAL;
486       return TRACE_SYSRES (-1);
487     }
488   notify_table[fd].handler = handler;
489   notify_table[fd].value = value;
490   return TRACE_SYSRES (0);
491 }
492
493
494 int
495 _gpgme_io_set_nonblocking (int fd)
496 {
497   GIOChannel *chan;
498   GIOStatus status;
499  
500   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
501
502   chan = find_channel (fd);
503   if (!chan)
504     {
505       errno = EIO;
506       return TRACE_SYSRES (-1);
507     }
508
509   status = g_io_channel_set_flags (chan,
510                                    g_io_channel_get_flags (chan) |
511                                    G_IO_FLAG_NONBLOCK, NULL);
512
513   if (status != G_IO_STATUS_NORMAL)
514     {
515 #if 0
516       /* glib 1.9.2 does not implement set_flags and returns an
517          error.  */
518       errno = EIO;
519       return TRACE_SYSRES (-1);
520 #else
521       TRACE_LOG1 ("g_io_channel_set_flags failed: status=%d (ignored)",
522                   status);
523 #endif
524     }
525
526   return TRACE_SYSRES (0);
527 }
528
529
530 static char *
531 build_commandline (char **argv)
532 {
533   int i;
534   int n = 0;
535   char *buf;
536   char *p;
537   
538   /* We have to quote some things because under Windows the program
539      parses the commandline and does some unquoting.  We enclose the
540      whole argument in double-quotes, and escape literal double-quotes
541      as well as backslashes with a backslash.  We end up with a
542      trailing space at the end of the line, but that is harmless.  */
543   for (i = 0; argv[i]; i++)
544     {
545       p = argv[i];
546       /* The leading double-quote.  */
547       n++;
548       while (*p)
549         {
550           /* An extra one for each literal that must be escaped.  */
551           if (*p == '\\' || *p == '"')
552             n++;
553           n++;
554           p++;
555         }
556       /* The trailing double-quote and the delimiter.  */
557       n += 2;
558     }
559   /* And a trailing zero.  */
560   n++;
561
562   buf = p = malloc (n);
563   if (!buf)
564     return NULL;
565   for (i = 0; argv[i]; i++)
566     {
567       char *argvp = argv[i];
568
569       *(p++) = '"';
570       while (*argvp)
571         {
572           if (*argvp == '\\' || *argvp == '"')
573             *(p++) = '\\';
574           *(p++) = *(argvp++);
575         }
576       *(p++) = '"';
577       *(p++) = ' ';
578     }
579   *(p++) = 0;
580
581   return buf;
582 }
583
584
585 int
586 _gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags,
587                  struct spawn_fd_item_s *fd_list,
588                  void (*atfork) (void *opaque, int reserved),
589                  void *atforkvalue, pid_t *r_pid)
590 {
591   SECURITY_ATTRIBUTES sec_attr;
592   PROCESS_INFORMATION pi =
593     {
594       NULL,      /* returns process handle */
595       0,         /* returns primary thread handle */
596       0,         /* returns pid */
597       0          /* returns tid */
598     };
599   STARTUPINFO si;
600   int cr_flags = (CREATE_DEFAULT_ERROR_MODE
601                   | GetPriorityClass (GetCurrentProcess ()));
602   int i;
603   char **args;
604   char *arg_string;
605   /* FIXME.  */
606   int debug_me = 0;
607   int tmp_fd;
608   char *tmp_name;
609
610   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
611               "path=%s", path);
612   i = 0;
613   while (argv[i])
614     {
615       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
616       i++;
617     }
618   
619   /* We do not inherit any handles by default, and just insert those
620      handles we want the child to have afterwards.  But some handle
621      values occur on the command line, and we need to move
622      stdin/out/err to the right location.  So we use a wrapper program
623      which gets the information from a temporary file.  */
624   if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
625     {
626       TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
627       return TRACE_SYSRES (-1);
628     }
629   TRACE_LOG1 ("tmp_name = %s", tmp_name);
630
631   args = calloc (2 + i + 1, sizeof (*args));
632   args[0] = (char *) _gpgme_get_w32spawn_path ();
633   args[1] = tmp_name;
634   args[2] = path;
635   memcpy (&args[3], &argv[1], i * sizeof (*args));
636
637   memset (&sec_attr, 0, sizeof sec_attr);
638   sec_attr.nLength = sizeof sec_attr;
639   sec_attr.bInheritHandle = FALSE;
640   
641   arg_string = build_commandline (args);
642   free (args);
643   if (!arg_string)
644     {
645       close (tmp_fd);
646       DeleteFile (tmp_name);
647       return TRACE_SYSRES (-1);
648     }
649
650   memset (&si, 0, sizeof si);
651   si.cb = sizeof (si);
652   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
653   si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
654   si.hStdInput = INVALID_HANDLE_VALUE;
655   si.hStdOutput = INVALID_HANDLE_VALUE;
656   si.hStdError = INVALID_HANDLE_VALUE;
657
658   cr_flags |= CREATE_SUSPENDED;
659   cr_flags |= DETACHED_PROCESS;
660   if (!CreateProcessA (_gpgme_get_w32spawn_path (),
661                        arg_string,
662                        &sec_attr,     /* process security attributes */
663                        &sec_attr,     /* thread security attributes */
664                        FALSE,         /* inherit handles */
665                        cr_flags,      /* creation flags */
666                        NULL,          /* environment */
667                        NULL,          /* use current drive/directory */
668                        &si,           /* startup information */
669                        &pi))          /* returns process information */
670     {
671       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
672       free (arg_string);
673       close (tmp_fd);
674       DeleteFile (tmp_name);
675
676       /* FIXME: Should translate the error code.  */
677       errno = EIO;
678       return TRACE_SYSRES (-1);
679     }
680
681   free (arg_string);
682   
683   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
684     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
685
686   /* Insert the inherited handles.  */
687   for (i = 0; fd_list[i].fd != -1; i++)
688     {
689       HANDLE hd;
690
691       /* Make it inheritable for the wrapper process.  */
692       if (!DuplicateHandle (GetCurrentProcess(),
693                             _get_osfhandle (giochannel_table[fd_list[i].fd].fd),
694                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
695         {
696           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
697           TerminateProcess (pi.hProcess, 0);
698           /* Just in case TerminateProcess didn't work, let the
699              process fail on its own.  */
700           ResumeThread (pi.hThread);
701           CloseHandle (pi.hThread);
702           CloseHandle (pi.hProcess);
703
704           close (tmp_fd);
705           DeleteFile (tmp_name);
706
707           /* FIXME: Should translate the error code.  */
708           errno = EIO;
709           return TRACE_SYSRES (-1);
710         }
711       /* Return the child name of this handle.  */
712       fd_list[i].peer_name = (int) hd;
713     }
714
715   /* Write the handle translation information to the temporary
716      file.  */
717   {
718     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
719        notation: "0xFEDCBA9876543210" with an extra white space after
720        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
721        for a time when a HANDLE is 64 bit.  */
722 #define BUFFER_MAX 800
723     char line[BUFFER_MAX + 1];
724     int res;
725     int written;
726     size_t len;
727
728     if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
729       strcpy (line, "~1 \n");
730     else
731       strcpy (line, "\n");
732     for (i = 0; fd_list[i].fd != -1; i++)
733       {
734         /* Strip the newline.  */
735         len = strlen (line) - 1;
736         
737         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
738         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
739                   fd_list[i].fd, fd_list[i].dup_to,
740                   fd_list[i].peer_name, fd_list[i].arg_loc);
741         /* Rather safe than sorry.  */
742         line[BUFFER_MAX - 1] = '\n';
743         line[BUFFER_MAX] = '\0';
744       }
745     len = strlen (line);
746     written = 0;
747     do
748       {
749         res = write (tmp_fd, &line[written], len - written);
750         if (res > 0)
751           written += res;
752       }
753     while (res > 0 || (res < 0 && errno == EAGAIN));
754   }
755   close (tmp_fd);
756   /* The temporary file is deleted by the gpgme-w32spawn process
757      (hopefully).  */
758     
759   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
760               "dwProcessID=%d, dwThreadId=%d",
761               pi.hProcess, pi.hThread, 
762               (int) pi.dwProcessId, (int) pi.dwThreadId);
763   
764   if (r_pid)
765     *r_pid = (pid_t)pi.dwProcessId;
766
767   if (ResumeThread (pi.hThread) < 0)
768     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
769   
770   if (!CloseHandle (pi.hThread))
771     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
772                 (int) GetLastError ());
773
774   TRACE_LOG1 ("process=%p", pi.hProcess);
775
776   /* We don't need to wait for the process.  */
777   if (!CloseHandle (pi.hProcess))
778     TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
779                 (int) GetLastError ());
780
781   if (! (flags & IOSPAWN_FLAG_NOCLOSE))
782     {
783       for (i = 0; fd_list[i].fd != -1; i++)
784         _gpgme_io_close (fd_list[i].fd);
785     }
786
787   for (i = 0; fd_list[i].fd != -1; i++)
788     if (fd_list[i].dup_to == -1)
789       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
790                   fd_list[i].peer_name);
791     else
792       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
793                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
794                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
795
796   return TRACE_SYSRES (0);
797 }
798
799
800 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
801    nothing to select, > 0 = number of signaled fds.  */
802 int
803 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
804 {
805   int npollfds;
806   GPollFD *pollfds;
807   int *pollfds_map; 
808   int i;
809   int j;
810   int any;
811   int n;
812   int count;
813   /* Use a 1s timeout.  */
814   int timeout = 1000;
815   void *dbg_help = NULL;
816   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
817               "nfds=%u, nonblock=%u", nfds, nonblock);
818
819   if (nonblock)
820     timeout = 0;
821
822   pollfds = calloc (nfds, sizeof *pollfds);
823   if (!pollfds)
824     return -1;
825   pollfds_map = calloc (nfds, sizeof *pollfds_map);
826   if (!pollfds_map)
827     {
828       free (pollfds);
829       return -1;
830     }
831   npollfds = 0;
832
833   TRACE_SEQ (dbg_help, "select on [ ");
834   any = 0;
835   for (i = 0; i < nfds; i++)
836     {
837       GIOChannel *chan = NULL;
838
839       if (fds[i].fd == -1) 
840         continue;
841
842       if ((fds[i].for_read || fds[i].for_write)
843           && !(chan = find_channel (fds[i].fd)))
844         {
845           TRACE_ADD1 (dbg_help, "[BAD0x%x ", fds[i].fd);
846           TRACE_END (dbg_help, "]"); 
847           assert (!"see log file");
848         }
849       else if (fds[i].for_read )
850         {
851           assert(chan);
852           g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds);
853           pollfds_map[npollfds] = i;
854           TRACE_ADD2 (dbg_help, "r0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
855           npollfds++;
856           any = 1;
857         }
858       else if (fds[i].for_write)
859         {
860           assert(chan);
861           g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds);
862           pollfds_map[npollfds] = i;
863           TRACE_ADD2 (dbg_help, "w0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
864           npollfds++;
865           any = 1;
866         }
867       fds[i].signaled = 0;
868     }
869   TRACE_END (dbg_help, "]"); 
870   if (!any)
871     {
872       count = 0;
873       goto leave;
874     }
875
876
877   count = g_io_channel_win32_poll (pollfds, npollfds, timeout);
878   if (count < 0)
879     {
880       int saved_errno = errno;
881       errno = saved_errno;
882       goto leave;
883     }
884
885   TRACE_SEQ (dbg_help, "select OK [ ");
886   if (TRACE_ENABLED (dbg_help))
887     {
888       for (i = 0; i < npollfds; i++)
889         {
890           if ((pollfds[i].revents & G_IO_IN))
891             TRACE_ADD1 (dbg_help, "r0x%x ", fds[pollfds_map[i]].fd);
892           if ((pollfds[i].revents & G_IO_OUT))
893             TRACE_ADD1 (dbg_help, "w0x%x ", fds[pollfds_map[i]].fd);
894         }
895       TRACE_END (dbg_help, "]");
896     }
897     
898   /* COUNT is used to stop the lop as soon as possible.  */
899   for (n = count, i = 0; i < npollfds && n; i++)
900     {
901       j = pollfds_map[i];
902       assert (j >= 0 && j < nfds);
903       if (fds[j].fd == -1)
904         ;
905       else if (fds[j].for_read)
906         {
907           if ((pollfds[i].revents & G_IO_IN))
908             {
909               fds[j].signaled = 1;
910               n--;
911             }
912         }
913       else if (fds[j].for_write)
914         {
915           if ((pollfds[i].revents & G_IO_OUT))
916             {
917               fds[j].signaled = 1;
918               n--;
919             }
920         }
921     }
922
923 leave:
924   free (pollfds);
925   free (pollfds_map);
926   return TRACE_SYSRES (count);
927 }
928
929
930 int
931 _gpgme_io_dup (int fd)
932 {
933   int newfd;
934   GIOChannel *chan;
935
936   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
937
938   if (fd < 0 || fd >= MAX_SLAFD || !giochannel_table[fd].used)
939     {
940       errno = EINVAL;
941       return TRACE_SYSRES (-1);
942     }
943
944   for (newfd = 0; newfd < MAX_SLAFD; newfd++)
945     if (! giochannel_table[newfd].used)
946       break;
947   if (newfd == MAX_SLAFD)
948     {
949       errno = EIO;
950       return TRACE_SYSRES (-1);
951     }
952   
953   chan = giochannel_table[fd].chan;
954   g_io_channel_ref (chan);
955   giochannel_table[newfd].used = 1;
956   giochannel_table[newfd].chan = chan;
957   giochannel_table[newfd].fd = -1;
958   giochannel_table[newfd].socket = INVALID_SOCKET;
959   giochannel_table[newfd].primary = 0;
960
961   return TRACE_SYSRES (newfd);
962 }
963
964 \f
965
966
967 \f
968 static int
969 wsa2errno (int err)
970 {
971   switch (err)
972     {
973     case WSAENOTSOCK:
974       return EINVAL;
975     case WSAEWOULDBLOCK:
976       return EAGAIN;
977     case ERROR_BROKEN_PIPE:
978       return EPIPE;
979     case WSANOTINITIALISED:
980       return ENOSYS;
981     default:
982       return EIO;
983     }
984 }
985
986
987 int
988 _gpgme_io_socket (int domain, int type, int proto)
989 {
990   int res;
991   int fd;
992
993   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
994               "type=%i, protp=%i", type, proto);
995
996   res = socket (domain, type, proto);
997   if (res == INVALID_SOCKET)
998     {
999       errno = wsa2errno (WSAGetLastError ());
1000       return TRACE_SYSRES (-1);
1001     }
1002
1003   fd = new_channel_from_socket (res);
1004   if (fd < 0)
1005     {
1006       int saved_errno = errno;
1007       closesocket (res);
1008       errno = saved_errno;
1009       return TRACE_SYSRES (-1);
1010     }
1011
1012   TRACE_SUC2 ("fd=%i, socket=0x%x", fd, res);
1013   
1014   return fd;
1015 }
1016
1017
1018 int
1019 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
1020 {
1021   GIOChannel *chan; 
1022   int sockfd;
1023   int res;
1024   GIOFlags flags;
1025   GIOStatus status;
1026   GError *err = NULL;
1027
1028   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
1029               "addr=%p, addrlen=%i", addr, addrlen);
1030
1031   chan = find_channel (fd);
1032   if (! chan)
1033     {
1034       errno = EINVAL;
1035       return TRACE_SYSRES (-1);
1036     }
1037
1038   flags = g_io_channel_get_flags (chan);
1039   if (flags & G_IO_FLAG_NONBLOCK)
1040     {
1041       status = g_io_channel_set_flags (chan, flags & ~G_IO_FLAG_NONBLOCK, &err);
1042       if (err)
1043         {
1044           TRACE_LOG1 ("setting flags error: %s", err->message);
1045           g_error_free (err);
1046           err = NULL;
1047         }
1048       if (status != G_IO_STATUS_NORMAL)
1049         {
1050           errno = EIO;
1051           return TRACE_SYSRES (-1);
1052         }
1053     }
1054
1055   sockfd = giochannel_table[fd].socket;
1056   if (sockfd == INVALID_SOCKET)
1057     {
1058       errno = EINVAL;
1059       return TRACE_SYSRES (-1);
1060     }
1061
1062   TRACE_LOG1 ("connect sockfd=0x%x", sockfd);
1063   res = connect (sockfd, addr, addrlen);
1064
1065   /* FIXME: Error ignored here.  */
1066   if (! (flags & G_IO_FLAG_NONBLOCK))
1067     g_io_channel_set_flags (chan, flags, NULL);
1068
1069   if (res)
1070     {
1071       TRACE_LOG2 ("connect failed: %i %i", res, WSAGetLastError ());
1072
1073       errno = wsa2errno (WSAGetLastError ());
1074       return TRACE_SYSRES (-1);
1075     }
1076
1077   return TRACE_SUC ();
1078 }