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