Reworked the process code.
[gpgme.git] / gpgme / w32-io.c
1 /* w32-io.c - W32 API I/O functions
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #ifdef HAVE_DOSISH_SYSTEM
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <signal.h>
32 #include <fcntl.h>
33 #include <windows.h>
34 #include "syshdr.h"
35
36 #include "util.h"
37 #include "sema.h"
38 #include "io.h"
39
40
41 /* 
42  * We assume that a HANDLE can be represented by an int which should be true   
43  * for all i386 systems (HANDLE is defined as void *) and these are the only
44  * systems for which Windows is available.
45  * Further we assume that -1 denotes an invalid handle.
46  */
47
48 #define fd_to_handle(a)  ((HANDLE)(a))
49 #define handle_to_fd(a)  ((int)(a))
50 #define pid_to_handle(a) ((HANDLE)(a))
51 #define handle_to_pid(a) ((int)(a))
52
53 #define READBUF_SIZE 4096
54
55 static struct {
56     int inuse;
57     int fd;
58     void (*handler)(int,void*);
59     void *value;
60 } notify_table[256];
61 DEFINE_STATIC_LOCK (notify_table_lock);
62
63
64 struct reader_context_s {
65     HANDLE file_hd;
66     HANDLE thread_hd;   
67     DECLARE_LOCK (mutex);
68
69     int stop_me;
70     int eof;
71     int eof_shortcut;
72     int error;
73     int error_code;
74
75     HANDLE have_data_ev;  /* manually reset */
76     HANDLE have_space_ev; /* auto reset */
77     HANDLE stopped;
78     size_t readpos, writepos;
79     char buffer[READBUF_SIZE];
80 };
81
82
83 #define MAX_READERS 20
84 static struct {
85     volatile int used;
86     int fd;
87     struct reader_context_s *context;
88 } reader_table[MAX_READERS];
89 static int reader_table_size= MAX_READERS;
90 DEFINE_STATIC_LOCK (reader_table_lock);
91
92 static HANDLE
93 set_synchronize (HANDLE h)
94 {
95     HANDLE tmp;
96     
97     /* For NT we have to set the sync flag.  It seems that the only
98      * way to do it is by duplicating the handle.  Tsss.. */
99     if (!DuplicateHandle( GetCurrentProcess(), h,
100                           GetCurrentProcess(), &tmp,
101                           EVENT_MODIFY_STATE|SYNCHRONIZE, FALSE, 0 ) ) {
102         DEBUG1 ("** Set SYNCRONIZE failed: ec=%d\n", (int)GetLastError());
103     }
104     else {
105         CloseHandle (h);
106         h = tmp;
107     }
108     return h;
109 }
110
111
112
113 static DWORD CALLBACK 
114 reader (void *arg)
115 {
116     struct reader_context_s *c = arg;
117     int nbytes;
118     DWORD nread;
119
120     DEBUG2 ("reader thread %p for file %p started", c->thread_hd, c->file_hd );
121     for (;;) {
122         LOCK (c->mutex);
123         /* leave a 1 byte gap so that we can see whether it is empty or full*/
124         if ((c->writepos + 1) % READBUF_SIZE == c->readpos) { 
125             /* wait for space */
126             if (!ResetEvent (c->have_space_ev) )
127                 DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
128             UNLOCK (c->mutex);
129             DEBUG1 ("reader thread %p: waiting for space ...", c->thread_hd );
130             WaitForSingleObject (c->have_space_ev, INFINITE);
131             DEBUG1 ("reader thread %p: got space", c->thread_hd );
132             LOCK (c->mutex);
133         }
134         if ( c->stop_me ) {
135             UNLOCK (c->mutex);
136             break;
137         }
138         nbytes = (c->readpos + READBUF_SIZE - c->writepos-1) % READBUF_SIZE;
139         if ( nbytes > READBUF_SIZE - c->writepos )
140             nbytes = READBUF_SIZE - c->writepos;
141         UNLOCK (c->mutex);
142
143         DEBUG2 ("reader thread %p: reading %d bytes", c->thread_hd, nbytes );
144         if ( !ReadFile ( c->file_hd,
145                          c->buffer+c->writepos, nbytes, &nread, NULL) ) {
146             c->error_code = (int)GetLastError ();
147             if (c->error_code == ERROR_BROKEN_PIPE ) {
148                 c->eof=1;
149                 DEBUG1 ("reader thread %p: got eof (broken pipe)",
150                         c->thread_hd );
151             }
152             else {
153                 c->error = 1;
154                 DEBUG2 ("reader thread %p: read error: ec=%d",
155                         c->thread_hd, c->error_code );
156             }
157             break;
158         }
159         if ( !nread ) {
160             c->eof = 1;
161             DEBUG1 ("reader thread %p: got eof", c->thread_hd );
162             break;
163         }
164         DEBUG2 ("reader thread %p: got %d bytes", c->thread_hd, (int)nread );
165       
166         LOCK (c->mutex);
167         if (c->stop_me) {
168             UNLOCK (c->mutex);
169             break;
170         }
171         c->writepos = (c->writepos + nread) % READBUF_SIZE;
172         if ( !SetEvent (c->have_data_ev) )
173             DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
174         UNLOCK (c->mutex);
175     }
176     /* indicate that we have an error or eof */
177     if ( !SetEvent (c->have_data_ev) )
178         DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
179     DEBUG1 ("reader thread %p ended", c->thread_hd );
180     SetEvent (c->stopped);
181
182     return 0;
183 }
184
185
186 static struct reader_context_s *
187 create_reader (HANDLE fd)
188 {
189     struct reader_context_s *c;
190     SECURITY_ATTRIBUTES sec_attr;
191     DWORD tid;
192
193     DEBUG1 ("creating new read thread for file handle %p", fd );
194     memset (&sec_attr, 0, sizeof sec_attr );
195     sec_attr.nLength = sizeof sec_attr;
196     sec_attr.bInheritHandle = FALSE;
197
198     c = xtrycalloc (1, sizeof *c );
199     if (!c)
200         return NULL;
201
202     c->file_hd = fd;
203     c->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
204     c->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
205     c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
206     if (!c->have_data_ev || !c->have_space_ev || !c->stopped ) {
207         DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ());
208         if (c->have_data_ev)
209             CloseHandle (c->have_data_ev);
210         if (c->have_space_ev)
211             CloseHandle (c->have_space_ev);
212         if (c->stopped)
213             CloseHandle (c->stopped);
214         xfree (c);
215         return NULL;
216     }
217
218     c->have_data_ev = set_synchronize (c->have_data_ev);
219     INIT_LOCK (c->mutex);
220
221     c->thread_hd = CreateThread (&sec_attr, 0, reader, c, 0, &tid );
222     if (!c->thread_hd) {
223         DEBUG1 ("** failed to create reader thread: ec=%d\n",
224                  (int)GetLastError ());
225         DESTROY_LOCK (c->mutex);
226         if (c->have_data_ev)
227             CloseHandle (c->have_data_ev);
228         if (c->have_space_ev)
229             CloseHandle (c->have_space_ev);
230         if (c->stopped)
231             CloseHandle (c->stopped);
232         xfree (c);
233         return NULL;
234     }    
235
236     return c;
237 }
238
239 static void
240 destroy_reader (struct reader_context_s *c)
241 {
242     if (c->have_space_ev) 
243         SetEvent (c->have_space_ev);
244
245     DEBUG1 ("waiting for thread %p termination ...", c->thread_hd );
246     WaitForSingleObject (c->stopped, INFINITE);
247     DEBUG1 ("thread %p has terminated", c->thread_hd );
248     
249     if (c->stopped)
250         CloseHandle (c->stopped);
251     if (c->have_data_ev)
252         CloseHandle (c->have_data_ev);
253     if (c->have_space_ev)
254         CloseHandle (c->have_space_ev);
255     CloseHandle (c->thread_hd);
256     DESTROY_LOCK (c->mutex);
257     xfree (c);
258 }
259
260
261 /* 
262  * Find a reader context or create a new one 
263  * Note that the reader context will last until a io_close.
264  */
265 static struct reader_context_s *
266 find_reader (int fd, int start_it)
267 {
268     int i;
269
270     for (i=0; i < reader_table_size ; i++ ) {
271         if ( reader_table[i].used && reader_table[i].fd == fd )
272             return reader_table[i].context;
273     }
274     if (!start_it)
275         return NULL;
276
277     LOCK (reader_table_lock);
278     for (i=0; i < reader_table_size; i++ ) {
279         if (!reader_table[i].used) {
280             reader_table[i].fd = fd;
281             reader_table[i].context = create_reader (fd_to_handle (fd));
282             reader_table[i].used = 1;
283             UNLOCK (reader_table_lock);
284             return reader_table[i].context;
285         }
286     }
287     UNLOCK (reader_table_lock);
288     return NULL;
289 }
290
291
292 static void
293 kill_reader (int fd)
294 {
295     int i;
296
297     LOCK (reader_table_lock);
298     for (i=0; i < reader_table_size; i++ ) {
299         if (reader_table[i].used && reader_table[i].fd == fd ) {
300             destroy_reader (reader_table[i].context);
301             reader_table[i].context = NULL;
302             reader_table[i].used = 0;
303             break;
304         }
305     }
306     UNLOCK (reader_table_lock);
307 }
308
309
310
311 int
312 _gpgme_io_read ( int fd, void *buffer, size_t count )
313 {
314     int nread;
315     struct reader_context_s *c = find_reader (fd,1);
316
317     DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int)count );
318     if ( !c ) {
319         DEBUG0 ( "no reader thread\n");
320         return -1;
321     }
322     if (c->eof_shortcut) {
323         DEBUG1 ("fd %d: EOF (again)", fd );
324         return 0;
325     }
326
327     LOCK (c->mutex);
328     if (c->readpos == c->writepos && !c->error) { /*no data avail*/
329         UNLOCK (c->mutex);
330         DEBUG2 ("fd %d: waiting for data from thread %p", fd, c->thread_hd);
331         WaitForSingleObject (c->have_data_ev, INFINITE);
332         DEBUG2 ("fd %d: data from thread %p available", fd, c->thread_hd);
333         LOCK (c->mutex);
334     }
335     
336     if (c->readpos == c->writepos || c->error) {
337         UNLOCK (c->mutex);
338         c->eof_shortcut = 1;
339         if (c->eof) {
340             DEBUG1 ("fd %d: EOF", fd );
341             return 0;
342         }
343         if (!c->error) {
344             DEBUG1 ("fd %d: EOF but eof flag not set", fd );
345             return 0;
346         }
347         DEBUG1 ("fd %d: read error", fd );
348         return -1;
349     }
350       
351     nread = c->readpos < c->writepos? c->writepos - c->readpos
352                                     : READBUF_SIZE - c->readpos;
353     if (nread > count)
354         nread = count;
355     memcpy (buffer, c->buffer+c->readpos, nread);
356     c->readpos = (c->readpos + nread) % READBUF_SIZE;
357     if (c->readpos == c->writepos && !c->eof) {
358         if ( !ResetEvent (c->have_data_ev) )
359             DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
360     }
361     if (!SetEvent (c->have_space_ev))
362         DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
363     UNLOCK (c->mutex);
364
365     DEBUG2 ("fd %d: got %d bytes\n", fd, nread );
366
367     return nread;
368 }
369
370
371 int
372 _gpgme_io_write ( int fd, const void *buffer, size_t count )
373 {
374     DWORD nwritten;
375     HANDLE h = fd_to_handle (fd);
376
377     /* writing blocks for large counts, so we limit it here. */
378     if (count > 1024)
379         count = 1024;
380
381     DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int)count );
382     if ( !WriteFile ( h, buffer, count, &nwritten, NULL) ) {
383         DEBUG1 ("WriteFile failed: ec=%d\n", (int)GetLastError ());
384         return -1;
385     }
386     DEBUG2 ("fd %d:          wrote %d bytes\n",
387                    fd, (int)nwritten );
388
389     return (int)nwritten;
390 }
391
392 int
393 _gpgme_io_pipe ( int filedes[2], int inherit_idx )
394 {
395     HANDLE r, w;
396     SECURITY_ATTRIBUTES sec_attr;
397
398     memset (&sec_attr, 0, sizeof sec_attr );
399     sec_attr.nLength = sizeof sec_attr;
400     sec_attr.bInheritHandle = FALSE;
401     
402     if (!CreatePipe ( &r, &w, &sec_attr, 0))
403         return -1;
404     /* make one end inheritable */
405     if ( inherit_idx == 0 ) {
406         HANDLE h;
407         if (!DuplicateHandle( GetCurrentProcess(), r,
408                               GetCurrentProcess(), &h, 0,
409                               TRUE, DUPLICATE_SAME_ACCESS ) ) {
410             DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
411             CloseHandle (r);
412             CloseHandle (w);
413             return -1;
414         }
415         CloseHandle (r);
416         r = h;
417     }
418     else if ( inherit_idx == 1 ) {
419         HANDLE h;
420         if (!DuplicateHandle( GetCurrentProcess(), w,
421                               GetCurrentProcess(), &h, 0,
422                               TRUE, DUPLICATE_SAME_ACCESS ) ) {
423             DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
424             CloseHandle (r);
425             CloseHandle (w);
426             return -1;
427         }
428         CloseHandle (w);
429         w = h;
430     }
431
432     filedes[0] = handle_to_fd (r);
433     filedes[1] = handle_to_fd (w);
434     DEBUG5 ("CreatePipe %p %p %d %d inherit=%d\n", r, w,
435                    filedes[0], filedes[1], inherit_idx );
436     return 0;
437 }
438
439 int
440 _gpgme_io_close ( int fd )
441 {
442     int i;
443     void (*handler)(int, void*) = NULL;
444     void *value = NULL;
445
446     if ( fd == -1 )
447         return -1;
448
449     DEBUG1 ("** closing handle for fd %d\n", fd);
450     kill_reader (fd);
451     LOCK (notify_table_lock);
452     for ( i=0; i < DIM (notify_table); i++ ) {
453         if (notify_table[i].inuse && notify_table[i].fd == fd) {
454             handler = notify_table[i].handler;
455             value   = notify_table[i].value;
456             notify_table[i].handler = NULL;
457             notify_table[i].value = NULL;
458             notify_table[i].inuse = 0;
459             break;
460         }
461     }
462     UNLOCK (notify_table_lock);
463     if (handler)
464         handler (fd, value);
465
466     if ( !CloseHandle (fd_to_handle (fd)) ) { 
467         DEBUG2 ("CloseHandle for fd %d failed: ec=%d\n",
468                  fd, (int)GetLastError ());
469         return -1;
470     }
471
472     return 0;
473 }
474
475 int
476 _gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
477 {
478     int i;
479
480     assert (fd != -1);
481
482     LOCK (notify_table_lock);
483     for (i=0; i < DIM (notify_table); i++ ) {
484         if ( notify_table[i].inuse && notify_table[i].fd == fd )
485             break;
486     }
487     if ( i == DIM (notify_table) ) {
488         for (i=0; i < DIM (notify_table); i++ ) {
489             if ( !notify_table[i].inuse )
490                 break;
491         }
492     }
493     if ( i == DIM (notify_table) ) {
494         UNLOCK (notify_table_lock);
495         return -1;
496     }
497     notify_table[i].fd = fd;
498     notify_table[i].handler = handler;
499     notify_table[i].value = value;
500     notify_table[i].inuse = 1;
501     UNLOCK (notify_table_lock);
502     DEBUG2 ("set notification for fd %d (idx=%d)", fd, i );
503     return 0;
504 }
505
506
507 int
508 _gpgme_io_set_nonblocking ( int fd )
509 {
510     return 0;
511 }
512
513
514 static char *
515 build_commandline ( char **argv )
516 {
517     int i, n = 0;
518     char *buf, *p;
519
520     /* FIXME: we have to quote some things because under Windows the 
521      * program parses the commandline and does some unquoting */
522     for (i=0; argv[i]; i++)
523         n += strlen (argv[i]) + 1;
524     buf = p = xtrymalloc (n);
525     if ( !buf )
526         return NULL;
527     *buf = 0;
528     if ( argv[0] )
529         p = stpcpy (p, argv[0]);
530     for (i = 1; argv[i]; i++)
531         p = stpcpy (stpcpy (p, " "), argv[i]);
532
533     return buf;
534 }
535
536
537 int
538 _gpgme_io_spawn ( const char *path, char **argv,
539                   struct spawn_fd_item_s *fd_child_list,
540                   struct spawn_fd_item_s *fd_parent_list )
541 {
542     SECURITY_ATTRIBUTES sec_attr;
543     PROCESS_INFORMATION pi = {
544         NULL,      /* returns process handle */
545         0,         /* returns primary thread handle */
546         0,         /* returns pid */
547         0         /* returns tid */
548     };
549     STARTUPINFO si;
550     char *envblock = NULL;
551     int cr_flags = CREATE_DEFAULT_ERROR_MODE
552                  | GetPriorityClass (GetCurrentProcess ());
553     int i;
554     char *arg_string;
555     int duped_stdin = 0;
556     int duped_stderr = 0;
557     HANDLE hnul = INVALID_HANDLE_VALUE;
558     int debug_me = !!getenv ("GPGME_DEBUG");
559
560     memset (&sec_attr, 0, sizeof sec_attr );
561     sec_attr.nLength = sizeof sec_attr;
562     sec_attr.bInheritHandle = FALSE;
563
564     arg_string = build_commandline ( argv );
565     if (!arg_string )
566         return -1; 
567
568     memset (&si, 0, sizeof si);
569     si.cb = sizeof (si);
570     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
571     si.wShowWindow = debug_me? SW_SHOW : SW_MINIMIZE;
572     si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
573     si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
574     si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
575
576     for (i=0; fd_child_list[i].fd != -1; i++ ) {
577         if (fd_child_list[i].dup_to == 0 ) {
578             si.hStdInput = fd_to_handle (fd_child_list[i].fd);
579             DEBUG1 ("using %d for stdin", fd_child_list[i].fd );
580             duped_stdin=1;
581         }
582         else if (fd_child_list[i].dup_to == 1 ) {
583             si.hStdOutput = fd_to_handle (fd_child_list[i].fd);
584             DEBUG1 ("using %d for stdout", fd_child_list[i].fd );
585         }
586         else if (fd_child_list[i].dup_to == 2 ) {
587             si.hStdError = fd_to_handle (fd_child_list[i].fd);
588             DEBUG1 ("using %d for stderr", fd_child_list[i].fd );
589             duped_stderr = 1;
590         }
591     }
592
593     if( !duped_stdin || !duped_stderr ) {
594         SECURITY_ATTRIBUTES sa;
595
596         memset (&sa, 0, sizeof sa );
597         sa.nLength = sizeof sa;
598         sa.bInheritHandle = TRUE;
599         hnul = CreateFile ( "nul",
600                             GENERIC_READ|GENERIC_WRITE,
601                             FILE_SHARE_READ|FILE_SHARE_WRITE,
602                             &sa,
603                             OPEN_EXISTING,
604                             FILE_ATTRIBUTE_NORMAL,
605                             NULL );
606         if ( hnul == INVALID_HANDLE_VALUE ) {
607             DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ());
608             xfree (arg_string);
609             return -1;
610         }
611         /* Make sure that the process has a connected stdin */
612         if ( !duped_stdin ) {
613             si.hStdInput = hnul;
614             DEBUG1 ("using %d for dummy stdin", (int)hnul );
615         }
616         /* We normally don't want all the normal output */
617         if ( !duped_stderr ) {
618             si.hStdError = hnul;
619             DEBUG1 ("using %d for dummy stderr", (int)hnul );
620         }
621     }
622
623     DEBUG2 ("CreateProcess, path=`%s' args=`%s'", path, arg_string);
624     cr_flags |= CREATE_SUSPENDED; 
625     if ( !CreateProcessA (path,
626                           arg_string,
627                           &sec_attr,     /* process security attributes */
628                           &sec_attr,     /* thread security attributes */
629                           TRUE,          /* inherit handles */
630                           cr_flags,      /* creation flags */
631                           envblock,      /* environment */
632                           NULL,          /* use current drive/directory */
633                           &si,           /* startup information */
634                           &pi            /* returns process information */
635         ) ) {
636         DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ());
637         xfree (arg_string);
638         return -1;
639     }
640
641     /* close the /dev/nul handle if used */
642     if (hnul != INVALID_HANDLE_VALUE ) {
643         if ( !CloseHandle ( hnul ) )
644             DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError());
645     }
646
647     /* Close the other ends of the pipes */
648     for (i=0; fd_parent_list[i].fd != -1; i++ ) {
649         DEBUG1 ("Closing fd %d\n", fd_parent_list[i].fd );
650         if ( !CloseHandle ( fd_to_handle (fd_parent_list[i].fd) ) )
651             DEBUG1 ("CloseHandle failed: ec=%d", (int)GetLastError());
652     }
653
654     DEBUG4 ("CreateProcess ready\n"
655             "-   hProcess=%p  hThread=%p\n"
656             "-   dwProcessID=%d dwThreadId=%d\n",
657             pi.hProcess, pi.hThread, 
658             (int) pi.dwProcessId, (int) pi.dwThreadId);
659
660     if ( ResumeThread ( pi.hThread ) < 0 ) {
661         DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ());
662     }
663
664     if ( !CloseHandle (pi.hThread) ) { 
665         DEBUG1 ("CloseHandle of thread failed: ec=%d\n",
666                  (int)GetLastError ());
667     }
668
669     return handle_to_pid (pi.hProcess);
670 }
671
672
673
674
675 int
676 _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
677 {
678     HANDLE proc = fd_to_handle (pid);
679     int code, ret = 0;
680     DWORD exc;
681
682     *r_status = 0;
683     *r_signal = 0;
684     code = WaitForSingleObject ( proc, hang? INFINITE : 0 );
685     switch (code) {
686       case WAIT_FAILED:
687         DEBUG2 ("WFSO pid=%d failed: %d\n", (int)pid, (int)GetLastError () );
688         break;
689
690       case WAIT_OBJECT_0:
691         if (!GetExitCodeProcess (proc, &exc)) {
692             DEBUG2 ("** GECP pid=%d failed: ec=%d\n",
693                     (int)pid, (int)GetLastError () );
694             *r_status = 4; 
695         }
696         else {
697             DEBUG2 ("GECP pid=%d exit code=%d\n", (int)pid,  exc);
698             *r_status = exc;
699         }
700         ret = 1;
701         break;
702
703       case WAIT_TIMEOUT:
704         if (hang)
705             DEBUG1 ("WFSO pid=%d timed out\n", (int)pid);
706         break;
707
708       default:
709         DEBUG2 ("WFSO pid=%d returned %d\n", (int)pid, code );
710         break;
711     }
712     return ret;
713 }
714
715 int
716 _gpgme_io_kill ( int pid, int hard )
717 {
718     HANDLE proc = fd_to_handle (pid);
719
720     #warning I am not sure how to kill a process
721     /* fixme: figure out how this can be done */
722     return 0;
723 }
724
725
726
727 /*
728  * Select on the list of fds.
729  * Returns: -1 = error
730  *           0 = timeout or nothing to select
731  *          >0 = number of signaled fds
732  */
733 int
734 _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
735 {
736     HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
737     int    waitidx[MAXIMUM_WAIT_OBJECTS];
738     int code, nwait;
739     int i, any, any_write;
740     int count;
741     void *dbg_help;
742
743  restart:
744     DEBUG_BEGIN (dbg_help, "select on [ ");
745     any = any_write = 0;
746     nwait = 0;
747     count = 0;
748     for ( i=0; i < nfds; i++ ) {
749         if ( fds[i].fd == -1 ) 
750             continue;
751         fds[i].signaled = 0;
752         if ( fds[i].for_read || fds[i].for_write ) {
753             if ( fds[i].frozen ) {
754                 DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd );
755             }
756             else if ( fds[i].for_read ) {
757                 struct reader_context_s *c = find_reader (fds[i].fd,1);
758                 
759                 if (!c) { 
760                     DEBUG1 ("oops: no reader thread for fd %d", fds[i].fd);
761                 }
762                 else {
763                     if ( nwait >= DIM (waitbuf) ) {
764                         DEBUG_END (dbg_help, "oops ]");
765                         DEBUG0 ("Too many objects for WFMO!" );
766                         return -1;
767                     }
768                     waitidx[nwait]   = i;
769                     waitbuf[nwait++] = c->have_data_ev;
770                 }
771                 DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd );
772                 any = 1;
773             }
774             else if ( fds[i].for_write ) {
775                 DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd );
776                 any = 1;
777                 /* no way to see whether a handle is ready for writing,
778                  * so we signal them all */
779                 fds[i].signaled = 1;
780                 any_write =1;
781                 count++;
782             }
783         }
784     }
785     DEBUG_END (dbg_help, "]");
786     if (!any) 
787         return 0;
788
789     code = WaitForMultipleObjects ( nwait, waitbuf, 0, any_write? 200:1000);
790     if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) {
791         /* This WFMO is a really silly function:  It does return either
792          * the index of the signaled object or if 2 objects have been
793          * signalled at the same time, the index of the object with the
794          * lowest object is returned - so and how do we find out
795          * how many objects have been signaled???.
796          * The only solution I can imagine is to test each object starting
797          * with the returned index individually - how dull.
798          */
799         any = 0;
800         for (i=code - WAIT_OBJECT_0; i < nwait; i++ ) {
801             if (WaitForSingleObject ( waitbuf[i], NULL ) == WAIT_OBJECT_0) {
802                 assert (waitidx[i] >=0 && waitidx[i] < nfds);
803                 fds[waitidx[i]].signaled = 1;
804                 any = 1;
805                 count++;
806             }
807         }
808         if (!any) {
809             DEBUG0 ("Oops: No signaled objects found after WFMO");
810             count = -1;
811         }
812     }
813     else if ( code == WAIT_TIMEOUT ) {
814         DEBUG0 ("WFMO timed out\n" );
815     }  
816     else if (code == WAIT_FAILED ) {
817         int le = (int)GetLastError ();
818         if ( le == ERROR_INVALID_HANDLE ) {
819             int k, j = handle_to_fd (waitbuf[i]);
820                     
821             DEBUG1 ("WFMO invalid handle %d removed\n", j);
822             for (k=0 ; k < nfds; i++ ) {
823                 if ( fds[k].fd == j ) {
824                     fds[k].for_read = fds[k].for_write = 0;
825                     goto restart;
826                 }
827             }
828             DEBUG0 (" oops, or not???\n");
829         }
830         DEBUG1 ("WFMO failed: %d\n", le );
831         count = -1;
832     }
833     else {
834         DEBUG1 ("WFMO returned %d\n", code );
835         count = -1;
836     }
837
838     if ( count ) {
839         DEBUG_BEGIN (dbg_help, " signaled [ ");
840         for ( i=0; i < nfds; i++ ) {
841             if ( fds[i].fd == -1 ) 
842                 continue;
843             if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) {
844                 DEBUG_ADD2 (dbg_help, "%c%d ",
845                             fds[i].for_read? 'r':'w',fds[i].fd );
846             }
847         }
848         DEBUG_END (dbg_help, "]");
849     }
850     
851     return count;
852 }
853
854 #endif /*HAVE_DOSISH_SYSTEM*/
855
856
857
858
859
860
861
862
863