Improved W32 SetForegroundWindow hacks.
[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[], unsigned int flags,
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   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
683     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
684
685   /* Insert the inherited handles.  */
686   for (i = 0; fd_list[i].fd != -1; i++)
687     {
688       HANDLE hd;
689
690       /* Make it inheritable for the wrapper process.  */
691       if (!DuplicateHandle (GetCurrentProcess(),
692                             _get_osfhandle (giochannel_table[fd_list[i].fd].fd),
693                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
694         {
695           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
696           TerminateProcess (pi.hProcess, 0);
697           /* Just in case TerminateProcess didn't work, let the
698              process fail on its own.  */
699           ResumeThread (pi.hThread);
700           CloseHandle (pi.hThread);
701           CloseHandle (pi.hProcess);
702
703           close (tmp_fd);
704           DeleteFile (tmp_name);
705
706           /* FIXME: Should translate the error code.  */
707           errno = EIO;
708           return TRACE_SYSRES (-1);
709         }
710       /* Return the child name of this handle.  */
711       fd_list[i].peer_name = (int) hd;
712     }
713
714   /* Write the handle translation information to the temporary
715      file.  */
716   {
717     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
718        notation: "0xFEDCBA9876543210" with an extra white space after
719        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
720        for a time when a HANDLE is 64 bit.  */
721 #define BUFFER_MAX 800
722     char line[BUFFER_MAX + 1];
723     int res;
724     int written;
725     size_t len;
726
727     if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
728       strcpy (line, "~1 \n");
729     else
730       strcpy (line, "\n");
731     for (i = 0; fd_list[i].fd != -1; i++)
732       {
733         /* Strip the newline.  */
734         len = strlen (line) - 1;
735         
736         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
737         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
738                   fd_list[i].fd, fd_list[i].dup_to,
739                   fd_list[i].peer_name, fd_list[i].arg_loc);
740         /* Rather safe than sorry.  */
741         line[BUFFER_MAX - 1] = '\n';
742         line[BUFFER_MAX] = '\0';
743       }
744     len = strlen (line);
745     written = 0;
746     do
747       {
748         res = write (tmp_fd, &line[written], len - written);
749         if (res > 0)
750           written += res;
751       }
752     while (res > 0 || (res < 0 && errno == EAGAIN));
753   }
754   close (tmp_fd);
755   /* The temporary file is deleted by the gpgme-w32spawn process
756      (hopefully).  */
757     
758   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
759               "dwProcessID=%d, dwThreadId=%d",
760               pi.hProcess, pi.hThread, 
761               (int) pi.dwProcessId, (int) pi.dwThreadId);
762   
763   if (r_pid)
764     *r_pid = (pid_t)pi.dwProcessId;
765
766   if (ResumeThread (pi.hThread) < 0)
767     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
768   
769   if (!CloseHandle (pi.hThread))
770     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
771                 (int) GetLastError ());
772
773   TRACE_LOG1 ("process=%p", pi.hProcess);
774
775   /* We don't need to wait for the process.  */
776   if (!CloseHandle (pi.hProcess))
777     TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
778                 (int) GetLastError ());
779
780   for (i = 0; fd_list[i].fd != -1; i++)
781     _gpgme_io_close (fd_list[i].fd);
782
783   for (i = 0; fd_list[i].fd != -1; i++)
784     if (fd_list[i].dup_to == -1)
785       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
786                   fd_list[i].peer_name);
787     else
788       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
789                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
790                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
791
792   return TRACE_SYSRES (0);
793 }
794
795
796 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
797    nothing to select, > 0 = number of signaled fds.  */
798 int
799 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
800 {
801   int npollfds;
802   GPollFD *pollfds;
803   int *pollfds_map; 
804   int i;
805   int j;
806   int any;
807   int n;
808   int count;
809   /* Use a 1s timeout.  */
810   int timeout = 1000;
811   void *dbg_help = NULL;
812   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
813               "nfds=%u, nonblock=%u", nfds, nonblock);
814
815   if (nonblock)
816     timeout = 0;
817
818   pollfds = calloc (nfds, sizeof *pollfds);
819   if (!pollfds)
820     return -1;
821   pollfds_map = calloc (nfds, sizeof *pollfds_map);
822   if (!pollfds_map)
823     {
824       free (pollfds);
825       return -1;
826     }
827   npollfds = 0;
828
829   TRACE_SEQ (dbg_help, "select on [ ");
830   any = 0;
831   for (i = 0; i < nfds; i++)
832     {
833       GIOChannel *chan = NULL;
834
835       if (fds[i].fd == -1) 
836         continue;
837
838       if ((fds[i].for_read || fds[i].for_write)
839           && !(chan = find_channel (fds[i].fd)))
840         {
841           TRACE_ADD1 (dbg_help, "[BAD0x%x ", fds[i].fd);
842           TRACE_END (dbg_help, "]"); 
843           assert (!"see log file");
844         }
845       else if (fds[i].for_read )
846         {
847           assert(chan);
848           g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds);
849           pollfds_map[npollfds] = i;
850           TRACE_ADD2 (dbg_help, "r0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
851           npollfds++;
852           any = 1;
853         }
854       else if (fds[i].for_write)
855         {
856           assert(chan);
857           g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds);
858           pollfds_map[npollfds] = i;
859           TRACE_ADD2 (dbg_help, "w0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
860           npollfds++;
861           any = 1;
862         }
863       fds[i].signaled = 0;
864     }
865   TRACE_END (dbg_help, "]"); 
866   if (!any)
867     {
868       count = 0;
869       goto leave;
870     }
871
872
873   count = g_io_channel_win32_poll (pollfds, npollfds, timeout);
874   if (count < 0)
875     {
876       int saved_errno = errno;
877       errno = saved_errno;
878       goto leave;
879     }
880
881   TRACE_SEQ (dbg_help, "select OK [ ");
882   if (TRACE_ENABLED (dbg_help))
883     {
884       for (i = 0; i < npollfds; i++)
885         {
886           if ((pollfds[i].revents & G_IO_IN))
887             TRACE_ADD1 (dbg_help, "r0x%x ", fds[pollfds_map[i]].fd);
888           if ((pollfds[i].revents & G_IO_OUT))
889             TRACE_ADD1 (dbg_help, "w0x%x ", fds[pollfds_map[i]].fd);
890         }
891       TRACE_END (dbg_help, "]");
892     }
893     
894   /* COUNT is used to stop the lop as soon as possible.  */
895   for (n = count, i = 0; i < npollfds && n; i++)
896     {
897       j = pollfds_map[i];
898       assert (j >= 0 && j < nfds);
899       if (fds[j].fd == -1)
900         ;
901       else if (fds[j].for_read)
902         {
903           if ((pollfds[i].revents & G_IO_IN))
904             {
905               fds[j].signaled = 1;
906               n--;
907             }
908         }
909       else if (fds[j].for_write)
910         {
911           if ((pollfds[i].revents & G_IO_OUT))
912             {
913               fds[j].signaled = 1;
914               n--;
915             }
916         }
917     }
918
919 leave:
920   free (pollfds);
921   free (pollfds_map);
922   return TRACE_SYSRES (count);
923 }
924
925
926 int
927 _gpgme_io_dup (int fd)
928 {
929   int newfd;
930   GIOChannel *chan;
931
932   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
933
934   if (fd < 0 || fd >= MAX_SLAFD || !giochannel_table[fd].used)
935     {
936       errno = EINVAL;
937       return TRACE_SYSRES (-1);
938     }
939
940   for (newfd = 0; newfd < MAX_SLAFD; newfd++)
941     if (! giochannel_table[newfd].used)
942       break;
943   if (newfd == MAX_SLAFD)
944     {
945       errno = EIO;
946       return TRACE_SYSRES (-1);
947     }
948   
949   chan = giochannel_table[fd].chan;
950   g_io_channel_ref (chan);
951   giochannel_table[newfd].used = 1;
952   giochannel_table[newfd].chan = chan;
953   giochannel_table[newfd].fd = -1;
954   giochannel_table[newfd].socket = INVALID_SOCKET;
955   giochannel_table[newfd].primary = 0;
956
957   return TRACE_SYSRES (newfd);
958 }
959
960 \f
961
962
963 \f
964 static int
965 wsa2errno (int err)
966 {
967   switch (err)
968     {
969     case WSAENOTSOCK:
970       return EINVAL;
971     case WSAEWOULDBLOCK:
972       return EAGAIN;
973     case ERROR_BROKEN_PIPE:
974       return EPIPE;
975     case WSANOTINITIALISED:
976       return ENOSYS;
977     default:
978       return EIO;
979     }
980 }
981
982
983 int
984 _gpgme_io_socket (int domain, int type, int proto)
985 {
986   int res;
987   int fd;
988
989   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
990               "type=%i, protp=%i", type, proto);
991
992   res = socket (domain, type, proto);
993   if (res == INVALID_SOCKET)
994     {
995       errno = wsa2errno (WSAGetLastError ());
996       return TRACE_SYSRES (-1);
997     }
998
999   fd = new_channel_from_socket (res);
1000   if (fd < 0)
1001     {
1002       int saved_errno = errno;
1003       closesocket (res);
1004       errno = saved_errno;
1005       return TRACE_SYSRES (-1);
1006     }
1007
1008   TRACE_SUC2 ("fd=%i, socket=0x%x", fd, res);
1009   
1010   return fd;
1011 }
1012
1013
1014 int
1015 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
1016 {
1017   GIOChannel *chan; 
1018   int sockfd;
1019   int res;
1020   GIOFlags flags;
1021   GIOStatus status;
1022   GError *err = NULL;
1023
1024   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
1025               "addr=%p, addrlen=%i", addr, addrlen);
1026
1027   chan = find_channel (fd);
1028   if (! chan)
1029     {
1030       errno = EINVAL;
1031       return TRACE_SYSRES (-1);
1032     }
1033
1034   flags = g_io_channel_get_flags (chan);
1035   if (flags & G_IO_FLAG_NONBLOCK)
1036     {
1037       status = g_io_channel_set_flags (chan, flags & ~G_IO_FLAG_NONBLOCK, &err);
1038       if (err)
1039         {
1040           TRACE_LOG1 ("setting flags error: %s", err->message);
1041           g_error_free (err);
1042           err = NULL;
1043         }
1044       if (status != G_IO_STATUS_NORMAL)
1045         {
1046           errno = EIO;
1047           return TRACE_SYSRES (-1);
1048         }
1049     }
1050
1051   sockfd = giochannel_table[fd].socket;
1052   if (sockfd == INVALID_SOCKET)
1053     {
1054       errno = EINVAL;
1055       return TRACE_SYSRES (-1);
1056     }
1057
1058   TRACE_LOG1 ("connect sockfd=0x%x", sockfd);
1059   res = connect (sockfd, addr, addrlen);
1060
1061   /* FIXME: Error ignored here.  */
1062   if (! (flags & G_IO_FLAG_NONBLOCK))
1063     g_io_channel_set_flags (chan, flags, NULL);
1064
1065   if (res)
1066     {
1067       TRACE_LOG2 ("connect failed: %i %i", res, WSAGetLastError ());
1068
1069       errno = wsa2errno (WSAGetLastError ());
1070       return TRACE_SYSRES (-1);
1071     }
1072
1073   return TRACE_SUC ();
1074 }