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