Release 1.4.3.
[gpgme.git] / src / w32-qt-io.cpp
1 /* w32-qt-io.c - W32 Glib I/O functions
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2004, 2005, 2007 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 #include <unistd.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <windows.h>
35 #include <io.h>
36
37 #include "kdpipeiodevice.h"
38
39 extern "C"
40 {
41 #include "util.h"
42 #include "priv-io.h"
43 #include "sema.h"
44 #include "debug.h"
45 }
46
47 #ifndef O_BINARY
48 #ifdef _O_BINARY
49 #define O_BINARY        _O_BINARY
50 #else
51 #define O_BINARY        0
52 #endif
53 #endif
54
55 using _gpgme_::KDPipeIODevice;
56
57 \f
58 /* This file is an ugly hack to get GPGME working with Qt on Windows
59    targets.  On Windows, you can not select() on file descriptors.
60 \f
61    The only way to check if there is something to read is to read
62    something.  This means that GPGME can not let Qt check for data
63    without letting Qt also handle the data on Windows targets.
64
65    The ugly consequence is that we need to work on QIODevices in
66    GPGME, creating a Qt dependency.  Also, we need to export an
67    interface for the application to get at GPGME's QIODevices.  There
68    is no good way to abstract all this with callbacks, because the
69    whole thing is also interconnected with the creation of pipes and
70    child processes.
71
72    The following rule applies only to this I/O backend:
73
74    * ALL operations must use the user defined event loop.  GPGME can
75    not anymore provide its own event loop.  This is mostly a sanity
76    requirement: Although we have in theory all information we need to
77    make the GPGME W32 code for select still work, it would be a big
78    complication and require changes throughout GPGME.
79
80    Eventually, we probably have to bite the bullet and make some
81    really nice callback interfaces to let the user control all this at
82    a per-context level.  */
83
84 #define MAX_SLAFD 1024
85
86 struct DeviceEntry {
87   DeviceEntry() : iodev( 0 ), refCount( 1 ), blocking( true ) {}
88     KDPipeIODevice* iodev;
89     bool blocking;
90     mutable int refCount;
91     void ref() const { ++refCount; }
92     int unref() const { assert( refCount > 0 ); return --refCount; }
93 };
94
95 DeviceEntry* iodevice_table[MAX_SLAFD];
96
97
98 static KDPipeIODevice *
99 find_channel (int fd, int create)
100 {
101   assert( fd < MAX_SLAFD );
102   if (fd < 0 || fd >= MAX_SLAFD)
103     return NULL;
104
105   if (create && !iodevice_table[fd])
106   {
107     DeviceEntry* entry = new DeviceEntry;
108     entry->iodev = new KDPipeIODevice
109       (fd, QIODevice::ReadWrite|QIODevice::Unbuffered);
110     iodevice_table[fd] = entry; 
111   }
112   return iodevice_table[fd] ? iodevice_table[fd]->iodev : 0;
113 }
114
115 /* Write the printable version of FD to the buffer BUF of length
116    BUFLEN.  The printable version is the representation on the command
117    line that the child process expects.  */
118 int
119 _gpgme_io_fd2str (char *buf, int buflen, int fd)
120 {
121   return snprintf (buf, buflen, "%d", (long)_get_osfhandle( fd ) );
122 }
123
124 \f
125 void
126 _gpgme_io_subsystem_init (void)
127 {
128 }
129
130 \f
131 static struct
132 {
133   _gpgme_close_notify_handler_t handler;
134   void *value;
135 } notify_table[MAX_SLAFD];
136
137
138 int
139 _gpgme_io_read (int fd, void *buffer, size_t count)
140 {
141   int saved_errno = 0;
142   qint64 nread;
143   KDPipeIODevice *chan;
144   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
145               "buffer=%p, count=%u", buffer, count);
146
147   chan = find_channel (fd, 0);
148   if (!chan)
149     {
150       TRACE_LOG ("no channel registered");
151       errno = EINVAL;
152       return TRACE_SYSRES (-1);
153     }
154   TRACE_LOG1 ("channel %p", chan);
155   if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->readWouldBlock() ) {
156       errno = EAGAIN;
157       return TRACE_SYSRES( -1 );
158   }
159  
160   nread = chan->read ((char *) buffer, count);
161   if (nread < 0)
162     {
163       TRACE_LOG1 ("err %s", qPrintable (chan->errorString ()));
164       saved_errno = EIO;
165       nread = -1;
166     }
167
168   TRACE_LOGBUF ((char *) buffer, nread);
169
170   errno = saved_errno;
171   return TRACE_SYSRES (nread);
172 }
173
174
175 int
176 _gpgme_io_write (int fd, const void *buffer, size_t count)
177 {
178   qint64 nwritten;
179   KDPipeIODevice *chan;
180   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
181               "buffer=%p, count=%u", buffer, count);
182   TRACE_LOGBUF ((char *) buffer, count);
183
184   chan = find_channel (fd, 0);
185   if (!chan)
186     {
187       TRACE_LOG ("fd %d: no channel registered");
188       errno = EINVAL;
189       return -1;
190     }
191
192   if ( iodevice_table[fd] && !iodevice_table[fd]->blocking && chan->writeWouldBlock() )
193   {
194       errno = EAGAIN;
195       return TRACE_SYSRES( -1 );
196   }
197   nwritten = chan->write ((char *) buffer, count);
198
199   if (nwritten < 0)
200     {
201       nwritten = -1;
202       errno = EIO;
203       return TRACE_SYSRES(-1);
204     }
205   errno = 0;
206   return TRACE_SYSRES (nwritten);
207 }
208
209
210 int
211 _gpgme_io_pipe (int filedes[2], int inherit_idx)
212 {
213   KDPipeIODevice *chan;
214   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
215               "inherit_idx=%i (GPGME uses it for %s)",
216               inherit_idx, inherit_idx ? "reading" : "writing");
217
218 #define PIPEBUF_SIZE  4096
219   if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
220     return TRACE_SYSRES (-1);
221
222   /* Make one end inheritable. */
223   if (inherit_idx == 0)
224     {
225       int new_read;
226
227       new_read = _dup (filedes[0]);
228       _close (filedes[0]);
229       filedes[0] = new_read;
230
231       if (new_read < 0)
232         {
233           _close (filedes[1]);
234           return TRACE_SYSRES (-1);
235         }
236     }
237   else if (inherit_idx == 1)
238     {
239       int new_write;
240
241       new_write = _dup (filedes[1]);
242       _close (filedes[1]);
243       filedes[1] = new_write;
244
245       if (new_write < 0)
246         {
247           _close (filedes[0]);
248           return TRACE_SYSRES (-1);
249         }
250     }
251
252   /* Now we have a pipe with the right end inheritable.  The other end
253      should have a giochannel.  */
254
255   chan = find_channel (filedes[1 - inherit_idx], 1);
256
257   if (!chan)
258     {
259       int saved_errno = errno;
260       _close (filedes[0]);
261       _close (filedes[1]);
262       errno = saved_errno;
263       return TRACE_SYSRES (-1);
264     }
265
266   return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p",
267           filedes[0], (HANDLE) _get_osfhandle (filedes[0]),
268           filedes[1], (HANDLE) _get_osfhandle (filedes[1]),
269           chan);
270 }
271
272 int
273 _gpgme_io_close (int fd)
274 {
275   KDPipeIODevice *chan;
276   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
277
278   if (fd < 0 || fd >= MAX_SLAFD)
279     {
280       errno = EBADF;
281       return TRACE_SYSRES (-1);
282     }
283
284   /* First call the notify handler.  */
285   if (notify_table[fd].handler)
286     {
287       notify_table[fd].handler (fd, notify_table[fd].value);
288       notify_table[fd].handler = NULL;
289       notify_table[fd].value = NULL;
290     }
291
292   /* Then do the close.  */    
293   
294   DeviceEntry* const entry = iodevice_table[fd];
295   if ( entry ) {
296       if ( entry->unref() == 0 ) {
297           entry->iodev->close();
298           delete entry->iodev;
299           delete entry;
300           iodevice_table[fd] = 0;
301       }
302   } else {
303       _close( fd );
304   }
305
306   
307
308   return 0;
309 }
310
311
312 int
313 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
314                             void *value)
315 {
316   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
317               "close_handler=%p/%p", handler, value);
318
319   assert (fd != -1);
320
321   if (fd < 0 || fd >= (int) DIM (notify_table))
322     {
323       errno = EINVAL;
324       return TRACE_SYSRES (-1);
325     }
326   notify_table[fd].handler = handler;
327   notify_table[fd].value = value;
328   return TRACE_SYSRES (0);
329 }
330
331
332 int
333 _gpgme_io_set_nonblocking (int fd)
334 {
335   DeviceEntry* const entry = iodevice_table[fd];
336   assert( entry );
337   entry->blocking = false; 
338   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
339   return TRACE_SYSRES (0);
340 }
341
342
343 static char *
344 build_commandline (char **argv)
345 {
346   int i;
347   int n = 0;
348   char *buf;
349   char *p;
350   
351   /* We have to quote some things because under Windows the program
352      parses the commandline and does some unquoting.  We enclose the
353      whole argument in double-quotes, and escape literal double-quotes
354      as well as backslashes with a backslash.  We end up with a
355      trailing space at the end of the line, but that is harmless.  */
356   for (i = 0; argv[i]; i++)
357     {
358       p = argv[i];
359       /* The leading double-quote.  */
360       n++;
361       while (*p)
362       {
363           /* An extra one for each literal that must be escaped.  */
364           if (*p == '\\' || *p == '"')
365             n++;
366           n++;
367           p++;
368         }
369       /* The trailing double-quote and the delimiter.  */
370       n += 2;
371     }
372   /* And a trailing zero.  */
373   n++;
374
375   buf = p = (char *) malloc (n);
376   if (!buf)
377     return NULL;
378   for (i = 0; argv[i]; i++)
379     {
380       char *argvp = argv[i];
381
382       *(p++) = '"';
383       while (*argvp)
384         {
385           if (*argvp == '\\' || *argvp == '"')
386             *(p++) = '\\';
387           *(p++) = *(argvp++);
388         }
389       *(p++) = '"';
390       *(p++) = ' ';
391     }
392   *(p++) = 0;
393
394   return buf;
395 }
396
397
398 int
399 _gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags,
400                  struct spawn_fd_item_s *fd_list,
401                  void (*atfork) (void *opaque, int reserved),
402                  void *atforkvalue, pid_t *r_pid)
403 {
404   SECURITY_ATTRIBUTES sec_attr;
405   PROCESS_INFORMATION pi =
406     {
407       NULL,      /* returns process handle */
408       0,         /* returns primary thread handle */
409       0,         /* returns pid */
410       0         /* returns tid */
411     };
412   STARTUPINFO si;
413   int cr_flags = CREATE_DEFAULT_ERROR_MODE
414     | GetPriorityClass (GetCurrentProcess ());
415   int i;
416   char **args;
417   char *arg_string;
418   /* FIXME.  */
419   int debug_me = 0;
420   int tmp_fd;
421   char *tmp_name;
422
423   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
424               "path=%s", path);
425   i = 0;
426   while (argv[i])
427     {
428       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
429       i++;
430     }
431   
432   /* We do not inherit any handles by default, and just insert those
433      handles we want the child to have afterwards.  But some handle
434      values occur on the command line, and we need to move
435      stdin/out/err to the right location.  So we use a wrapper program
436      which gets the information from a temporary file.  */
437   if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
438     {
439       TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
440       return TRACE_SYSRES (-1);
441     }
442   TRACE_LOG1 ("tmp_name = %s", tmp_name);
443
444   args = (char **) calloc (2 + i + 1, sizeof (*args));
445   args[0] = (char *) _gpgme_get_w32spawn_path ();
446   args[1] = tmp_name;
447   args[2] = const_cast<char *>(path);
448   memcpy (&args[3], &argv[1], i * sizeof (*args));
449
450   memset (&sec_attr, 0, sizeof sec_attr);
451   sec_attr.nLength = sizeof sec_attr;
452   sec_attr.bInheritHandle = FALSE;
453   
454   arg_string = build_commandline (args);
455   free (args);
456   if (!arg_string)
457     {
458       close (tmp_fd);
459       DeleteFile (tmp_name);
460       return TRACE_SYSRES (-1);
461     }
462   
463   memset (&si, 0, sizeof si);
464   si.cb = sizeof (si);
465   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
466   si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
467   si.hStdInput = INVALID_HANDLE_VALUE;
468   si.hStdOutput = INVALID_HANDLE_VALUE;
469   si.hStdError = INVALID_HANDLE_VALUE;
470
471   cr_flags |= CREATE_SUSPENDED;
472   cr_flags |= DETACHED_PROCESS;
473   if (!CreateProcessA (_gpgme_get_w32spawn_path (),
474                        arg_string,
475                        &sec_attr,     /* process security attributes */
476                        &sec_attr,     /* thread security attributes */
477                        FALSE,         /* inherit handles */
478                        cr_flags,      /* creation flags */
479                        NULL,          /* environment */
480                        NULL,          /* use current drive/directory */
481                        &si,           /* startup information */
482                        &pi))          /* returns process information */
483     {
484       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
485       free (arg_string);
486       close (tmp_fd);
487       DeleteFile (tmp_name);
488
489       /* FIXME: Should translate the error code.  */
490       errno = EIO;
491       return TRACE_SYSRES (-1);
492     }
493
494   free (arg_string);
495
496   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
497     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
498
499   /* Insert the inherited handles.  */
500   for (i = 0; fd_list[i].fd != -1; i++)
501     {
502       HANDLE hd;
503
504       if (!DuplicateHandle (GetCurrentProcess(),
505                             (HANDLE) _get_osfhandle (fd_list[i].fd),
506                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
507         {
508           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
509           TerminateProcess (pi.hProcess, 0);
510           /* Just in case TerminateProcess didn't work, let the
511              process fail on its own.  */
512           ResumeThread (pi.hThread);
513           CloseHandle (pi.hThread);
514           CloseHandle (pi.hProcess);
515
516           close (tmp_fd);
517           DeleteFile (tmp_name);
518
519           /* FIXME: Should translate the error code.  */
520           errno = EIO;
521           return TRACE_SYSRES (-1);
522         }
523       /* Return the child name of this handle.  */
524       fd_list[i].peer_name = (int) hd;
525     }
526     
527   /* Write the handle translation information to the temporary
528      file.  */
529   {
530     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
531        notation: "0xFEDCBA9876543210" with an extra white space after
532        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
533        for a time when a HANDLE is 64 bit.  */
534 #define BUFFER_MAX 800
535     char line[BUFFER_MAX + 1];
536     int res;
537     int written;
538     size_t len;
539
540     if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
541       strcpy (line, "~1 \n");
542     else
543       strcpy (line, "\n");
544     for (i = 0; fd_list[i].fd != -1; i++)
545       {
546         /* Strip the newline.  */
547         len = strlen (line) - 1;
548         
549         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
550         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
551                   fd_list[i].fd, fd_list[i].dup_to,
552                   fd_list[i].peer_name, fd_list[i].arg_loc);
553         /* Rather safe than sorry.  */
554         line[BUFFER_MAX - 1] = '\n';
555         line[BUFFER_MAX] = '\0';
556       }
557     len = strlen (line);
558     written = 0;
559     do
560       {
561         res = write (tmp_fd, &line[written], len - written);
562         if (res > 0)
563           written += res;
564       }
565     while (res > 0 || (res < 0 && errno == EAGAIN));
566   }
567   close (tmp_fd);
568   /* The temporary file is deleted by the gpgme-w32spawn process
569      (hopefully).  */
570   
571   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
572               "dwProcessID=%d, dwThreadId=%d",
573               pi.hProcess, pi.hThread, 
574               (int) pi.dwProcessId, (int) pi.dwThreadId);
575
576   if (r_pid)
577     *r_pid = (pid_t)pi.dwProcessId;
578   
579   if (ResumeThread (pi.hThread) < 0)
580     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
581   
582   if (!CloseHandle (pi.hThread))
583     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
584                 (int) GetLastError ());
585
586   TRACE_LOG1 ("process=%p", pi.hProcess);
587
588   /* We don't need to wait for the process.  */
589   if (!CloseHandle (pi.hProcess))
590     TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
591                 (int) GetLastError ());
592
593   for (i = 0; fd_list[i].fd != -1; i++)
594     _gpgme_io_close (fd_list[i].fd);
595
596   for (i = 0; fd_list[i].fd != -1; i++)
597     if (fd_list[i].dup_to == -1)
598       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
599                   fd_list[i].peer_name);
600     else
601       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
602                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
603                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
604
605   return TRACE_SYSRES (0);
606 }
607
608
609 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
610    nothing to select, > 0 = number of signaled fds.  */
611 int
612 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
613 {
614   /* Use a 1s timeout.  */
615
616   void *dbg_help = NULL;
617   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
618               "nfds=%u, nonblock=%u", nfds, nonblock);
619
620   int count = 0;
621
622   TRACE_SEQ (dbg_help, "select on [ ");
623   for (int i = 0; i < nfds; i++)
624     {
625       if (fds[i].fd == -1)
626         {
627           fds[i].signaled = 0;
628         }
629       else if (fds[i].for_read )
630       {
631           KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
632           assert (chan);
633           if ( nonblock )
634               fds[i].signaled = chan->readWouldBlock() ? 0 : 1;
635           else
636               fds[i].signaled = chan->waitForReadyRead( 1000 ) ? 1 : 0;
637           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
638           if ( fds[i].signaled ) 
639               count++;
640         }
641       else if (fds[i].for_write)
642         {
643           const KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
644           assert (chan);
645           fds[i].signaled = nonblock ? ( chan->writeWouldBlock() ? 0 : 1 ) : 1;
646           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
647           if ( fds[i].signaled ) 
648               count++;
649         }
650     }
651   TRACE_END (dbg_help, "]"); 
652
653   return TRACE_SYSRES (count);
654 }
655
656
657 /* Look up the qiodevice for file descriptor FD.  */
658 extern "C"
659 void *
660 gpgme_get_fdptr (int fd)
661 {
662   return find_channel (fd, 0);
663 }
664
665
666 /* Obsolete compatibility interface.  */
667 extern "C"
668 void *
669 gpgme_get_giochannel (int fd)
670 {
671   return NULL;
672 }
673
674
675 int
676 _gpgme_io_dup (int fd)
677 {
678     assert( iodevice_table[fd] );
679     iodevice_table[fd]->ref();
680     return fd;
681 }
682
683 \f
684 extern "C"
685 int
686 _gpgme_io_socket (int domain, int type, int proto)
687 {
688   errno = EIO;
689   return -1;
690 }
691
692
693 extern "C"
694 int
695 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
696 {
697   errno = EIO;
698   return -1;
699 }