2007-07-13 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / w32-io.c
1 /* w32-io.c - W32 API I/O functions.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004 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 <sys/time.h>
33 #include <sys/types.h>
34 #include <windows.h>
35 #include <io.h>
36
37 #include "util.h"
38 #include "sema.h"
39 #include "priv-io.h"
40 #include "debug.h"
41
42 /* We assume that a HANDLE can be represented by an int which should
43    be true for all i386 systems (HANDLE is defined as void *) and
44    these are the only systems for which Windows is available.  Further
45    we assume that -1 denotes an invalid handle.  */
46
47 #define fd_to_handle(a)  ((HANDLE)(a))
48 #define handle_to_fd(a)  ((int)(a))
49 #define pid_to_handle(a) ((HANDLE)(a))
50 #define handle_to_pid(a) ((int)(a))
51
52 #define READBUF_SIZE 4096
53 #define WRITEBUF_SIZE 4096
54 #define PIPEBUF_SIZE  4096
55 #define MAX_READERS 20
56 #define MAX_WRITERS 20
57
58 static struct
59 {
60   int inuse;
61   int fd;
62   _gpgme_close_notify_handler_t handler;
63   void *value;
64 } notify_table[256];
65 DEFINE_STATIC_LOCK (notify_table_lock);
66
67
68 struct reader_context_s {
69     HANDLE file_hd;
70     HANDLE thread_hd;   
71     DECLARE_LOCK (mutex);
72
73     int stop_me;
74     int eof;
75     int eof_shortcut;
76     int error;
77     int error_code;
78
79     HANDLE have_data_ev;  /* manually reset */
80     HANDLE have_space_ev; /* auto reset */
81     HANDLE stopped;
82     size_t readpos, writepos;
83     char buffer[READBUF_SIZE];
84 };
85
86
87 static struct {
88     volatile int used;
89     int fd;
90     struct reader_context_s *context;
91 } reader_table[MAX_READERS];
92 static int reader_table_size= MAX_READERS;
93 DEFINE_STATIC_LOCK (reader_table_lock);
94
95
96 struct writer_context_s {
97     HANDLE file_hd;
98     HANDLE thread_hd;   
99     DECLARE_LOCK (mutex);
100
101     int stop_me;
102     int error;
103     int error_code;
104
105     HANDLE have_data;  /* manually reset */
106     HANDLE is_empty;
107     HANDLE stopped;
108     size_t nbytes; 
109     char buffer[WRITEBUF_SIZE];
110 };
111
112
113 static struct {
114     volatile int used;
115     int fd;
116     struct writer_context_s *context;
117 } writer_table[MAX_WRITERS];
118 static int writer_table_size= MAX_WRITERS;
119 DEFINE_STATIC_LOCK (writer_table_lock);
120
121
122
123 static int
124 get_desired_thread_priority (void)
125 {
126   int value;
127
128   if (!_gpgme_get_conf_int ("IOThreadPriority", &value))
129     {
130       value = THREAD_PRIORITY_HIGHEST;
131       DEBUG1 ("** Using standard IOThreadPriority of %d\n", value);
132     }
133   else
134     DEBUG1 ("** Configured IOThreadPriority is %d\n", value);
135
136   return value;
137 }
138
139
140 static HANDLE
141 set_synchronize (HANDLE h)
142 {
143     HANDLE tmp;
144     
145     /* For NT we have to set the sync flag.  It seems that the only
146      * way to do it is by duplicating the handle.  Tsss.. */
147     if (!DuplicateHandle( GetCurrentProcess(), h,
148                           GetCurrentProcess(), &tmp,
149                           EVENT_MODIFY_STATE|SYNCHRONIZE, FALSE, 0 ) ) {
150         DEBUG1 ("** Set SYNCRONIZE failed: ec=%d\n", (int)GetLastError());
151     }
152     else {
153         CloseHandle (h);
154         h = tmp;
155     }
156     return h;
157 }
158
159
160
161 static DWORD CALLBACK 
162 reader (void *arg)
163 {
164     struct reader_context_s *c = arg;
165     int nbytes;
166     DWORD nread;
167
168     DEBUG2 ("reader thread %p for file %p started", c->thread_hd, c->file_hd );
169     for (;;) {
170         LOCK (c->mutex);
171         /* leave a 1 byte gap so that we can see whether it is empty or full*/
172         if ((c->writepos + 1) % READBUF_SIZE == c->readpos) { 
173             /* wait for space */
174             if (!ResetEvent (c->have_space_ev) )
175                 DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
176             UNLOCK (c->mutex);
177             DEBUG1 ("reader thread %p: waiting for space ...", c->thread_hd );
178             WaitForSingleObject (c->have_space_ev, INFINITE);
179             DEBUG1 ("reader thread %p: got space", c->thread_hd );
180             LOCK (c->mutex);
181         }
182         if ( c->stop_me ) {
183             UNLOCK (c->mutex);
184             break;
185         }
186         nbytes = (c->readpos + READBUF_SIZE - c->writepos-1) % READBUF_SIZE;
187         if ( nbytes > READBUF_SIZE - c->writepos )
188             nbytes = READBUF_SIZE - c->writepos;
189         UNLOCK (c->mutex);
190
191         DEBUG2 ("reader thread %p: reading %d bytes", c->thread_hd, nbytes );
192         if ( !ReadFile ( c->file_hd,
193                          c->buffer+c->writepos, nbytes, &nread, NULL) ) {
194             c->error_code = (int)GetLastError ();
195             if (c->error_code == ERROR_BROKEN_PIPE ) {
196                 c->eof=1;
197                 DEBUG1 ("reader thread %p: got eof (broken pipe)",
198                         c->thread_hd );
199             }
200             else {
201                 c->error = 1;
202                 DEBUG2 ("reader thread %p: read error: ec=%d",
203                         c->thread_hd, c->error_code );
204             }
205             break;
206         }
207         if ( !nread ) {
208             c->eof = 1;
209             DEBUG1 ("reader thread %p: got eof", c->thread_hd );
210             break;
211         }
212         DEBUG2 ("reader thread %p: got %d bytes", c->thread_hd, (int)nread );
213       
214         LOCK (c->mutex);
215         if (c->stop_me) {
216             UNLOCK (c->mutex);
217             break;
218         }
219         c->writepos = (c->writepos + nread) % READBUF_SIZE;
220         if ( !SetEvent (c->have_data_ev) )
221             DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
222         UNLOCK (c->mutex);
223     }
224     /* indicate that we have an error or eof */
225     if ( !SetEvent (c->have_data_ev) )
226         DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
227     DEBUG1 ("reader thread %p ended", c->thread_hd );
228     SetEvent (c->stopped);
229
230     return 0;
231 }
232
233
234 static struct reader_context_s *
235 create_reader (HANDLE fd)
236 {
237     struct reader_context_s *c;
238     SECURITY_ATTRIBUTES sec_attr;
239     DWORD tid;
240
241     DEBUG1 ("creating new read thread for file handle %p", fd );
242     memset (&sec_attr, 0, sizeof sec_attr );
243     sec_attr.nLength = sizeof sec_attr;
244     sec_attr.bInheritHandle = FALSE;
245
246     c = calloc (1, sizeof *c );
247     if (!c)
248         return NULL;
249
250     c->file_hd = fd;
251     c->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
252     c->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
253     c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
254     if (!c->have_data_ev || !c->have_space_ev || !c->stopped ) {
255         DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ());
256         if (c->have_data_ev)
257             CloseHandle (c->have_data_ev);
258         if (c->have_space_ev)
259             CloseHandle (c->have_space_ev);
260         if (c->stopped)
261             CloseHandle (c->stopped);
262         free (c);
263         return NULL;
264     }
265
266     c->have_data_ev = set_synchronize (c->have_data_ev);
267     INIT_LOCK (c->mutex);
268
269     c->thread_hd = CreateThread (&sec_attr, 0, reader, c, 0, &tid );
270     if (!c->thread_hd) {
271         DEBUG1 ("** failed to create reader thread: ec=%d\n",
272                  (int)GetLastError ());
273         DESTROY_LOCK (c->mutex);
274         if (c->have_data_ev)
275             CloseHandle (c->have_data_ev);
276         if (c->have_space_ev)
277             CloseHandle (c->have_space_ev);
278         if (c->stopped)
279             CloseHandle (c->stopped);
280         free (c);
281         return NULL;
282     }    
283     else {
284       /* We set the priority of the thread higher because we know that
285          it only runs for a short time.  This greatly helps to increase
286          the performance of the I/O. */
287       SetThreadPriority (c->thread_hd, get_desired_thread_priority ());
288     }
289
290     return c;
291 }
292
293 static void
294 destroy_reader (struct reader_context_s *c)
295 {
296     LOCK (c->mutex);
297     c->stop_me = 1;
298     if (c->have_space_ev) 
299         SetEvent (c->have_space_ev);
300     UNLOCK (c->mutex);
301
302     DEBUG1 ("waiting for thread %p termination ...", c->thread_hd );
303     WaitForSingleObject (c->stopped, INFINITE);
304     DEBUG1 ("thread %p has terminated", c->thread_hd );
305     
306     if (c->stopped)
307         CloseHandle (c->stopped);
308     if (c->have_data_ev)
309         CloseHandle (c->have_data_ev);
310     if (c->have_space_ev)
311         CloseHandle (c->have_space_ev);
312     CloseHandle (c->thread_hd);
313     DESTROY_LOCK (c->mutex);
314     free (c);
315 }
316
317
318 /* 
319  * Find a reader context or create a new one 
320  * Note that the reader context will last until a io_close.
321  */
322 static struct reader_context_s *
323 find_reader (int fd, int start_it)
324 {
325     int i;
326
327     for (i=0; i < reader_table_size ; i++ ) {
328         if ( reader_table[i].used && reader_table[i].fd == fd )
329             return reader_table[i].context;
330     }
331     if (!start_it)
332         return NULL;
333
334     LOCK (reader_table_lock);
335     for (i=0; i < reader_table_size; i++ ) {
336         if (!reader_table[i].used) {
337             reader_table[i].fd = fd;
338             reader_table[i].context = create_reader (fd_to_handle (fd));
339             reader_table[i].used = 1;
340             UNLOCK (reader_table_lock);
341             return reader_table[i].context;
342         }
343     }
344     UNLOCK (reader_table_lock);
345     return NULL;
346 }
347
348
349 static void
350 kill_reader (int fd)
351 {
352     int i;
353
354     LOCK (reader_table_lock);
355     for (i=0; i < reader_table_size; i++ ) {
356         if (reader_table[i].used && reader_table[i].fd == fd ) {
357             destroy_reader (reader_table[i].context);
358             reader_table[i].context = NULL;
359             reader_table[i].used = 0;
360             break;
361         }
362     }
363     UNLOCK (reader_table_lock);
364 }
365
366
367
368 int
369 _gpgme_io_read ( int fd, void *buffer, size_t count )
370 {
371     int nread;
372     struct reader_context_s *c = find_reader (fd,1);
373
374     DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int)count );
375     if ( !c ) {
376         DEBUG0 ( "no reader thread\n");
377         return -1;
378     }
379     if (c->eof_shortcut) {
380         DEBUG1 ("fd %d: EOF (again)", fd );
381         return 0;
382     }
383
384     LOCK (c->mutex);
385     if (c->readpos == c->writepos && !c->error) { /*no data avail*/
386         UNLOCK (c->mutex);
387         DEBUG2 ("fd %d: waiting for data from thread %p", fd, c->thread_hd);
388         WaitForSingleObject (c->have_data_ev, INFINITE);
389         DEBUG2 ("fd %d: data from thread %p available", fd, c->thread_hd);
390         LOCK (c->mutex);
391     }
392     
393     if (c->readpos == c->writepos || c->error) {
394         UNLOCK (c->mutex);
395         c->eof_shortcut = 1;
396         if (c->eof) {
397             DEBUG1 ("fd %d: EOF", fd );
398             return 0;
399         }
400         if (!c->error) {
401             DEBUG1 ("fd %d: EOF but eof flag not set", fd );
402             return 0;
403         }
404         DEBUG1 ("fd %d: read error", fd );
405         return -1;
406     }
407       
408     nread = c->readpos < c->writepos? c->writepos - c->readpos
409                                     : READBUF_SIZE - c->readpos;
410     if (nread > count)
411         nread = count;
412     memcpy (buffer, c->buffer+c->readpos, nread);
413     c->readpos = (c->readpos + nread) % READBUF_SIZE;
414     if (c->readpos == c->writepos && !c->eof) {
415         if ( !ResetEvent (c->have_data_ev) )
416             DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
417     }
418     if (!SetEvent (c->have_space_ev))
419         DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
420     UNLOCK (c->mutex);
421
422     DEBUG2 ("fd %d: got %d bytes\n", fd, nread );
423     if (nread > 0)
424       _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);
425
426     return nread;
427 }
428 /*
429  * The writer does use a simple buffering strategy so that we are
430  * informed about write errors as soon as possible (i.e. with the the
431  * next call to the write function
432  */
433 static DWORD CALLBACK 
434 writer (void *arg)
435 {
436     struct writer_context_s *c = arg;
437     DWORD nwritten;
438
439     DEBUG2 ("writer thread %p for file %p started", c->thread_hd, c->file_hd );
440     for (;;) {
441         LOCK (c->mutex);
442         if ( c->stop_me ) {
443             UNLOCK (c->mutex);
444             break;
445         }
446         if ( !c->nbytes ) { 
447             if (!SetEvent (c->is_empty))
448                 DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
449             if (!ResetEvent (c->have_data) )
450                 DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
451             UNLOCK (c->mutex);
452             DEBUG1 ("writer thread %p: idle ...", c->thread_hd );
453             WaitForSingleObject (c->have_data, INFINITE);
454             DEBUG1 ("writer thread %p: got data to send", c->thread_hd );
455             LOCK (c->mutex);
456         }
457         if ( c->stop_me ) {
458             UNLOCK (c->mutex);
459             break;
460         }
461         UNLOCK (c->mutex);
462
463         DEBUG2 ("writer thread %p: writing %d bytes",
464                 c->thread_hd, c->nbytes );
465         if ( c->nbytes && !WriteFile ( c->file_hd,  c->buffer, c->nbytes,
466                                        &nwritten, NULL)) {
467             c->error_code = (int)GetLastError ();
468             c->error = 1;
469             DEBUG2 ("writer thread %p: write error: ec=%d",
470                     c->thread_hd, c->error_code );
471             break;
472         }
473         DEBUG2 ("writer thread %p: wrote %d bytes",
474                 c->thread_hd, (int)nwritten );
475       
476         LOCK (c->mutex);
477         c->nbytes -= nwritten;
478         UNLOCK (c->mutex);
479     }
480     /* indicate that we have an error  */
481     if ( !SetEvent (c->is_empty) )
482         DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
483     DEBUG1 ("writer thread %p ended", c->thread_hd );
484     SetEvent (c->stopped);
485
486     return 0;
487 }
488
489
490 static struct writer_context_s *
491 create_writer (HANDLE fd)
492 {
493     struct writer_context_s *c;
494     SECURITY_ATTRIBUTES sec_attr;
495     DWORD tid;
496
497     DEBUG1 ("creating new write thread for file handle %p", fd );
498     memset (&sec_attr, 0, sizeof sec_attr );
499     sec_attr.nLength = sizeof sec_attr;
500     sec_attr.bInheritHandle = FALSE;
501
502     c = calloc (1, sizeof *c );
503     if (!c)
504         return NULL;
505
506     c->file_hd = fd;
507     c->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
508     c->is_empty  = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
509     c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
510     if (!c->have_data || !c->is_empty || !c->stopped ) {
511         DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ());
512         if (c->have_data)
513             CloseHandle (c->have_data);
514         if (c->is_empty)
515             CloseHandle (c->is_empty);
516         if (c->stopped)
517             CloseHandle (c->stopped);
518         free (c);
519         return NULL;
520     }
521
522     c->is_empty = set_synchronize (c->is_empty);
523     INIT_LOCK (c->mutex);
524
525     c->thread_hd = CreateThread (&sec_attr, 0, writer, c, 0, &tid );
526     if (!c->thread_hd) {
527         DEBUG1 ("** failed to create writer thread: ec=%d\n",
528                  (int)GetLastError ());
529         DESTROY_LOCK (c->mutex);
530         if (c->have_data)
531             CloseHandle (c->have_data);
532         if (c->is_empty)
533             CloseHandle (c->is_empty);
534         if (c->stopped)
535             CloseHandle (c->stopped);
536         free (c);
537         return NULL;
538     }    
539     else {
540       /* We set the priority of the thread higher because we know that
541          it only runs for a short time.  This greatly helps to increase
542          the performance of the I/O. */
543       SetThreadPriority (c->thread_hd, get_desired_thread_priority ());
544     }
545
546     return c;
547 }
548
549 static void
550 destroy_writer (struct writer_context_s *c)
551 {
552     LOCK (c->mutex);
553     c->stop_me = 1;
554     if (c->have_data) 
555         SetEvent (c->have_data);
556     UNLOCK (c->mutex);
557
558     DEBUG1 ("waiting for thread %p termination ...", c->thread_hd );
559     WaitForSingleObject (c->stopped, INFINITE);
560     DEBUG1 ("thread %p has terminated", c->thread_hd );
561     
562     if (c->stopped)
563         CloseHandle (c->stopped);
564     if (c->have_data)
565         CloseHandle (c->have_data);
566     if (c->is_empty)
567         CloseHandle (c->is_empty);
568     CloseHandle (c->thread_hd);
569     DESTROY_LOCK (c->mutex);
570     free (c);
571 }
572
573
574 /* 
575  * Find a writer context or create a new one 
576  * Note that the writer context will last until a io_close.
577  */
578 static struct writer_context_s *
579 find_writer (int fd, int start_it)
580 {
581     int i;
582
583     for (i=0; i < writer_table_size ; i++ ) {
584         if ( writer_table[i].used && writer_table[i].fd == fd )
585             return writer_table[i].context;
586     }
587     if (!start_it)
588         return NULL;
589
590     LOCK (writer_table_lock);
591     for (i=0; i < writer_table_size; i++ ) {
592         if (!writer_table[i].used) {
593             writer_table[i].fd = fd;
594             writer_table[i].context = create_writer (fd_to_handle (fd));
595             writer_table[i].used = 1;
596             UNLOCK (writer_table_lock);
597             return writer_table[i].context;
598         }
599     }
600     UNLOCK (writer_table_lock);
601     return NULL;
602 }
603
604
605 static void
606 kill_writer (int fd)
607 {
608     int i;
609
610     LOCK (writer_table_lock);
611     for (i=0; i < writer_table_size; i++ ) {
612         if (writer_table[i].used && writer_table[i].fd == fd ) {
613             destroy_writer (writer_table[i].context);
614             writer_table[i].context = NULL;
615             writer_table[i].used = 0;
616             break;
617         }
618     }
619     UNLOCK (writer_table_lock);
620 }
621
622
623
624
625 int
626 _gpgme_io_write ( int fd, const void *buffer, size_t count )
627 {
628     struct writer_context_s *c = find_writer (fd,1);
629
630     DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int)count );
631     _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
632     if ( !c ) {
633         DEBUG0 ( "no writer thread\n");
634         return -1;
635     }
636
637     LOCK (c->mutex);
638     if ( c->nbytes ) { /* bytes are pending for send */
639         /* Reset the is_empty event.  Better safe than sorry.  */
640         if (!ResetEvent (c->is_empty))
641             DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
642         UNLOCK (c->mutex);
643         DEBUG2 ("fd %d: waiting for empty buffer in thread %p",
644                 fd, c->thread_hd);
645         WaitForSingleObject (c->is_empty, INFINITE);
646         DEBUG2 ("fd %d: thread %p buffer is empty", fd, c->thread_hd);
647         LOCK (c->mutex);
648     }
649     
650     if ( c->error) {
651         UNLOCK (c->mutex);
652         DEBUG1 ("fd %d: write error", fd );
653         return -1;
654     }
655
656     /* If no error occured, the number of bytes in the buffer must be
657        zero.  */
658     assert (!c->nbytes);
659
660     if (count > WRITEBUF_SIZE)
661         count = WRITEBUF_SIZE;
662     memcpy (c->buffer, buffer, count);
663     c->nbytes = count;
664
665     /* We have to reset the is_empty event early, because it is also
666        used by the select() implementation to probe the channel.  */
667     if (!ResetEvent (c->is_empty))
668         DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
669     if (!SetEvent (c->have_data))
670         DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
671     UNLOCK (c->mutex);
672
673     DEBUG2 ("fd %d:         copied %d bytes\n",
674                    fd, (int)count );
675     return (int)count;
676 }
677
678
679 int
680 _gpgme_io_pipe ( int filedes[2], int inherit_idx )
681 {
682     HANDLE r, w;
683     SECURITY_ATTRIBUTES sec_attr;
684
685     memset (&sec_attr, 0, sizeof sec_attr );
686     sec_attr.nLength = sizeof sec_attr;
687     sec_attr.bInheritHandle = FALSE;
688     
689     if (!CreatePipe ( &r, &w, &sec_attr, PIPEBUF_SIZE))
690         return -1;
691     /* Make one end inheritable. */
692     if ( inherit_idx == 0 ) {
693         HANDLE h;
694         if (!DuplicateHandle( GetCurrentProcess(), r,
695                               GetCurrentProcess(), &h, 0,
696                               TRUE, DUPLICATE_SAME_ACCESS ) ) {
697             DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
698             CloseHandle (r);
699             CloseHandle (w);
700             return -1;
701         }
702         CloseHandle (r);
703         r = h;
704     }
705     else if ( inherit_idx == 1 ) {
706         HANDLE h;
707         if (!DuplicateHandle( GetCurrentProcess(), w,
708                               GetCurrentProcess(), &h, 0,
709                               TRUE, DUPLICATE_SAME_ACCESS ) ) {
710             DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
711             CloseHandle (r);
712             CloseHandle (w);
713             return -1;
714         }
715         CloseHandle (w);
716         w = h;
717     }
718
719     filedes[0] = handle_to_fd (r);
720     filedes[1] = handle_to_fd (w);
721     DEBUG5 ("CreatePipe %p %p %d %d inherit=%d\n", r, w,
722                    filedes[0], filedes[1], inherit_idx );
723     return 0;
724 }
725
726 int
727 _gpgme_io_close ( int fd )
728 {
729     int i;
730     _gpgme_close_notify_handler_t handler = NULL;
731     void *value = NULL;
732     int really_close = 1;
733
734     if ( fd == -1 )
735         return -1;
736
737     DEBUG1 ("** closing handle for fd %d\n", fd);
738     kill_reader (fd);
739     kill_writer (fd);
740     LOCK (notify_table_lock);
741     for ( i=0; i < DIM (notify_table); i++ ) {
742         if (notify_table[i].inuse && notify_table[i].fd == fd) {
743             handler = notify_table[i].handler;
744             value   = notify_table[i].value;
745             notify_table[i].handler = NULL;
746             notify_table[i].value = NULL;
747             notify_table[i].inuse = 0;
748             break;
749         }
750     }
751     UNLOCK (notify_table_lock);
752     if (handler)
753         really_close = handler (fd, value);
754
755     if ( really_close && !CloseHandle (fd_to_handle (fd)) ) { 
756         DEBUG2 ("CloseHandle for fd %d failed: ec=%d\n",
757                  fd, (int)GetLastError ());
758         return -1;
759     }
760
761     return 0;
762 }
763
764 int
765 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
766                             void *value)
767 {
768     int i;
769
770     assert (fd != -1);
771
772     LOCK (notify_table_lock);
773     for (i=0; i < DIM (notify_table); i++ ) {
774         if ( notify_table[i].inuse && notify_table[i].fd == fd )
775             break;
776     }
777     if ( i == DIM (notify_table) ) {
778         for (i=0; i < DIM (notify_table); i++ ) {
779             if ( !notify_table[i].inuse )
780                 break;
781         }
782     }
783     if ( i == DIM (notify_table) ) {
784         UNLOCK (notify_table_lock);
785         return -1;
786     }
787     notify_table[i].fd = fd;
788     notify_table[i].handler = handler;
789     notify_table[i].value = value;
790     notify_table[i].inuse = 1;
791     UNLOCK (notify_table_lock);
792     DEBUG2 ("set notification for fd %d (idx=%d)", fd, i );
793     return 0;
794 }
795
796
797 int
798 _gpgme_io_set_nonblocking ( int fd )
799 {
800     return 0;
801 }
802
803
804 static char *
805 build_commandline (char **argv)
806 {
807   int i;
808   int j;
809   int n = 0;
810   char *buf;
811   char *p;
812   
813   /* We have to quote some things because under Windows the program
814      parses the commandline and does some unquoting.  We enclose the
815      whole argument in double-quotes, and escape literal double-quotes
816      as well as backslashes with a backslash.  We end up with a
817      trailing space at the end of the line, but that is harmless.  */
818   for (i = 0; argv[i]; i++)
819     {
820       p = argv[i];
821       /* The leading double-quote.  */
822       n++;
823       while (*p)
824         {
825           /* An extra one for each literal that must be escaped.  */
826           if (*p == '\\' || *p == '"')
827             n++;
828           n++;
829           p++;
830         }
831       /* The trailing double-quote and the delimiter.  */
832       n += 2;
833     }
834   /* And a trailing zero.  */
835   n++;
836
837   buf = p = malloc (n);
838   if (!buf)
839     return NULL;
840   for (i = 0; argv[i]; i++)
841     {
842       char *argvp = argv[i];
843
844       *(p++) = '"';
845       while (*argvp)
846         {
847           if (*argvp == '\\' || *argvp == '"')
848             *(p++) = '\\';
849           *(p++) = *(argvp++);
850         }
851       *(p++) = '"';
852       *(p++) = ' ';
853     }
854   *(p++) = 0;
855
856   return buf;
857 }
858
859
860 int
861 _gpgme_io_spawn ( const char *path, char **argv,
862                   struct spawn_fd_item_s *fd_child_list,
863                   struct spawn_fd_item_s *fd_parent_list )
864 {
865     SECURITY_ATTRIBUTES sec_attr;
866     PROCESS_INFORMATION pi = {
867         NULL,      /* returns process handle */
868         0,         /* returns primary thread handle */
869         0,         /* returns pid */
870         0         /* returns tid */
871     };
872     STARTUPINFO si;
873     char *envblock = NULL;
874     int cr_flags = CREATE_DEFAULT_ERROR_MODE
875                  | GetPriorityClass (GetCurrentProcess ());
876     int i;
877     char *arg_string;
878     int duped_stdin = 0;
879     int duped_stderr = 0;
880     HANDLE hnul = INVALID_HANDLE_VALUE;
881     /* FIXME.  */
882     int debug_me = 0;
883
884     memset (&sec_attr, 0, sizeof sec_attr );
885     sec_attr.nLength = sizeof sec_attr;
886     sec_attr.bInheritHandle = FALSE;
887
888     arg_string = build_commandline ( argv );
889     if (!arg_string )
890         return -1; 
891
892     memset (&si, 0, sizeof si);
893     si.cb = sizeof (si);
894     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
895     si.wShowWindow = debug_me? SW_SHOW : SW_HIDE;
896     si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
897     si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
898     si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
899
900     for (i=0; fd_child_list[i].fd != -1; i++ ) {
901         if (fd_child_list[i].dup_to == 0 ) {
902             si.hStdInput = fd_to_handle (fd_child_list[i].fd);
903             DEBUG1 ("using %d for stdin", fd_child_list[i].fd );
904             duped_stdin=1;
905         }
906         else if (fd_child_list[i].dup_to == 1 ) {
907             si.hStdOutput = fd_to_handle (fd_child_list[i].fd);
908             DEBUG1 ("using %d for stdout", fd_child_list[i].fd );
909         }
910         else if (fd_child_list[i].dup_to == 2 ) {
911             si.hStdError = fd_to_handle (fd_child_list[i].fd);
912             DEBUG1 ("using %d for stderr", fd_child_list[i].fd );
913             duped_stderr = 1;
914         }
915     }
916
917     if( !duped_stdin || !duped_stderr ) {
918         SECURITY_ATTRIBUTES sa;
919
920         memset (&sa, 0, sizeof sa );
921         sa.nLength = sizeof sa;
922         sa.bInheritHandle = TRUE;
923         hnul = CreateFile ( "nul",
924                             GENERIC_READ|GENERIC_WRITE,
925                             FILE_SHARE_READ|FILE_SHARE_WRITE,
926                             &sa,
927                             OPEN_EXISTING,
928                             FILE_ATTRIBUTE_NORMAL,
929                             NULL );
930         if ( hnul == INVALID_HANDLE_VALUE ) {
931             DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ());
932             free (arg_string);
933             return -1;
934         }
935         /* Make sure that the process has a connected stdin */
936         if ( !duped_stdin ) {
937             si.hStdInput = hnul;
938             DEBUG1 ("using %d for dummy stdin", (int)hnul );
939         }
940         /* We normally don't want all the normal output */
941         if ( !duped_stderr ) {
942             si.hStdError = hnul;
943             DEBUG1 ("using %d for dummy stderr", (int)hnul );
944         }
945     }
946
947     DEBUG2 ("CreateProcess, path=`%s' args=`%s'", path, arg_string);
948     cr_flags |= CREATE_SUSPENDED; 
949     if ( !CreateProcessA (path,
950                           arg_string,
951                           &sec_attr,     /* process security attributes */
952                           &sec_attr,     /* thread security attributes */
953                           TRUE,          /* inherit handles */
954                           cr_flags,      /* creation flags */
955                           envblock,      /* environment */
956                           NULL,          /* use current drive/directory */
957                           &si,           /* startup information */
958                           &pi            /* returns process information */
959         ) ) {
960         DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ());
961         free (arg_string);
962         return -1;
963     }
964
965     /* Close the /dev/nul handle if used. */
966     if (hnul != INVALID_HANDLE_VALUE ) {
967         if ( !CloseHandle ( hnul ) )
968             DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError());
969     }
970
971     /* Close the other ends of the pipes. */
972     for (i = 0; fd_parent_list[i].fd != -1; i++)
973       _gpgme_io_close (fd_parent_list[i].fd);
974
975     DEBUG4 ("CreateProcess ready\n"
976             "-   hProcess=%p  hThread=%p\n"
977             "-   dwProcessID=%d dwThreadId=%d\n",
978             pi.hProcess, pi.hThread, 
979             (int) pi.dwProcessId, (int) pi.dwThreadId);
980
981     if ( ResumeThread ( pi.hThread ) < 0 ) {
982         DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ());
983     }
984
985     if ( !CloseHandle (pi.hThread) ) { 
986         DEBUG1 ("CloseHandle of thread failed: ec=%d\n",
987                  (int)GetLastError ());
988     }
989
990     return handle_to_pid (pi.hProcess);
991 }
992
993
994 /*
995  * Select on the list of fds.
996  * Returns: -1 = error
997  *           0 = timeout or nothing to select
998  *          >0 = number of signaled fds
999  */
1000 int
1001 _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds, int nonblock )
1002 {
1003     HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1004     int    waitidx[MAXIMUM_WAIT_OBJECTS];
1005     int code, nwait;
1006     int i, any;
1007     int count;
1008     void *dbg_help;
1009
1010  restart:
1011     DEBUG_BEGIN (dbg_help, 3, "select on [ ");
1012     any = 0;
1013     nwait = 0;
1014     count = 0;
1015     for ( i=0; i < nfds; i++ ) {
1016         if ( fds[i].fd == -1 ) 
1017             continue;
1018         fds[i].signaled = 0;
1019         if ( fds[i].for_read || fds[i].for_write ) {
1020             if ( fds[i].frozen ) {
1021                 DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd );
1022             }
1023             else if ( fds[i].for_read ) {
1024                 struct reader_context_s *c = find_reader (fds[i].fd,1);
1025                 
1026                 if (!c) { 
1027                     DEBUG1 ("oops: no reader thread for fd %d", fds[i].fd);
1028                 }
1029                 else {
1030                     if ( nwait >= DIM (waitbuf) ) {
1031                         DEBUG_END (dbg_help, "oops ]");
1032                         DEBUG0 ("Too many objects for WFMO!" );
1033                         return -1;
1034                     }
1035                     waitidx[nwait]   = i;
1036                     waitbuf[nwait++] = c->have_data_ev;
1037                 }
1038                 DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd );
1039                 any = 1;
1040             }
1041             else if ( fds[i].for_write ) {
1042                 struct writer_context_s *c = find_writer (fds[i].fd,1);
1043                 
1044                 if (!c) { 
1045                     DEBUG1 ("oops: no writer thread for fd %d", fds[i].fd);
1046                 }
1047                 else {
1048                     if ( nwait >= DIM (waitbuf) ) {
1049                         DEBUG_END (dbg_help, "oops ]");
1050                         DEBUG0 ("Too many objects for WFMO!" );
1051                         return -1;
1052                     }
1053                     waitidx[nwait]   = i;
1054                     waitbuf[nwait++] = c->is_empty;
1055                 }
1056                 DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd );
1057                 any = 1;
1058             }
1059         }
1060     }
1061     DEBUG_END (dbg_help, "]");
1062     if (!any) 
1063         return 0;
1064
1065     code = WaitForMultipleObjects ( nwait, waitbuf, 0, nonblock ? 0 : 1000);
1066     if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) {
1067         /* This WFMO is a really silly function:  It does return either
1068          * the index of the signaled object or if 2 objects have been
1069          * signalled at the same time, the index of the object with the
1070          * lowest object is returned - so and how do we find out
1071          * how many objects have been signaled???.
1072          * The only solution I can imagine is to test each object starting
1073          * with the returned index individually - how dull.
1074          */
1075         any = 0;
1076         for (i=code - WAIT_OBJECT_0; i < nwait; i++ ) {
1077             if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0) {
1078                 assert (waitidx[i] >=0 && waitidx[i] < nfds);
1079                 fds[waitidx[i]].signaled = 1;
1080                 any = 1;
1081                 count++;
1082             }
1083         }
1084         if (!any) {
1085             DEBUG0 ("Oops: No signaled objects found after WFMO");
1086             count = -1;
1087         }
1088     }
1089     else if ( code == WAIT_TIMEOUT ) {
1090         DEBUG0 ("WFMO timed out\n" );
1091     }  
1092     else if (code == WAIT_FAILED ) {
1093         int le = (int)GetLastError ();
1094         if ( le == ERROR_INVALID_HANDLE ) {
1095             int k, j = handle_to_fd (waitbuf[i]);
1096                     
1097             DEBUG1 ("WFMO invalid handle %d removed\n", j);
1098             for (k=0 ; k < nfds; k++ ) {
1099                 if ( fds[k].fd == j ) {
1100                     fds[k].for_read = fds[k].for_write = 0;
1101                     goto restart;
1102                 }
1103             }
1104             DEBUG0 (" oops, or not???\n");
1105         }
1106         DEBUG1 ("WFMO failed: %d\n", le );
1107         count = -1;
1108     }
1109     else {
1110         DEBUG1 ("WFMO returned %d\n", code );
1111         count = -1;
1112     }
1113
1114     if ( count ) {
1115         DEBUG_BEGIN (dbg_help, 3, " signaled [ ");
1116         for ( i=0; i < nfds; i++ ) {
1117             if ( fds[i].fd == -1 ) 
1118                 continue;
1119             if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) {
1120                 DEBUG_ADD2 (dbg_help, "%c%d ",
1121                             fds[i].for_read? 'r':'w',fds[i].fd );
1122             }
1123         }
1124         DEBUG_END (dbg_help, "]");
1125     }
1126     
1127     return count;
1128 }
1129
1130 void
1131 _gpgme_io_subsystem_init (void)
1132 {
1133   
1134 }
1135
1136
1137 /* Write the printable version of FD to the buffer BUF of length
1138    BUFLEN.  The printable version is the representation on the command
1139    line that the child process expects.  */
1140 int
1141 _gpgme_io_fd2str (char *buf, int buflen, int fd)
1142 {
1143   return snprintf (buf, buflen, "%d", fd);
1144 }
1145
1146 \f
1147 /* The following interface is only useful for GPGME Glib.  */
1148
1149 /* Look up the giochannel for file descriptor FD.  */
1150 void *
1151 gpgme_get_giochannel (int fd)
1152 {
1153   return NULL;
1154 }
1155