/[winpt]/trunk/MyGPGME/w32-io.c
ViewVC logotype

Annotation of /trunk/MyGPGME/w32-io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Mon Jan 31 11:02:21 2005 UTC (20 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 32964 byte(s)
WinPT initial checkin.


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26