gpgme-tool: Use membuf functions to build up strings.
[gpgme.git] / src / w32-glib-io.c
1 /* w32-glib-io.c - W32 Glib I/O functions
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2004, 2005 g10 Code GmbH
4
5    This file is part of GPGME.
6
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (at your option) any later version.
11
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #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 refering 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_BEG1 (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_SUC1 ("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_BEG2 (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_LOG1 ("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_LOG2 ("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_LOG1 ("status %d", status);
299       nread = -1;
300       saved_errno = EIO;
301     }
302
303   if (nread != 0 && nread != -1)
304     TRACE_LOGBUF (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_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
321               "buffer=%p, count=%u", buffer, count);
322   TRACE_LOGBUF (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_LOG1 ("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_BEG2 (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   return TRACE_SUC5 ("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 }
431
432
433 int
434 _gpgme_io_close (int fd)
435 {
436   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
437
438   if (fd < 0 || fd >= MAX_SLAFD)
439     {
440       errno = EBADF;
441       return TRACE_SYSRES (-1);
442     }
443
444   assert (giochannel_table[fd].used);
445
446   /* First call the notify handler.  */
447   if (notify_table[fd].handler)
448     {
449       notify_table[fd].handler (fd, notify_table[fd].value);
450       notify_table[fd].handler = NULL;
451       notify_table[fd].value = NULL;
452     }
453
454   /* Then do the close.  */
455   if (giochannel_table[fd].chan)
456     {
457       if (giochannel_table[fd].primary)
458         g_io_channel_shutdown (giochannel_table[fd].chan, 1, NULL);
459
460       g_io_channel_unref (giochannel_table[fd].chan);
461     }
462   else
463     {
464       /* Dummy entry, just close.  */
465       assert (giochannel_table[fd].fd != -1);
466       _close (giochannel_table[fd].fd);
467     }
468
469   giochannel_table[fd].used = 0;
470   giochannel_table[fd].fd = -1;
471   giochannel_table[fd].socket = INVALID_SOCKET;
472   giochannel_table[fd].chan = NULL;
473   giochannel_table[fd].primary = 0;
474
475   TRACE_SUC ();
476   return 0;
477 }
478
479
480 int
481 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
482                             void *value)
483 {
484   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
485               "close_handler=%p/%p", handler, value);
486
487   assert (fd != -1);
488
489   if (fd < 0 || fd >= (int) DIM (notify_table))
490     {
491       errno = EINVAL;
492       return TRACE_SYSRES (-1);
493     }
494   notify_table[fd].handler = handler;
495   notify_table[fd].value = value;
496   return TRACE_SYSRES (0);
497 }
498
499
500 int
501 _gpgme_io_set_nonblocking (int fd)
502 {
503   GIOChannel *chan;
504   GIOStatus status;
505
506   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
507
508   chan = find_channel (fd);
509   if (!chan)
510     {
511       errno = EIO;
512       return TRACE_SYSRES (-1);
513     }
514
515   status = g_io_channel_set_flags (chan,
516                                    g_io_channel_get_flags (chan) |
517                                    G_IO_FLAG_NONBLOCK, NULL);
518
519   if (status != G_IO_STATUS_NORMAL)
520     {
521 #if 0
522       /* glib 1.9.2 does not implement set_flags and returns an
523          error.  */
524       errno = EIO;
525       return TRACE_SYSRES (-1);
526 #else
527       TRACE_LOG1 ("g_io_channel_set_flags failed: status=%d (ignored)",
528                   status);
529 #endif
530     }
531
532   return TRACE_SYSRES (0);
533 }
534
535
536 static char *
537 build_commandline (char **argv)
538 {
539   int i;
540   int n = 0;
541   char *buf;
542   char *p;
543
544   /* We have to quote some things because under Windows the program
545      parses the commandline and does some unquoting.  We enclose the
546      whole argument in double-quotes, and escape literal double-quotes
547      as well as backslashes with a backslash.  We end up with a
548      trailing space at the end of the line, but that is harmless.  */
549   for (i = 0; argv[i]; i++)
550     {
551       p = argv[i];
552       /* The leading double-quote.  */
553       n++;
554       while (*p)
555         {
556           /* An extra one for each literal that must be escaped.  */
557           if (*p == '\\' || *p == '"')
558             n++;
559           n++;
560           p++;
561         }
562       /* The trailing double-quote and the delimiter.  */
563       n += 2;
564     }
565   /* And a trailing zero.  */
566   n++;
567
568   buf = p = malloc (n);
569   if (!buf)
570     return NULL;
571   for (i = 0; argv[i]; i++)
572     {
573       char *argvp = argv[i];
574
575       *(p++) = '"';
576       while (*argvp)
577         {
578           if (*argvp == '\\' || *argvp == '"')
579             *(p++) = '\\';
580           *(p++) = *(argvp++);
581         }
582       *(p++) = '"';
583       *(p++) = ' ';
584     }
585   *(p++) = 0;
586
587   return buf;
588 }
589
590
591 int
592 _gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags,
593                  struct spawn_fd_item_s *fd_list,
594                  void (*atfork) (void *opaque, int reserved),
595                  void *atforkvalue, pid_t *r_pid)
596 {
597   SECURITY_ATTRIBUTES sec_attr;
598   PROCESS_INFORMATION pi =
599     {
600       NULL,      /* returns process handle */
601       0,         /* returns primary thread handle */
602       0,         /* returns pid */
603       0          /* returns tid */
604     };
605   STARTUPINFO si;
606   int cr_flags = (CREATE_DEFAULT_ERROR_MODE
607                   | GetPriorityClass (GetCurrentProcess ()));
608   int i;
609   char **args;
610   char *arg_string;
611   /* FIXME.  */
612   int debug_me = 0;
613   int tmp_fd;
614   char *tmp_name;
615
616   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
617               "path=%s", path);
618   i = 0;
619   while (argv[i])
620     {
621       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
622       i++;
623     }
624
625   /* We do not inherit any handles by default, and just insert those
626      handles we want the child to have afterwards.  But some handle
627      values occur on the command line, and we need to move
628      stdin/out/err to the right location.  So we use a wrapper program
629      which gets the information from a temporary file.  */
630   if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
631     {
632       TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
633       return TRACE_SYSRES (-1);
634     }
635   TRACE_LOG1 ("tmp_name = %s", tmp_name);
636
637   args = calloc (2 + i + 1, sizeof (*args));
638   args[0] = (char *) _gpgme_get_w32spawn_path ();
639   args[1] = tmp_name;
640   args[2] = path;
641   memcpy (&args[3], &argv[1], i * sizeof (*args));
642
643   memset (&sec_attr, 0, sizeof sec_attr);
644   sec_attr.nLength = sizeof sec_attr;
645   sec_attr.bInheritHandle = FALSE;
646
647   arg_string = build_commandline (args);
648   free (args);
649   if (!arg_string)
650     {
651       close (tmp_fd);
652       DeleteFile (tmp_name);
653       return TRACE_SYSRES (-1);
654     }
655
656   memset (&si, 0, sizeof si);
657   si.cb = sizeof (si);
658   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
659   si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
660   si.hStdInput = INVALID_HANDLE_VALUE;
661   si.hStdOutput = INVALID_HANDLE_VALUE;
662   si.hStdError = INVALID_HANDLE_VALUE;
663
664   cr_flags |= CREATE_SUSPENDED;
665   cr_flags |= DETACHED_PROCESS;
666   if (!CreateProcessA (_gpgme_get_w32spawn_path (),
667                        arg_string,
668                        &sec_attr,     /* process security attributes */
669                        &sec_attr,     /* thread security attributes */
670                        FALSE,         /* inherit handles */
671                        cr_flags,      /* creation flags */
672                        NULL,          /* environment */
673                        NULL,          /* use current drive/directory */
674                        &si,           /* startup information */
675                        &pi))          /* returns process information */
676     {
677       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
678       free (arg_string);
679       close (tmp_fd);
680       DeleteFile (tmp_name);
681
682       /* FIXME: Should translate the error code.  */
683       errno = EIO;
684       return TRACE_SYSRES (-1);
685     }
686
687   free (arg_string);
688
689   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
690     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
691
692   /* Insert the inherited handles.  */
693   for (i = 0; fd_list[i].fd != -1; i++)
694     {
695       HANDLE hd;
696
697       /* Make it inheritable for the wrapper process.  */
698       if (!DuplicateHandle (GetCurrentProcess(),
699                             _get_osfhandle (giochannel_table[fd_list[i].fd].fd),
700                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
701         {
702           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
703           TerminateProcess (pi.hProcess, 0);
704           /* Just in case TerminateProcess didn't work, let the
705              process fail on its own.  */
706           ResumeThread (pi.hThread);
707           CloseHandle (pi.hThread);
708           CloseHandle (pi.hProcess);
709
710           close (tmp_fd);
711           DeleteFile (tmp_name);
712
713           /* FIXME: Should translate the error code.  */
714           errno = EIO;
715           return TRACE_SYSRES (-1);
716         }
717       /* Return the child name of this handle.  */
718       fd_list[i].peer_name = (int) hd;
719     }
720
721   /* Write the handle translation information to the temporary
722      file.  */
723   {
724     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
725        notation: "0xFEDCBA9876543210" with an extra white space after
726        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
727        for a time when a HANDLE is 64 bit.  */
728 #define BUFFER_MAX 800
729     char line[BUFFER_MAX + 1];
730     int res;
731     int written;
732     size_t len;
733
734     if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
735       strcpy (line, "~1 \n");
736     else
737       strcpy (line, "\n");
738     for (i = 0; fd_list[i].fd != -1; i++)
739       {
740         /* Strip the newline.  */
741         len = strlen (line) - 1;
742
743         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
744         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
745                   fd_list[i].fd, fd_list[i].dup_to,
746                   fd_list[i].peer_name, fd_list[i].arg_loc);
747         /* Rather safe than sorry.  */
748         line[BUFFER_MAX - 1] = '\n';
749         line[BUFFER_MAX] = '\0';
750       }
751     len = strlen (line);
752     written = 0;
753     do
754       {
755         res = write (tmp_fd, &line[written], len - written);
756         if (res > 0)
757           written += res;
758       }
759     while (res > 0 || (res < 0 && errno == EAGAIN));
760   }
761   close (tmp_fd);
762   /* The temporary file is deleted by the gpgme-w32spawn process
763      (hopefully).  */
764
765   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
766               "dwProcessID=%d, dwThreadId=%d",
767               pi.hProcess, pi.hThread,
768               (int) pi.dwProcessId, (int) pi.dwThreadId);
769
770   if (r_pid)
771     *r_pid = (pid_t)pi.dwProcessId;
772
773   if (ResumeThread (pi.hThread) < 0)
774     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
775
776   if (!CloseHandle (pi.hThread))
777     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
778                 (int) GetLastError ());
779
780   TRACE_LOG1 ("process=%p", pi.hProcess);
781
782   /* We don't need to wait for the process.  */
783   if (!CloseHandle (pi.hProcess))
784     TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
785                 (int) GetLastError ());
786
787   if (! (flags & IOSPAWN_FLAG_NOCLOSE))
788     {
789       for (i = 0; fd_list[i].fd != -1; i++)
790         _gpgme_io_close (fd_list[i].fd);
791     }
792
793   for (i = 0; fd_list[i].fd != -1; i++)
794     if (fd_list[i].dup_to == -1)
795       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
796                   fd_list[i].peer_name);
797     else
798       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
799                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
800                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
801
802   return TRACE_SYSRES (0);
803 }
804
805
806 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
807    nothing to select, > 0 = number of signaled fds.  */
808 int
809 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
810 {
811   int npollfds;
812   GPollFD *pollfds;
813   int *pollfds_map;
814   int i;
815   int j;
816   int any;
817   int n;
818   int count;
819   /* Use a 1s timeout.  */
820   int timeout = 1000;
821   void *dbg_help = NULL;
822   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
823               "nfds=%u, nonblock=%u", nfds, nonblock);
824
825   if (nonblock)
826     timeout = 0;
827
828   pollfds = calloc (nfds, sizeof *pollfds);
829   if (!pollfds)
830     return -1;
831   pollfds_map = calloc (nfds, sizeof *pollfds_map);
832   if (!pollfds_map)
833     {
834       free (pollfds);
835       return -1;
836     }
837   npollfds = 0;
838
839   TRACE_SEQ (dbg_help, "select on [ ");
840   any = 0;
841   for (i = 0; i < nfds; i++)
842     {
843       GIOChannel *chan = NULL;
844
845       if (fds[i].fd == -1)
846         continue;
847
848       if ((fds[i].for_read || fds[i].for_write)
849           && !(chan = find_channel (fds[i].fd)))
850         {
851           TRACE_ADD1 (dbg_help, "[BAD0x%x ", fds[i].fd);
852           TRACE_END (dbg_help, "]");
853           assert (!"see log file");
854         }
855       else if (fds[i].for_read )
856         {
857           assert(chan);
858           g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds);
859           pollfds_map[npollfds] = i;
860           TRACE_ADD2 (dbg_help, "r0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
861           npollfds++;
862           any = 1;
863         }
864       else if (fds[i].for_write)
865         {
866           assert(chan);
867           g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds);
868           pollfds_map[npollfds] = i;
869           TRACE_ADD2 (dbg_help, "w0x%x<%d> ", fds[i].fd, pollfds[npollfds].fd);
870           npollfds++;
871           any = 1;
872         }
873       fds[i].signaled = 0;
874     }
875   TRACE_END (dbg_help, "]");
876   if (!any)
877     {
878       count = 0;
879       goto leave;
880     }
881
882
883   count = g_io_channel_win32_poll (pollfds, npollfds, timeout);
884   if (count < 0)
885     {
886       int saved_errno = errno;
887       errno = saved_errno;
888       goto leave;
889     }
890
891   TRACE_SEQ (dbg_help, "select OK [ ");
892   if (TRACE_ENABLED (dbg_help))
893     {
894       for (i = 0; i < npollfds; i++)
895         {
896           if ((pollfds[i].revents & G_IO_IN))
897             TRACE_ADD1 (dbg_help, "r0x%x ", fds[pollfds_map[i]].fd);
898           if ((pollfds[i].revents & G_IO_OUT))
899             TRACE_ADD1 (dbg_help, "w0x%x ", fds[pollfds_map[i]].fd);
900         }
901       TRACE_END (dbg_help, "]");
902     }
903
904   /* COUNT is used to stop the lop as soon as possible.  */
905   for (n = count, i = 0; i < npollfds && n; i++)
906     {
907       j = pollfds_map[i];
908       assert (j >= 0 && j < nfds);
909       if (fds[j].fd == -1)
910         ;
911       else if (fds[j].for_read)
912         {
913           if ((pollfds[i].revents & G_IO_IN))
914             {
915               fds[j].signaled = 1;
916               n--;
917             }
918         }
919       else if (fds[j].for_write)
920         {
921           if ((pollfds[i].revents & G_IO_OUT))
922             {
923               fds[j].signaled = 1;
924               n--;
925             }
926         }
927     }
928
929 leave:
930   free (pollfds);
931   free (pollfds_map);
932   return TRACE_SYSRES (count);
933 }
934
935
936 int
937 _gpgme_io_dup (int fd)
938 {
939   int newfd;
940   GIOChannel *chan;
941
942   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
943
944   if (fd < 0 || fd >= MAX_SLAFD || !giochannel_table[fd].used)
945     {
946       errno = EINVAL;
947       return TRACE_SYSRES (-1);
948     }
949
950   for (newfd = 0; newfd < MAX_SLAFD; newfd++)
951     if (! giochannel_table[newfd].used)
952       break;
953   if (newfd == MAX_SLAFD)
954     {
955       errno = EIO;
956       return TRACE_SYSRES (-1);
957     }
958
959   chan = giochannel_table[fd].chan;
960   g_io_channel_ref (chan);
961   giochannel_table[newfd].used = 1;
962   giochannel_table[newfd].chan = chan;
963   giochannel_table[newfd].fd = -1;
964   giochannel_table[newfd].socket = INVALID_SOCKET;
965   giochannel_table[newfd].primary = 0;
966
967   return TRACE_SYSRES (newfd);
968 }
969
970 \f
971
972
973 \f
974 static int
975 wsa2errno (int err)
976 {
977   switch (err)
978     {
979     case WSAENOTSOCK:
980       return EINVAL;
981     case WSAEWOULDBLOCK:
982       return EAGAIN;
983     case ERROR_BROKEN_PIPE:
984       return EPIPE;
985     case WSANOTINITIALISED:
986       return ENOSYS;
987     default:
988       return EIO;
989     }
990 }
991
992
993 int
994 _gpgme_io_socket (int domain, int type, int proto)
995 {
996   int res;
997   int fd;
998
999   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
1000               "type=%i, protp=%i", type, proto);
1001
1002   res = socket (domain, type, proto);
1003   if (res == INVALID_SOCKET)
1004     {
1005       errno = wsa2errno (WSAGetLastError ());
1006       return TRACE_SYSRES (-1);
1007     }
1008
1009   fd = new_channel_from_socket (res);
1010   if (fd < 0)
1011     {
1012       int saved_errno = errno;
1013       closesocket (res);
1014       errno = saved_errno;
1015       return TRACE_SYSRES (-1);
1016     }
1017
1018   TRACE_SUC2 ("fd=%i, socket=0x%x", fd, res);
1019
1020   return fd;
1021 }
1022
1023
1024 int
1025 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
1026 {
1027   GIOChannel *chan;
1028   int sockfd;
1029   int res;
1030   GIOFlags flags;
1031   GIOStatus status;
1032   GError *err = NULL;
1033
1034   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
1035               "addr=%p, addrlen=%i", addr, addrlen);
1036
1037   chan = find_channel (fd);
1038   if (! chan)
1039     {
1040       errno = EINVAL;
1041       return TRACE_SYSRES (-1);
1042     }
1043
1044   flags = g_io_channel_get_flags (chan);
1045   if (flags & G_IO_FLAG_NONBLOCK)
1046     {
1047       status = g_io_channel_set_flags (chan, flags & ~G_IO_FLAG_NONBLOCK, &err);
1048       if (err)
1049         {
1050           TRACE_LOG1 ("setting flags error: %s", err->message);
1051           g_error_free (err);
1052           err = NULL;
1053         }
1054       if (status != G_IO_STATUS_NORMAL)
1055         {
1056           errno = EIO;
1057           return TRACE_SYSRES (-1);
1058         }
1059     }
1060
1061   sockfd = giochannel_table[fd].socket;
1062   if (sockfd == INVALID_SOCKET)
1063     {
1064       errno = EINVAL;
1065       return TRACE_SYSRES (-1);
1066     }
1067
1068   TRACE_LOG1 ("connect sockfd=0x%x", sockfd);
1069   res = connect (sockfd, addr, addrlen);
1070
1071   /* FIXME: Error ignored here.  */
1072   if (! (flags & G_IO_FLAG_NONBLOCK))
1073     g_io_channel_set_flags (chan, flags, NULL);
1074
1075   if (res)
1076     {
1077       TRACE_LOG2 ("connect failed: %i %i", res, WSAGetLastError ());
1078
1079       errno = wsa2errno (WSAGetLastError ());
1080       return TRACE_SYSRES (-1);
1081     }
1082
1083   return TRACE_SUC ();
1084 }