Improve the debug output a bit.
[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   if ((flags & IOSPAWN_FLAG_DETACHED))
473     cr_flags |= DETACHED_PROCESS;
474   if (!CreateProcessA (_gpgme_get_w32spawn_path (),
475                        arg_string,
476                        &sec_attr,     /* process security attributes */
477                        &sec_attr,     /* thread security attributes */
478                        FALSE,         /* inherit handles */
479                        cr_flags,      /* creation flags */
480                        NULL,          /* environment */
481                        NULL,          /* use current drive/directory */
482                        &si,           /* startup information */
483                        &pi))          /* returns process information */
484     {
485       TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
486       free (arg_string);
487       close (tmp_fd);
488       DeleteFile (tmp_name);
489
490       /* FIXME: Should translate the error code.  */
491       errno = EIO;
492       return TRACE_SYSRES (-1);
493     }
494
495   free (arg_string);
496
497   if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
498     _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
499
500   /* Insert the inherited handles.  */
501   for (i = 0; fd_list[i].fd != -1; i++)
502     {
503       HANDLE hd;
504
505       if (!DuplicateHandle (GetCurrentProcess(),
506                             (HANDLE) _get_osfhandle (fd_list[i].fd),
507                             pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
508         {
509           TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
510           TerminateProcess (pi.hProcess, 0);
511           /* Just in case TerminateProcess didn't work, let the
512              process fail on its own.  */
513           ResumeThread (pi.hThread);
514           CloseHandle (pi.hThread);
515           CloseHandle (pi.hProcess);
516
517           close (tmp_fd);
518           DeleteFile (tmp_name);
519
520           /* FIXME: Should translate the error code.  */
521           errno = EIO;
522           return TRACE_SYSRES (-1);
523         }
524       /* Return the child name of this handle.  */
525       fd_list[i].peer_name = (int) hd;
526     }
527
528   /* Write the handle translation information to the temporary
529      file.  */
530   {
531     /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
532        notation: "0xFEDCBA9876543210" with an extra white space after
533        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
534        for a time when a HANDLE is 64 bit.  */
535 #define BUFFER_MAX 800
536     char line[BUFFER_MAX + 1];
537     int res;
538     int written;
539     size_t len;
540
541     if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
542       strcpy (line, "~1 \n");
543     else
544       strcpy (line, "\n");
545     for (i = 0; fd_list[i].fd != -1; i++)
546       {
547         /* Strip the newline.  */
548         len = strlen (line) - 1;
549
550         /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */
551         snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n",
552                   fd_list[i].fd, fd_list[i].dup_to,
553                   fd_list[i].peer_name, fd_list[i].arg_loc);
554         /* Rather safe than sorry.  */
555         line[BUFFER_MAX - 1] = '\n';
556         line[BUFFER_MAX] = '\0';
557       }
558     len = strlen (line);
559     written = 0;
560     do
561       {
562         res = write (tmp_fd, &line[written], len - written);
563         if (res > 0)
564           written += res;
565       }
566     while (res > 0 || (res < 0 && errno == EAGAIN));
567   }
568   close (tmp_fd);
569   /* The temporary file is deleted by the gpgme-w32spawn process
570      (hopefully).  */
571
572   TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
573               "dwProcessID=%d, dwThreadId=%d",
574               pi.hProcess, pi.hThread,
575               (int) pi.dwProcessId, (int) pi.dwThreadId);
576
577   if (r_pid)
578     *r_pid = (pid_t)pi.dwProcessId;
579
580   if (ResumeThread (pi.hThread) < 0)
581     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
582
583   if (!CloseHandle (pi.hThread))
584     TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
585                 (int) GetLastError ());
586
587   TRACE_LOG1 ("process=%p", pi.hProcess);
588
589   /* We don't need to wait for the process.  */
590   if (!CloseHandle (pi.hProcess))
591     TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
592                 (int) GetLastError ());
593
594   for (i = 0; fd_list[i].fd != -1; i++)
595     _gpgme_io_close (fd_list[i].fd);
596
597   for (i = 0; fd_list[i].fd != -1; i++)
598     if (fd_list[i].dup_to == -1)
599       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
600                   fd_list[i].peer_name);
601     else
602       TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
603                   fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
604                   ((fd_list[i].dup_to == 1) ? "out" : "err"));
605
606   return TRACE_SYSRES (0);
607 }
608
609
610 /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
611    nothing to select, > 0 = number of signaled fds.  */
612 int
613 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
614 {
615   /* Use a 1s timeout.  */
616
617   void *dbg_help = NULL;
618   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
619               "nfds=%u, nonblock=%u", nfds, nonblock);
620
621   int count = 0;
622
623   TRACE_SEQ (dbg_help, "select on [ ");
624   for (int i = 0; i < nfds; i++)
625     {
626       if (fds[i].fd == -1)
627         {
628           fds[i].signaled = 0;
629         }
630       else if (fds[i].for_read )
631       {
632           KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
633           assert (chan);
634           if ( nonblock )
635               fds[i].signaled = chan->readWouldBlock() ? 0 : 1;
636           else
637               fds[i].signaled = chan->waitForReadyRead( 1000 ) ? 1 : 0;
638           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
639           if ( fds[i].signaled )
640               count++;
641         }
642       else if (fds[i].for_write)
643         {
644           const KDPipeIODevice * const chan = find_channel (fds[i].fd, 0);
645           assert (chan);
646           fds[i].signaled = nonblock ? ( chan->writeWouldBlock() ? 0 : 1 ) : 1;
647           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
648           if ( fds[i].signaled )
649               count++;
650         }
651     }
652   TRACE_END (dbg_help, "]");
653
654   return TRACE_SYSRES (count);
655 }
656
657
658 /* Look up the qiodevice for file descriptor FD.  */
659 extern "C"
660 void *
661 gpgme_get_fdptr (int fd)
662 {
663   return find_channel (fd, 0);
664 }
665
666
667 /* Obsolete compatibility interface.  */
668 extern "C"
669 void *
670 gpgme_get_giochannel (int fd)
671 {
672   return NULL;
673 }
674
675
676 int
677 _gpgme_io_dup (int fd)
678 {
679     assert( iodevice_table[fd] );
680     iodevice_table[fd]->ref();
681     return fd;
682 }
683
684 \f
685 extern "C"
686 int
687 _gpgme_io_socket (int domain, int type, int proto)
688 {
689   errno = EIO;
690   return -1;
691 }
692
693
694 extern "C"
695 int
696 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
697 {
698   errno = EIO;
699   return -1;
700 }