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