2006-01-03 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / 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
45 \f
46 /* This file is an ugly hack to get GPGME working with glib on Windows
47    targets.  On Windows, you can not select() on file descriptors.
48    The only way to check if there is something to read is to read
49    something.  This means that GPGME can not let glib check for data
50    without letting glib also handle the data on Windows targets.
51
52    The ugly consequence is that we need to work on GIOChannels in
53    GPGME, creating a glib dependency.  Also, we need to export an
54    interface for the application to get at GPGME's GIOChannel.  There
55    is no good way to abstract all this with callbacks, because the
56    whole thing is also interconnected with the creation of pipes and
57    child processes.
58
59    The following rule applies only to this I/O backend:
60
61    * ALL operations must use the user defined event loop.  GPGME can
62    not anymore provide its own event loop.  This is mostly a sanity
63    requirement: Although we have in theory all information we need to
64    make the GPGME W32 code for select still work, it would be a big
65    complication and require changes throughout GPGME.
66
67    Eventually, we probably have to bite the bullet and make some
68    really nice callback interfaces to let the user control all this at
69    a per-context level.  */
70
71 \f
72 #define MAX_SLAFD 256
73
74 GIOChannel *giochannel_table[MAX_SLAFD];
75
76
77 static GIOChannel *
78 find_channel (int fd, int create)
79 {
80   if (fd < 0 || fd >= MAX_SLAFD)
81     return NULL;
82
83   if (create && !giochannel_table[fd])
84     {
85       giochannel_table[fd] = g_io_channel_win32_new_fd (fd);
86       g_io_channel_set_encoding (giochannel_table[fd], NULL, NULL);
87       g_io_channel_set_buffered (giochannel_table[fd], FALSE);
88     }
89
90   return giochannel_table[fd];
91 }
92
93 /* Look up the giochannel for "file descriptor" FD.  */
94 GIOChannel *
95 gpgme_get_giochannel (int fd)
96 {
97   return find_channel (fd, 0);
98 }
99
100
101 /* Write the printable version of FD to the buffer BUF of length
102    BUFLEN.  The printable version is the representation on the command
103    line that the child process expects.  */
104 int
105 _gpgme_io_fd2str (char *buf, int buflen, int fd)
106 {
107   return snprintf (buf, buflen, "%ld", (long) _get_osfhandle (fd));
108 }
109
110 \f
111 void
112 _gpgme_io_subsystem_init (void)
113 {
114 }
115
116 \f
117 static struct
118 {
119   void (*handler) (int,void*);
120   void *value;
121 } notify_table[MAX_SLAFD];
122
123 int
124 _gpgme_io_read (int fd, void *buffer, size_t count)
125 {
126   int saved_errno = 0;
127   gsize nread;
128   GIOChannel *chan;
129   GIOStatus status;
130
131   DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count);
132
133   chan = find_channel (fd, 0);
134   if (!chan)
135     {
136       DEBUG1 ("fd %d: no channel registered\n", fd);
137       errno = EINVAL;
138       return -1;
139     }
140   DEBUG2 ("fd %d: channel %p\n", fd, chan);
141
142   {
143     GError *err = NULL;
144     status = g_io_channel_read_chars (chan, (gchar *) buffer,
145                                       count, &nread, &err);
146     if (err)
147       {
148         DEBUG3 ("fd %d: status %i, err %s\n", fd, status, err->message);
149         g_error_free (err);
150       }
151   }
152
153   if (status == G_IO_STATUS_EOF)
154     nread = 0;
155   else if (status != G_IO_STATUS_NORMAL)
156     {
157       DEBUG2 ("fd %d: status %d\n", fd, status);
158       nread = -1;
159       saved_errno = EIO;
160     }
161
162   DEBUG2 ("fd %d: got %d bytes\n", fd, nread);
163   if (nread > 0)
164     _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);
165
166   errno = saved_errno;
167   return nread;
168 }
169
170
171 int
172 _gpgme_io_write (int fd, const void *buffer, size_t count)
173 {
174   int saved_errno = 0;
175   gsize nwritten;
176   GIOChannel *chan;
177   GIOStatus status;
178
179   DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) count);
180   _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
181
182   chan = find_channel (fd, 0);
183   if (!chan)
184     {
185       DEBUG1 ("fd %d: no channel registered\n", fd);
186       errno = EINVAL;
187       return -1;
188     }
189
190   status = g_io_channel_write_chars (chan, (gchar *) buffer, count,
191                                      &nwritten, NULL);
192   if (status != G_IO_STATUS_NORMAL)
193     {
194       nwritten = -1;
195       saved_errno = EIO;
196     }
197   DEBUG2 ("fd %d:          wrote %d bytes\n", fd, (int) nwritten);
198   errno = saved_errno;
199   return nwritten;
200 }
201
202
203 int
204 _gpgme_io_pipe (int filedes[2], int inherit_idx)
205 {
206   GIOChannel *chan;
207
208 #define PIPEBUF_SIZE  4096
209   if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT) == -1)
210     return -1;
211
212   /* Make one end inheritable. */
213   if (inherit_idx == 0)
214     {
215       int new_read;
216
217       new_read = _dup (filedes[0]);
218       _close (filedes[0]);
219       filedes[0] = new_read;
220
221       if (new_read < 0)
222         {
223           _close (filedes[1]);
224           return -1;
225         }
226     }
227   else if (inherit_idx == 1)
228     {
229       int new_write;
230
231       new_write = _dup (filedes[1]);
232       _close (filedes[1]);
233       filedes[1] = new_write;
234
235       if (new_write < 0)
236         {
237           _close (filedes[0]);
238           return -1;
239         }
240     }
241
242   /* Now we have a pipe with the right end inheritable.  The other end
243      should have a giochannel.  */
244   chan = find_channel (filedes[1 - inherit_idx], 1);
245   if (!chan)
246     {
247       DEBUG2 ("channel creation for %d failed: ec=%d\n",
248               filedes[1 - inherit_idx], errno);
249       _close (filedes[0]);
250       _close (filedes[1]);
251       return -1;
252     }
253
254   DEBUG5 ("CreatePipe %d (%p) %d (%p) inherit=%p\n",
255           filedes[0], (HANDLE) _get_osfhandle (filedes[0]),
256           filedes[1], (HANDLE) _get_osfhandle (filedes[1]),
257           chan);
258   return 0;
259 }
260
261
262 int
263 _gpgme_io_close (int fd)
264 {
265   GIOChannel *chan;
266
267   if (fd < 0 || fd >= MAX_SLAFD)
268     {
269       errno = EBADF;
270       return -1;
271     }
272
273   /* First call the notify handler.  */
274   DEBUG1 ("closing fd %d", fd);
275   if (notify_table[fd].handler)
276     {
277       notify_table[fd].handler (fd, notify_table[fd].value);
278       notify_table[fd].handler = NULL;
279       notify_table[fd].value = NULL;
280     }
281
282   /* Then do the close.  */    
283   chan = giochannel_table[fd];
284   if (chan)
285     {
286       g_io_channel_shutdown (chan, 1, NULL);
287       g_io_channel_unref (chan);
288       giochannel_table[fd] = NULL;
289     }
290   else
291     _close (fd);
292
293   return 0;
294 }
295
296
297 int
298 _gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
299 {
300   assert (fd != -1);
301
302   if (fd < 0 || fd >= (int) DIM (notify_table))
303     return -1;
304   DEBUG1 ("set notification for fd %d", fd);
305   notify_table[fd].handler = handler;
306   notify_table[fd].value = value;
307   return 0;
308 }
309
310
311 int
312 _gpgme_io_set_nonblocking (int fd)
313 {
314   GIOChannel *chan;
315   GIOStatus status;
316
317   chan = find_channel (fd, 0);
318   if (!chan)
319     {
320       errno = EIO;
321       return -1;
322     }
323
324   status = g_io_channel_set_flags (chan,
325                                    g_io_channel_get_flags (chan) |
326                                    G_IO_FLAG_NONBLOCK, NULL);
327   if (status != G_IO_STATUS_NORMAL)
328     {
329       errno = EIO;
330       return -1;
331     }
332
333   return 0;
334 }
335
336
337 static char *
338 build_commandline ( char **argv )
339 {
340   int i, n = 0;
341   char *buf, *p;
342   
343   /* FIXME: we have to quote some things because under Windows the
344    * program parses the commandline and does some unquoting.  For now
345    * we only do very basic quoting to the first argument because this
346    * one often contains a space (e.g. C:\\Program Files\GNU\GnuPG\gpg.exe) 
347    * and we would produce an invalid line in that case.  */
348   for (i=0; argv[i]; i++)
349     n += strlen (argv[i]) + 2 + 1; /* 2 extra bytes for possible quoting */
350   buf = p = malloc (n);
351   if ( !buf )
352     return NULL;
353   *buf = 0;
354   if ( argv[0] )
355     {
356       if (strpbrk (argv[0], " \t"))
357         p = stpcpy (stpcpy (stpcpy (p, "\""), argv[0]), "\"");
358       else
359         p = stpcpy (p, argv[0]);
360       for (i = 1; argv[i]; i++)
361         {
362           if (!*argv[i])
363             p = stpcpy (p, " \"\"");
364           else
365             p = stpcpy (stpcpy (p, " "), argv[i]);
366         }
367     }
368   
369   return buf;
370 }
371
372
373 int
374 _gpgme_io_spawn ( const char *path, char **argv,
375                   struct spawn_fd_item_s *fd_child_list,
376                   struct spawn_fd_item_s *fd_parent_list )
377 {
378     SECURITY_ATTRIBUTES sec_attr;
379     PROCESS_INFORMATION pi = {
380         NULL,      /* returns process handle */
381         0,         /* returns primary thread handle */
382         0,         /* returns pid */
383         0         /* returns tid */
384     };
385     STARTUPINFO si;
386     char *envblock = NULL;
387     int cr_flags = CREATE_DEFAULT_ERROR_MODE
388                  | GetPriorityClass (GetCurrentProcess ());
389     int i;
390     char *arg_string;
391     int duped_stdin = 0;
392     int duped_stderr = 0;
393     HANDLE hnul = INVALID_HANDLE_VALUE;
394     /* FIXME.  */
395     int debug_me = 0;
396
397     memset (&sec_attr, 0, sizeof sec_attr);
398     sec_attr.nLength = sizeof sec_attr;
399     sec_attr.bInheritHandle = FALSE;
400
401     arg_string = build_commandline (argv);
402     if (!arg_string )
403         return -1; 
404
405     memset (&si, 0, sizeof si);
406     si.cb = sizeof (si);
407     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
408     si.wShowWindow = debug_me? SW_SHOW : SW_HIDE;
409     si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
410     si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
411     si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
412
413     for (i=0; fd_child_list[i].fd != -1; i++ ) {
414         if (fd_child_list[i].dup_to == 0 ) {
415             si.hStdInput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
416             DEBUG2 ("using %d (%p) for stdin", fd_child_list[i].fd,
417                     _get_osfhandle (fd_child_list[i].fd));
418             duped_stdin=1;
419         }
420         else if (fd_child_list[i].dup_to == 1 ) {
421             si.hStdOutput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
422             DEBUG2 ("using %d (%p) for stdout", fd_child_list[i].fd,
423                     _get_osfhandle (fd_child_list[i].fd));
424         }
425         else if (fd_child_list[i].dup_to == 2 ) {
426             si.hStdError = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
427             DEBUG2 ("using %d (%p) for stderr", fd_child_list[i].fd,
428                     _get_osfhandle (fd_child_list[i].fd));
429             duped_stderr = 1;
430         }
431     }
432
433     if( !duped_stdin || !duped_stderr ) {
434         SECURITY_ATTRIBUTES sa;
435
436         memset (&sa, 0, sizeof sa );
437         sa.nLength = sizeof sa;
438         sa.bInheritHandle = TRUE;
439         hnul = CreateFile ( "nul",
440                             GENERIC_READ|GENERIC_WRITE,
441                             FILE_SHARE_READ|FILE_SHARE_WRITE,
442                             &sa,
443                             OPEN_EXISTING,
444                             FILE_ATTRIBUTE_NORMAL,
445                             NULL );
446         if ( hnul == INVALID_HANDLE_VALUE ) {
447             DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ());
448             free (arg_string);
449             return -1;
450         }
451         /* Make sure that the process has a connected stdin */
452         if ( !duped_stdin ) {
453             si.hStdInput = hnul;
454             DEBUG1 ("using %d for dummy stdin", (int)hnul );
455         }
456         /* We normally don't want all the normal output */
457         if ( !duped_stderr ) {
458             si.hStdError = hnul;
459             DEBUG1 ("using %d for dummy stderr", (int)hnul );
460         }
461     }
462
463     DEBUG2 ("CreateProcess, path=`%s' args=`%s'", path, arg_string);
464     cr_flags |= CREATE_SUSPENDED; 
465     if ( !CreateProcessA (path,
466                           arg_string,
467                           &sec_attr,     /* process security attributes */
468                           &sec_attr,     /* thread security attributes */
469                           TRUE,          /* inherit handles */
470                           cr_flags,      /* creation flags */
471                           envblock,      /* environment */
472                           NULL,          /* use current drive/directory */
473                           &si,           /* startup information */
474                           &pi            /* returns process information */
475         ) ) {
476         DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ());
477         free (arg_string);
478         return -1;
479     }
480
481     /* Close the /dev/nul handle if used. */
482     if (hnul != INVALID_HANDLE_VALUE ) {
483         if ( !CloseHandle ( hnul ) )
484             DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError());
485     }
486
487     /* Close the other ends of the pipes. */
488     for (i = 0; fd_parent_list[i].fd != -1; i++)
489       _gpgme_io_close (fd_parent_list[i].fd);
490
491     DEBUG4 ("CreateProcess ready\n"
492             "-   hProcess=%p  hThread=%p\n"
493             "-   dwProcessID=%d dwThreadId=%d\n",
494             pi.hProcess, pi.hThread, 
495             (int) pi.dwProcessId, (int) pi.dwThreadId);
496
497     if ( ResumeThread ( pi.hThread ) < 0 ) {
498         DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ());
499     }
500
501     if ( !CloseHandle (pi.hThread) ) { 
502         DEBUG1 ("CloseHandle of thread failed: ec=%d\n",
503                  (int)GetLastError ());
504     }
505
506     return 0;
507 }
508
509
510 /*
511  * Select on the list of fds.
512  * Returns: -1 = error
513  *           0 = timeout or nothing to select
514  *          >0 = number of signaled fds
515  */
516 int
517 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
518 {
519   int     npollfds;
520   GPollFD *pollfds;
521   int     *pollfds_map; 
522   int i, j;
523   int any, n, count;
524   int timeout = 1000;  /* Use a 1s timeout.  */
525   void *dbg_help = NULL;
526
527   if (nonblock)
528     timeout = 0;
529
530   pollfds = calloc (nfds, sizeof *pollfds);
531   if (!pollfds)
532     return -1;
533   pollfds_map = calloc (nfds, sizeof *pollfds_map);
534   if (!pollfds_map)
535     {
536       free (pollfds);
537       return -1;
538     }
539   npollfds = 0;
540
541   DEBUG_BEGIN (dbg_help, 3, "gpgme:select on [ ");
542   any = 0;
543   for (i = 0; i < nfds; i++)
544     {
545       if (fds[i].fd == -1) 
546         continue;
547       if (fds[i].frozen)
548         DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd);
549       else if (fds[i].for_read )
550         {
551           GIOChannel *chan = find_channel (fds[i].fd, 0);
552           assert (chan);
553           g_io_channel_win32_make_pollfd (chan, G_IO_IN, pollfds + npollfds);
554           pollfds_map[npollfds] = i;
555           DEBUG_ADD2 (dbg_help, "r%d<%d> ", fds[i].fd, pollfds[npollfds].fd);
556           npollfds++;
557           any = 1;
558         }
559       else if (fds[i].for_write)
560         {
561           GIOChannel *chan = find_channel (fds[i].fd, 0);
562           assert (chan);
563           g_io_channel_win32_make_pollfd (chan, G_IO_OUT, pollfds + npollfds);
564           pollfds_map[npollfds] = i;
565           DEBUG_ADD2 (dbg_help, "w%d<%d> ", fds[i].fd, pollfds[npollfds].fd);
566           npollfds++;
567           any = 1;
568         }
569       fds[i].signaled = 0;
570     }
571   DEBUG_END (dbg_help, "]"); 
572   if (!any)
573     {
574       count = 0;
575       goto leave;
576     }
577
578
579   count = g_io_channel_win32_poll (pollfds, npollfds, timeout);
580   if (count < 0)
581     {
582       int saved_errno = errno;
583       DEBUG1 ("_gpgme_io_select failed: %s\n", strerror (errno));
584       errno = saved_errno;
585       goto leave;
586     }
587
588   DEBUG_BEGIN (dbg_help, 3, "select OK [ ");
589   if (DEBUG_ENABLED (dbg_help))
590     {
591       for (i = 0; i < npollfds; i++)
592         {
593           if ((pollfds[i].revents & G_IO_IN))
594             DEBUG_ADD1 (dbg_help, "r%d ", fds[pollfds_map[i]].fd);
595           if ((pollfds[i].revents & G_IO_OUT))
596             DEBUG_ADD1 (dbg_help, "w%d ", fds[pollfds_map[i]].fd);
597         }
598       DEBUG_END (dbg_help, "]");
599     }
600     
601   /* COUNT is used to stop the lop as soon as possible.  */
602   for (n = count, i = 0; i < npollfds && n; i++)
603     {
604       j = pollfds_map[i];
605       assert (j >= 0 && j < nfds);
606       if (fds[j].fd == -1)
607         ;
608       else if (fds[j].for_read)
609         {
610           if ((pollfds[i].revents & G_IO_IN))
611             {
612               fds[j].signaled = 1;
613               n--;
614             }
615         }
616       else if (fds[j].for_write)
617         {
618           if ((pollfds[i].revents & G_IO_OUT))
619             {
620               fds[j].signaled = 1;
621               n--;
622             }
623         }
624     }
625
626 leave:
627   free (pollfds);
628   free (pollfds_map);
629   return count;
630 }