97399bf7e586bab4019cd64597f570e36fd8a5ce
[sdk/target/sdbd.git] / src / sysdeps_win32.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "sysdeps.h"
18 #include <windows.h>
19 #include <winsock2.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #define  TRACE_TAG  TRACE_SYSDEPS
23 #include "sdb.h"
24
25 extern void fatal(const char *fmt, ...);
26
27 #define assert(cond)  do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
28
29 /**************************************************************************/
30 /**************************************************************************/
31 /*****                                                                *****/
32 /*****      replaces libs/cutils/load_file.c                          *****/
33 /*****                                                                *****/
34 /**************************************************************************/
35 /**************************************************************************/
36
37 void *load_file(const char *fn, unsigned *_sz)
38 {
39     HANDLE    file;
40     char     *data;
41     DWORD     file_size;
42
43     file = CreateFile( fn,
44                        GENERIC_READ,
45                        FILE_SHARE_READ,
46                        NULL,
47                        OPEN_EXISTING,
48                        0,
49                        NULL );
50
51     if (file == INVALID_HANDLE_VALUE)
52         return NULL;
53
54     file_size = GetFileSize( file, NULL );
55     data      = NULL;
56
57     if (file_size > 0) {
58         data = (char*) malloc( file_size + 1 );
59         if (data == NULL) {
60             D("load_file: could not allocate %ld bytes\n", file_size );
61             file_size = 0;
62         } else {
63             DWORD  out_bytes;
64
65             if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
66                  out_bytes != file_size )
67             {
68                 D("load_file: could not read %ld bytes from '%s'\n", file_size, fn);
69                 free(data);
70                 data      = NULL;
71                 file_size = 0;
72             }
73         }
74     }
75     CloseHandle( file );
76
77     *_sz = (unsigned) file_size;
78     return  data;
79 }
80
81 /**************************************************************************/
82 /**************************************************************************/
83 /*****                                                                *****/
84 /*****    common file descriptor handling                             *****/
85 /*****                                                                *****/
86 /**************************************************************************/
87 /**************************************************************************/
88
89 typedef const struct FHClassRec_*   FHClass;
90
91 typedef struct FHRec_*          FH;
92
93 typedef struct EventHookRec_*  EventHook;
94
95 typedef struct FHClassRec_
96 {
97     void (*_fh_init) ( FH  f );
98     int  (*_fh_close)( FH  f );
99     int  (*_fh_lseek)( FH  f, int  pos, int  origin );
100     int  (*_fh_read) ( FH  f, void*  buf, int  len );
101     int  (*_fh_write)( FH  f, const void*  buf, int  len );
102     void (*_fh_hook) ( FH  f, int  events, EventHook  hook );
103
104 } FHClassRec;
105
106 /* used to emulate unix-domain socket pairs */
107 typedef struct SocketPairRec_*  SocketPair;
108
109 typedef struct FHRec_
110 {
111     FHClass    clazz;
112     int        used;
113     int        eof;
114     union {
115         HANDLE      handle;
116         SOCKET      socket;
117         SocketPair  pair;
118     } u;
119
120     HANDLE    event;
121     int       mask;
122
123     char  name[32];
124
125 } FHRec;
126
127 #define  fh_handle  u.handle
128 #define  fh_socket  u.socket
129 #define  fh_pair    u.pair
130
131 #define  WIN32_FH_BASE    100
132
133 #define  WIN32_MAX_FHS    128
134
135 static sdb_mutex_t   _win32_lock;
136 static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
137 static  int          _win32_fh_count;
138
139 static FH
140 _fh_from_int( int   fd )
141 {
142     FH  f;
143
144     fd -= WIN32_FH_BASE;
145
146     if (fd < 0 || fd >= _win32_fh_count) {
147         D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
148         errno = EBADF;
149         return NULL;
150     }
151
152     f = &_win32_fhs[fd];
153
154     if (f->used == 0) {
155         D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
156         errno = EBADF;
157         return NULL;
158     }
159
160     return f;
161 }
162
163
164 static int
165 _fh_to_int( FH  f )
166 {
167     if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
168         return (int)(f - _win32_fhs) + WIN32_FH_BASE;
169
170     return -1;
171 }
172
173 static FH
174 _fh_alloc( FHClass  clazz )
175 {
176     int  nn;
177     FH   f = NULL;
178
179     sdb_mutex_lock( &_win32_lock );
180
181     if (_win32_fh_count < WIN32_MAX_FHS) {
182         f = &_win32_fhs[ _win32_fh_count++ ];
183         goto Exit;
184     }
185
186     for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
187         if ( _win32_fhs[nn].clazz == NULL) {
188             f = &_win32_fhs[nn];
189             goto Exit;
190         }
191     }
192     D( "_fh_alloc: no more free file descriptors\n" );
193 Exit:
194     if (f) {
195         f->clazz = clazz;
196         f->used  = 1;
197         f->eof   = 0;
198         clazz->_fh_init(f);
199     }
200     sdb_mutex_unlock( &_win32_lock );
201     return f;
202 }
203
204
205 static int
206 _fh_close( FH   f )
207 {
208     if ( f->used ) {
209         f->clazz->_fh_close( f );
210         f->used = 0;
211         f->eof  = 0;
212         f->clazz = NULL;
213     }
214     return 0;
215 }
216
217 /* forward definitions */
218 static const FHClassRec   _fh_file_class;
219 static const FHClassRec   _fh_socket_class;
220
221 /**************************************************************************/
222 /**************************************************************************/
223 /*****                                                                *****/
224 /*****    file-based descriptor handling                              *****/
225 /*****                                                                *****/
226 /**************************************************************************/
227 /**************************************************************************/
228
229 static void
230 _fh_file_init( FH  f )
231 {
232     f->fh_handle = INVALID_HANDLE_VALUE;
233 }
234
235 static int
236 _fh_file_close( FH  f )
237 {
238     CloseHandle( f->fh_handle );
239     f->fh_handle = INVALID_HANDLE_VALUE;
240     return 0;
241 }
242
243 static int
244 _fh_file_read( FH  f,  void*  buf, int   len )
245 {
246     DWORD  read_bytes;
247
248     if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
249         D( "sdb_read: could not read %d bytes from %s\n", len, f->name );
250         errno = EIO;
251         return -1;
252     } else if (read_bytes < (DWORD)len) {
253         f->eof = 1;
254     }
255     return (int)read_bytes;
256 }
257
258 static int
259 _fh_file_write( FH  f,  const void*  buf, int   len )
260 {
261     DWORD  wrote_bytes;
262
263     if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
264         D( "sdb_file_write: could not write %d bytes from %s\n", len, f->name );
265         errno = EIO;
266         return -1;
267     } else if (wrote_bytes < (DWORD)len) {
268         f->eof = 1;
269     }
270     return  (int)wrote_bytes;
271 }
272
273 static int
274 _fh_file_lseek( FH  f, int  pos, int  origin )
275 {
276     DWORD  method;
277     DWORD  result;
278
279     switch (origin)
280     {
281         case SEEK_SET:  method = FILE_BEGIN; break;
282         case SEEK_CUR:  method = FILE_CURRENT; break;
283         case SEEK_END:  method = FILE_END; break;
284         default:
285             errno = EINVAL;
286             return -1;
287     }
288
289     result = SetFilePointer( f->fh_handle, pos, NULL, method );
290     if (result == INVALID_SET_FILE_POINTER) {
291         errno = EIO;
292         return -1;
293     } else {
294         f->eof = 0;
295     }
296     return (int)result;
297 }
298
299 static void  _fh_file_hook( FH  f, int  event, EventHook  eventhook );  /* forward */
300
301 static const FHClassRec  _fh_file_class =
302 {
303     _fh_file_init,
304     _fh_file_close,
305     _fh_file_lseek,
306     _fh_file_read,
307     _fh_file_write,
308     _fh_file_hook
309 };
310
311 /**************************************************************************/
312 /**************************************************************************/
313 /*****                                                                *****/
314 /*****    file-based descriptor handling                              *****/
315 /*****                                                                *****/
316 /**************************************************************************/
317 /**************************************************************************/
318
319 int  sdb_open(const char*  path, int  options)
320 {
321     FH  f;
322
323     DWORD  desiredAccess       = 0;
324     DWORD  shareMode           = FILE_SHARE_READ | FILE_SHARE_WRITE;
325
326     switch (options) {
327         case O_RDONLY:
328             desiredAccess = GENERIC_READ;
329             break;
330         case O_WRONLY:
331             desiredAccess = GENERIC_WRITE;
332             break;
333         case O_RDWR:
334             desiredAccess = GENERIC_READ | GENERIC_WRITE;
335             break;
336         default:
337             D("sdb_open: invalid options (0x%0x)\n", options);
338             errno = EINVAL;
339             return -1;
340     }
341
342     f = _fh_alloc( &_fh_file_class );
343     if ( !f ) {
344         errno = ENOMEM;
345         return -1;
346     }
347
348     f->fh_handle = CreateFile( path, desiredAccess, shareMode, NULL, OPEN_EXISTING,
349                                0, NULL );
350
351     if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
352         _fh_close(f);
353         D( "sdb_open: could not open '%s':", path );
354         switch (GetLastError()) {
355             case ERROR_FILE_NOT_FOUND:
356                 D( "file not found\n" );
357                 errno = ENOENT;
358                 return -1;
359
360             case ERROR_PATH_NOT_FOUND:
361                 D( "path not found\n" );
362                 errno = ENOTDIR;
363                 return -1;
364
365             default:
366                 D( "unknown error\n" );
367                 errno = ENOENT;
368                 return -1;
369         }
370     }
371     
372     snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
373     D( "sdb_open: '%s' => fd %d\n", path, _fh_to_int(f) );
374     return _fh_to_int(f);
375 }
376
377 /* ignore mode on Win32 */
378 int  sdb_creat(const char*  path, int  mode)
379 {
380     FH  f;
381
382     f = _fh_alloc( &_fh_file_class );
383     if ( !f ) {
384         errno = ENOMEM;
385         return -1;
386     }
387
388     f->fh_handle = CreateFile( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
389                                NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
390                                NULL );
391
392     if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
393         _fh_close(f);
394         D( "sdb_creat: could not open '%s':", path );
395         switch (GetLastError()) {
396             case ERROR_FILE_NOT_FOUND:
397                 D( "file not found\n" );
398                 errno = ENOENT;
399                 return -1;
400
401             case ERROR_PATH_NOT_FOUND:
402                 D( "path not found\n" );
403                 errno = ENOTDIR;
404                 return -1;
405
406             default:
407                 D( "unknown error\n" );
408                 errno = ENOENT;
409                 return -1;
410         }
411     }
412     snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
413     D( "sdb_creat: '%s' => fd %d\n", path, _fh_to_int(f) );
414     return _fh_to_int(f);
415 }
416
417
418 int  sdb_read(int  fd, void* buf, int len)
419 {
420     FH     f = _fh_from_int(fd);
421
422     if (f == NULL) {
423         return -1;
424     }
425
426     return f->clazz->_fh_read( f, buf, len );
427 }
428
429
430 int  sdb_write(int  fd, const void*  buf, int  len)
431 {
432     FH     f = _fh_from_int(fd);
433
434     if (f == NULL) {
435         return -1;
436     }
437
438     return f->clazz->_fh_write(f, buf, len);
439 }
440
441
442 int  sdb_lseek(int  fd, int  pos, int  where)
443 {
444     FH     f = _fh_from_int(fd);
445
446     if (!f) {
447         return -1;
448     }
449
450     return f->clazz->_fh_lseek(f, pos, where);
451 }
452
453
454 int  sdb_shutdown(int  fd)
455 {
456     FH   f = _fh_from_int(fd);
457
458     if (!f) {
459         return -1;
460     }
461
462     D( "sdb_shutdown: %s\n", f->name);
463     shutdown( f->fh_socket, SD_BOTH );
464     return 0;
465 }
466
467
468 int  sdb_close(int  fd)
469 {
470     FH   f = _fh_from_int(fd);
471
472     if (!f) {
473         return -1;
474     }
475
476     D( "sdb_close: %s\n", f->name);
477     _fh_close(f);
478     return 0;
479 }
480
481 /**************************************************************************/
482 /**************************************************************************/
483 /*****                                                                *****/
484 /*****    socket-based file descriptors                               *****/
485 /*****                                                                *****/
486 /**************************************************************************/
487 /**************************************************************************/
488
489 static void
490 _socket_set_errno( void )
491 {
492     switch (WSAGetLastError()) {
493     case 0:              errno = 0; break;
494     case WSAEWOULDBLOCK: errno = EAGAIN; break;
495     case WSAEINTR:       errno = EINTR; break;
496     default:
497         D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
498         errno = EINVAL;
499     }
500 }
501
502 static void
503 _fh_socket_init( FH  f )
504 {
505     f->fh_socket = INVALID_SOCKET;
506     f->event     = WSACreateEvent();
507     f->mask      = 0;
508 }
509
510 static int
511 _fh_socket_close( FH  f )
512 {
513     /* gently tell any peer that we're closing the socket */
514     shutdown( f->fh_socket, SD_BOTH );
515     closesocket( f->fh_socket );
516     f->fh_socket = INVALID_SOCKET;
517     CloseHandle( f->event );
518     f->mask = 0;
519     return 0;
520 }
521
522 static int
523 _fh_socket_lseek( FH  f, int pos, int origin )
524 {
525     errno = EPIPE;
526     return -1;
527 }
528
529 static int
530 _fh_socket_read( FH  f, void*  buf, int  len )
531 {
532     int  result = recv( f->fh_socket, buf, len, 0 );
533     if (result == SOCKET_ERROR) {
534         _socket_set_errno();
535         result = -1;
536     }
537     return  result;
538 }
539
540 static int
541 _fh_socket_write( FH  f, const void*  buf, int  len )
542 {
543     int  result = send( f->fh_socket, buf, len, 0 );
544     if (result == SOCKET_ERROR) {
545         _socket_set_errno();
546         result = -1;
547     }
548     return result;
549 }
550
551 static void  _fh_socket_hook( FH  f, int  event, EventHook  hook );  /* forward */
552
553 static const FHClassRec  _fh_socket_class =
554 {
555     _fh_socket_init,
556     _fh_socket_close,
557     _fh_socket_lseek,
558     _fh_socket_read,
559     _fh_socket_write,
560     _fh_socket_hook
561 };
562
563 /**************************************************************************/
564 /**************************************************************************/
565 /*****                                                                *****/
566 /*****    replacement for libs/cutils/socket_xxxx.c                   *****/
567 /*****                                                                *****/
568 /**************************************************************************/
569 /**************************************************************************/
570
571 #include <winsock2.h>
572
573 static int  _winsock_init;
574
575 static void
576 _cleanup_winsock( void )
577 {
578     WSACleanup();
579 }
580
581 static void
582 _init_winsock( void )
583 {
584     if (!_winsock_init) {
585         WSADATA  wsaData;
586         int      rc = WSAStartup( MAKEWORD(2,2), &wsaData);
587         if (rc != 0) {
588             fatal( "sdb: could not initialize Winsock\n" );
589         }
590         atexit( _cleanup_winsock );
591         _winsock_init = 1;
592     }
593 }
594
595 int socket_loopback_client(int port, int type)
596 {
597     FH  f = _fh_alloc( &_fh_socket_class );
598     struct sockaddr_in addr;
599     SOCKET  s;
600
601     if (!f)
602         return -1;
603
604     if (!_winsock_init)
605         _init_winsock();
606
607     memset(&addr, 0, sizeof(addr));
608     addr.sin_family = AF_INET;
609     addr.sin_port = htons(port);
610     addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
611
612     s = socket(AF_INET, type, 0);
613     if(s == INVALID_SOCKET) {
614         D("socket_loopback_client: could not create socket\n" );
615         _fh_close(f);
616         return -1;
617     }
618
619     f->fh_socket = s;
620     if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
621         D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port );
622         _fh_close(f);
623         return -1;
624     }
625     snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
626     D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
627     return _fh_to_int(f);
628 }
629
630 #define LISTEN_BACKLOG 4
631
632 int socket_loopback_server(int port, int type)
633 {
634     FH   f = _fh_alloc( &_fh_socket_class );
635     struct sockaddr_in addr;
636     SOCKET  s;
637     int  n;
638
639     if (!f) {
640         return -1;
641     }
642
643     if (!_winsock_init)
644         _init_winsock();
645
646     memset(&addr, 0, sizeof(addr));
647     addr.sin_family = AF_INET;
648     addr.sin_port = htons(port);
649     addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
650
651     s = socket(AF_INET, type, 0);
652     if(s == INVALID_SOCKET) return -1;
653
654     f->fh_socket = s;
655
656     n = 1;
657     setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
658
659     if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
660         _fh_close(f);
661         return -1;
662     }
663     if (type == SOCK_STREAM) {
664         int ret;
665
666         ret = listen(s, LISTEN_BACKLOG);
667         if (ret < 0) {
668             _fh_close(f);
669             return -1;
670         }
671     }
672     snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
673     D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
674     return _fh_to_int(f);
675 }
676
677
678 int socket_network_client(const char *host, int port, int type)
679 {
680     FH  f = _fh_alloc( &_fh_socket_class );
681     struct hostent *hp;
682     struct sockaddr_in addr;
683     SOCKET s;
684
685     if (!f)
686         return -1;
687
688     if (!_winsock_init)
689         _init_winsock();
690
691     hp = gethostbyname(host);
692     if(hp == 0) {
693         _fh_close(f);
694         return -1;
695     }
696
697     memset(&addr, 0, sizeof(addr));
698     addr.sin_family = hp->h_addrtype;
699     addr.sin_port = htons(port);
700     memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
701
702     s = socket(hp->h_addrtype, type, 0);
703     if(s == INVALID_SOCKET) {
704         _fh_close(f);
705         return -1;
706     }
707     f->fh_socket = s;
708
709     if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
710         _fh_close(f);
711         return -1;
712     }
713
714     snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
715     D( "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
716     return _fh_to_int(f);
717 }
718
719
720 int socket_inaddr_any_server(int port, int type)
721 {
722     FH  f = _fh_alloc( &_fh_socket_class );
723     struct sockaddr_in addr;
724     SOCKET  s;
725     int n;
726
727     if (!f)
728         return -1;
729
730     if (!_winsock_init)
731         _init_winsock();
732
733     memset(&addr, 0, sizeof(addr));
734     addr.sin_family = AF_INET;
735     addr.sin_port = htons(port);
736     addr.sin_addr.s_addr = htonl(INADDR_ANY);
737
738     s = socket(AF_INET, type, 0);
739     if(s == INVALID_SOCKET) {
740         _fh_close(f);
741         return -1;
742     }
743
744     f->fh_socket = s;
745     n = 1;
746     setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
747
748     if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
749         _fh_close(f);
750         return -1;
751     }
752
753     if (type == SOCK_STREAM) {
754         int ret;
755
756         ret = listen(s, LISTEN_BACKLOG);
757         if (ret < 0) {
758             _fh_close(f);
759             return -1;
760         }
761     }
762     snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
763     D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
764     return _fh_to_int(f);
765 }
766
767 #undef accept
768 int  sdb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
769 {
770     FH   serverfh = _fh_from_int(serverfd);
771     FH   fh;
772
773     if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
774         D( "sdb_socket_accept: invalid fd %d\n", serverfd );
775         return -1;
776     }
777
778     fh = _fh_alloc( &_fh_socket_class );
779     if (!fh) {
780         D( "sdb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
781         return -1;
782     }
783
784     fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
785     if (fh->fh_socket == INVALID_SOCKET) {
786         _fh_close( fh );
787         D( "sdb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
788         return -1;
789     }
790
791     snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
792     D( "sdb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
793     return  _fh_to_int(fh);
794 }
795
796
797 void  disable_tcp_nagle(int fd)
798 {
799     FH   fh = _fh_from_int(fd);
800     int  on;
801
802     if ( !fh || fh->clazz != &_fh_socket_class )
803         return;
804
805     setsockopt( fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on) );
806 }
807
808 /**************************************************************************/
809 /**************************************************************************/
810 /*****                                                                *****/
811 /*****    emulated socketpairs                                       *****/
812 /*****                                                                *****/
813 /**************************************************************************/
814 /**************************************************************************/
815
816 /* we implement socketpairs directly in use space for the following reasons:
817  *   - it avoids copying data from/to the Nt kernel
818  *   - it allows us to implement fdevent hooks easily and cheaply, something
819  *     that is not possible with standard Win32 pipes !!
820  *
821  * basically, we use two circular buffers, each one corresponding to a given
822  * direction.
823  *
824  * each buffer is implemented as two regions:
825  *
826  *   region A which is (a_start,a_end)
827  *   region B which is (0, b_end)  with b_end <= a_start
828  *
829  * an empty buffer has:  a_start = a_end = b_end = 0
830  *
831  * a_start is the pointer where we start reading data
832  * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
833  * then you start writing at b_end
834  *
835  * the buffer is full when  b_end == a_start && a_end == BUFFER_SIZE
836  *
837  * there is room when b_end < a_start || a_end < BUFER_SIZE
838  *
839  * when reading, a_start is incremented, it a_start meets a_end, then
840  * we do:  a_start = 0, a_end = b_end, b_end = 0, and keep going on..
841  */
842
843 #define  BIP_BUFFER_SIZE   4096
844
845 #if 0
846 #include <stdio.h>
847 #  define  BIPD(x)      D x
848 #  define  BIPDUMP   bip_dump_hex
849
850 static void  bip_dump_hex( const unsigned char*  ptr, size_t  len )
851 {
852     int  nn, len2 = len;
853
854     if (len2 > 8) len2 = 8;
855
856     for (nn = 0; nn < len2; nn++) 
857         printf("%02x", ptr[nn]);
858     printf("  ");
859
860     for (nn = 0; nn < len2; nn++) {
861         int  c = ptr[nn];
862         if (c < 32 || c > 127)
863             c = '.';
864         printf("%c", c);
865     }
866     printf("\n");
867     fflush(stdout);
868 }
869
870 #else
871 #  define  BIPD(x)        do {} while (0)
872 #  define  BIPDUMP(p,l)   BIPD(p)
873 #endif
874
875 typedef struct BipBufferRec_
876 {
877     int                a_start;
878     int                a_end;
879     int                b_end;
880     int                fdin;
881     int                fdout;
882     int                closed;
883     int                can_write;  /* boolean */
884     HANDLE             evt_write;  /* event signaled when one can write to a buffer  */
885     int                can_read;   /* boolean */
886     HANDLE             evt_read;   /* event signaled when one can read from a buffer */
887     CRITICAL_SECTION  lock;
888     unsigned char      buff[ BIP_BUFFER_SIZE ];
889
890 } BipBufferRec, *BipBuffer;
891
892 static void
893 bip_buffer_init( BipBuffer  buffer )
894 {
895     D( "bit_buffer_init %p\n", buffer );
896     buffer->a_start   = 0;
897     buffer->a_end     = 0;
898     buffer->b_end     = 0;
899     buffer->can_write = 1;
900     buffer->can_read  = 0;
901     buffer->fdin      = 0;
902     buffer->fdout     = 0;
903     buffer->closed    = 0;
904     buffer->evt_write = CreateEvent( NULL, TRUE, TRUE, NULL );
905     buffer->evt_read  = CreateEvent( NULL, TRUE, FALSE, NULL );
906     InitializeCriticalSection( &buffer->lock );
907 }
908
909 static void
910 bip_buffer_close( BipBuffer  bip )
911 {
912     bip->closed = 1;
913
914     if (!bip->can_read) {
915         SetEvent( bip->evt_read );
916     }
917     if (!bip->can_write) {
918         SetEvent( bip->evt_write );
919     }
920 }
921
922 static void
923 bip_buffer_done( BipBuffer  bip )
924 {
925     BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout ));
926     CloseHandle( bip->evt_read );
927     CloseHandle( bip->evt_write );
928     DeleteCriticalSection( &bip->lock );
929 }
930
931 static int
932 bip_buffer_write( BipBuffer  bip, const void* src, int  len )
933 {
934     int  avail, count = 0;
935
936     if (len <= 0)
937         return 0;
938
939     BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
940     BIPDUMP( src, len );
941
942     EnterCriticalSection( &bip->lock );
943
944     while (!bip->can_write) {
945         int  ret;
946         LeaveCriticalSection( &bip->lock );
947
948         if (bip->closed) {
949             errno = EPIPE;
950             return -1;
951         }
952         /* spinlocking here is probably unfair, but let's live with it */
953         ret = WaitForSingleObject( bip->evt_write, INFINITE );
954         if (ret != WAIT_OBJECT_0) {  /* buffer probably closed */
955             D( "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError() );
956             return 0;
957         }
958         if (bip->closed) {
959             errno = EPIPE;
960             return -1;
961         }
962         EnterCriticalSection( &bip->lock );
963     }
964
965     BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
966
967     avail = BIP_BUFFER_SIZE - bip->a_end;
968     if (avail > 0)
969     {
970         /* we can append to region A */
971         if (avail > len)
972             avail = len;
973
974         memcpy( bip->buff + bip->a_end, src, avail );
975         src   += avail;
976         count += avail;
977         len   -= avail;
978
979         bip->a_end += avail;
980         if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
981             bip->can_write = 0;
982             ResetEvent( bip->evt_write );
983             goto Exit;
984         }
985     }
986
987     if (len == 0)
988         goto Exit;
989
990     avail = bip->a_start - bip->b_end;
991     assert( avail > 0 );  /* since can_write is TRUE */
992
993     if (avail > len)
994         avail = len;
995
996     memcpy( bip->buff + bip->b_end, src, avail );
997     count += avail;
998     bip->b_end += avail;
999
1000     if (bip->b_end == bip->a_start) {
1001         bip->can_write = 0;
1002         ResetEvent( bip->evt_write );
1003     }
1004
1005 Exit:
1006     assert( count > 0 );
1007
1008     if ( !bip->can_read ) {
1009         bip->can_read = 1;
1010         SetEvent( bip->evt_read );
1011     }
1012
1013     BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", 
1014             bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
1015     LeaveCriticalSection( &bip->lock );
1016
1017     return count;
1018  }
1019
1020 static int
1021 bip_buffer_read( BipBuffer  bip, void*  dst, int  len )
1022 {
1023     int  avail, count = 0;
1024
1025     if (len <= 0)
1026         return 0;
1027
1028     BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
1029
1030     EnterCriticalSection( &bip->lock );
1031     while ( !bip->can_read )
1032     {
1033 #if 0
1034         LeaveCriticalSection( &bip->lock );
1035         errno = EAGAIN;
1036         return -1;
1037 #else    
1038         int  ret;
1039         LeaveCriticalSection( &bip->lock );
1040
1041         if (bip->closed) {
1042             errno = EPIPE;
1043             return -1;
1044         }
1045
1046         ret = WaitForSingleObject( bip->evt_read, INFINITE );
1047         if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
1048             D( "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
1049             return 0;
1050         }
1051         if (bip->closed) {
1052             errno = EPIPE;
1053             return -1;
1054         }
1055         EnterCriticalSection( &bip->lock );
1056 #endif
1057     }
1058
1059     BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
1060
1061     avail = bip->a_end - bip->a_start;
1062     assert( avail > 0 );  /* since can_read is TRUE */
1063
1064     if (avail > len)
1065         avail = len;
1066
1067     memcpy( dst, bip->buff + bip->a_start, avail );
1068     dst   += avail;
1069     count += avail;
1070     len   -= avail;
1071
1072     bip->a_start += avail;
1073     if (bip->a_start < bip->a_end)
1074         goto Exit;
1075
1076     bip->a_start = 0;
1077     bip->a_end   = bip->b_end;
1078     bip->b_end   = 0;
1079
1080     avail = bip->a_end;
1081     if (avail > 0) {
1082         if (avail > len)
1083             avail = len;
1084         memcpy( dst, bip->buff, avail );
1085         count += avail;
1086         bip->a_start += avail;
1087
1088         if ( bip->a_start < bip->a_end )
1089             goto Exit;
1090
1091         bip->a_start = bip->a_end = 0;
1092     }
1093
1094     bip->can_read = 0;
1095     ResetEvent( bip->evt_read );
1096
1097 Exit:
1098     assert( count > 0 );
1099
1100     if (!bip->can_write ) {
1101         bip->can_write = 1;
1102         SetEvent( bip->evt_write );
1103     }
1104
1105     BIPDUMP( (const unsigned char*)dst - count, count );
1106     BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", 
1107             bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
1108     LeaveCriticalSection( &bip->lock );
1109
1110     return count;
1111 }
1112
1113 typedef struct SocketPairRec_ 
1114 {
1115     BipBufferRec  a2b_bip;
1116     BipBufferRec  b2a_bip;
1117     FH            a_fd;
1118     int           used;
1119
1120 } SocketPairRec;
1121
1122 void _fh_socketpair_init( FH  f )
1123 {
1124     f->fh_pair = NULL;
1125 }
1126
1127 static int
1128 _fh_socketpair_close( FH  f )
1129 {
1130     if ( f->fh_pair ) {
1131         SocketPair  pair = f->fh_pair;
1132
1133         if ( f == pair->a_fd ) {
1134             pair->a_fd = NULL;
1135         }
1136
1137         bip_buffer_close( &pair->b2a_bip );
1138         bip_buffer_close( &pair->a2b_bip );
1139
1140         if ( --pair->used == 0 ) {
1141             bip_buffer_done( &pair->b2a_bip );
1142             bip_buffer_done( &pair->a2b_bip );
1143             free( pair );
1144         }
1145         f->fh_pair = NULL;
1146     }
1147     return 0;
1148 }
1149
1150 static int
1151 _fh_socketpair_lseek( FH  f, int pos, int  origin )
1152 {
1153     errno = ESPIPE;
1154     return -1;
1155 }
1156
1157 static int
1158 _fh_socketpair_read( FH  f, void* buf, int  len )
1159 {
1160     SocketPair  pair = f->fh_pair;
1161     BipBuffer   bip;
1162
1163     if (!pair)
1164         return -1;
1165
1166     if ( f == pair->a_fd )
1167         bip = &pair->b2a_bip;
1168     else
1169         bip = &pair->a2b_bip;
1170
1171     return bip_buffer_read( bip, buf, len );
1172 }
1173
1174 static int
1175 _fh_socketpair_write( FH  f, const void*  buf, int  len )
1176 {
1177     SocketPair  pair = f->fh_pair;
1178     BipBuffer   bip;
1179
1180     if (!pair)
1181         return -1;
1182
1183     if ( f == pair->a_fd )
1184         bip = &pair->a2b_bip;
1185     else
1186         bip = &pair->b2a_bip;
1187
1188     return bip_buffer_write( bip, buf, len );
1189 }
1190
1191
1192 static void  _fh_socketpair_hook( FH  f, int  event, EventHook  hook );  /* forward */
1193
1194 static const FHClassRec  _fh_socketpair_class =
1195 {
1196     _fh_socketpair_init,
1197     _fh_socketpair_close,
1198     _fh_socketpair_lseek,
1199     _fh_socketpair_read,
1200     _fh_socketpair_write,
1201     _fh_socketpair_hook
1202 };
1203
1204
1205 int  sdb_socketpair( int  sv[2] )
1206 {
1207     FH          fa, fb;
1208     SocketPair  pair;
1209
1210     fa = _fh_alloc( &_fh_socketpair_class );
1211     fb = _fh_alloc( &_fh_socketpair_class );
1212
1213     if (!fa || !fb)
1214         goto Fail;
1215
1216     pair = malloc( sizeof(*pair) );
1217     if (pair == NULL) {
1218         D("sdb_socketpair: not enough memory to allocate pipes\n" );
1219         goto Fail;
1220     }
1221
1222     bip_buffer_init( &pair->a2b_bip );
1223     bip_buffer_init( &pair->b2a_bip );
1224
1225     fa->fh_pair = pair;
1226     fb->fh_pair = pair;
1227     pair->used  = 2;
1228     pair->a_fd  = fa;
1229
1230     sv[0] = _fh_to_int(fa);
1231     sv[1] = _fh_to_int(fb);
1232
1233     pair->a2b_bip.fdin  = sv[0];
1234     pair->a2b_bip.fdout = sv[1];
1235     pair->b2a_bip.fdin  = sv[1];
1236     pair->b2a_bip.fdout = sv[0];
1237
1238     snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
1239     snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
1240     D( "sdb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
1241     return 0;
1242
1243 Fail:
1244     _fh_close(fb);
1245     _fh_close(fa);
1246     return -1;
1247 }
1248
1249 /**************************************************************************/
1250 /**************************************************************************/
1251 /*****                                                                *****/
1252 /*****    fdevents emulation                                          *****/
1253 /*****                                                                *****/
1254 /*****   this is a very simple implementation, we rely on the fact    *****/
1255 /*****   that SDB doesn't use FDE_ERROR.                              *****/
1256 /*****                                                                *****/
1257 /**************************************************************************/
1258 /**************************************************************************/
1259
1260 #define FATAL(x...) fatal(__FUNCTION__, x)
1261
1262 #if DEBUG
1263 static void dump_fde(fdevent *fde, const char *info)
1264 {
1265     fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
1266             fde->state & FDE_READ ? 'R' : ' ',
1267             fde->state & FDE_WRITE ? 'W' : ' ',
1268             fde->state & FDE_ERROR ? 'E' : ' ',
1269             info);
1270 }
1271 #else
1272 #define dump_fde(fde, info) do { } while(0)
1273 #endif
1274
1275 #define FDE_EVENTMASK  0x00ff
1276 #define FDE_STATEMASK  0xff00
1277
1278 #define FDE_ACTIVE     0x0100
1279 #define FDE_PENDING    0x0200
1280 #define FDE_CREATED    0x0400
1281
1282 static void fdevent_plist_enqueue(fdevent *node);
1283 static void fdevent_plist_remove(fdevent *node);
1284 static fdevent *fdevent_plist_dequeue(void);
1285
1286 static fdevent list_pending = {
1287     .next = &list_pending,
1288     .prev = &list_pending,
1289 };
1290
1291 static fdevent **fd_table = 0;
1292 static int       fd_table_max = 0;
1293
1294 typedef struct EventLooperRec_*  EventLooper;
1295
1296 typedef struct EventHookRec_
1297 {
1298     EventHook    next;
1299     FH           fh;
1300     HANDLE       h;
1301     int          wanted;   /* wanted event flags */
1302     int          ready;    /* ready event flags  */
1303     void*        aux;
1304     void        (*prepare)( EventHook  hook );
1305     int         (*start)  ( EventHook  hook );
1306     void        (*stop)   ( EventHook  hook );
1307     int         (*check)  ( EventHook  hook );
1308     int         (*peek)   ( EventHook  hook );
1309 } EventHookRec;
1310
1311 static EventHook  _free_hooks;
1312
1313 static EventHook
1314 event_hook_alloc( FH  fh )
1315 {
1316     EventHook  hook = _free_hooks;
1317     if (hook != NULL)
1318         _free_hooks = hook->next;
1319     else {
1320         hook = malloc( sizeof(*hook) );
1321         if (hook == NULL)
1322             fatal( "could not allocate event hook\n" );
1323     }
1324     hook->next   = NULL;
1325     hook->fh     = fh;
1326     hook->wanted = 0;
1327     hook->ready  = 0;
1328     hook->h      = INVALID_HANDLE_VALUE;
1329     hook->aux    = NULL;
1330
1331     hook->prepare = NULL;
1332     hook->start   = NULL;
1333     hook->stop    = NULL;
1334     hook->check   = NULL;
1335     hook->peek    = NULL;
1336
1337     return hook;
1338 }
1339
1340 static void
1341 event_hook_free( EventHook  hook )
1342 {
1343     hook->fh     = NULL;
1344     hook->wanted = 0;
1345     hook->ready  = 0;
1346     hook->next   = _free_hooks;
1347     _free_hooks  = hook;
1348 }
1349
1350
1351 static void
1352 event_hook_signal( EventHook  hook )
1353 {
1354     FH        f   = hook->fh;
1355     int       fd  = _fh_to_int(f);
1356     fdevent*  fde = fd_table[ fd - WIN32_FH_BASE ];
1357
1358     if (fde != NULL && fde->fd == fd) {
1359         if ((fde->state & FDE_PENDING) == 0) {
1360             fde->state |= FDE_PENDING;
1361             fdevent_plist_enqueue( fde );
1362         }
1363         fde->events |= hook->wanted;
1364     }
1365 }
1366
1367
1368 #define  MAX_LOOPER_HANDLES  WIN32_MAX_FHS
1369
1370 typedef struct EventLooperRec_
1371 {
1372     EventHook    hooks;
1373     HANDLE       htab[ MAX_LOOPER_HANDLES ];
1374     int          htab_count;
1375
1376 } EventLooperRec;
1377
1378 static EventHook*
1379 event_looper_find_p( EventLooper  looper, FH  fh )
1380 {
1381     EventHook  *pnode = &looper->hooks;
1382     EventHook   node  = *pnode;
1383     for (;;) {
1384         if ( node == NULL || node->fh == fh )
1385             break;
1386         pnode = &node->next;
1387         node  = *pnode;
1388     }
1389     return  pnode;
1390 }
1391
1392 static void
1393 event_looper_hook( EventLooper  looper, int  fd, int  events )
1394 {
1395     FH          f = _fh_from_int(fd);
1396     EventHook  *pnode;
1397     EventHook   node;
1398
1399     if (f == NULL)  /* invalid arg */ {
1400         D("event_looper_hook: invalid fd=%d\n", fd);
1401         return;
1402     }
1403
1404     pnode = event_looper_find_p( looper, f );
1405     node  = *pnode;
1406     if ( node == NULL ) {
1407         node       = event_hook_alloc( f );
1408         node->next = *pnode;
1409         *pnode     = node;
1410     }
1411
1412     if ( (node->wanted & events) != events ) {
1413         /* this should update start/stop/check/peek */
1414         D("event_looper_hook: call hook for %d (new=%x, old=%x)\n",
1415            fd, node->wanted, events);
1416         f->clazz->_fh_hook( f, events & ~node->wanted, node );
1417         node->wanted |= events;
1418     } else {
1419         D("event_looper_hook: ignoring events %x for %d wanted=%x)\n", 
1420            events, fd, node->wanted);
1421     }
1422 }
1423
1424 static void
1425 event_looper_unhook( EventLooper  looper, int  fd, int  events )
1426 {
1427     FH          fh    = _fh_from_int(fd);
1428     EventHook  *pnode = event_looper_find_p( looper, fh );
1429     EventHook   node  = *pnode;
1430
1431     if (node != NULL) {
1432         int  events2 = events & node->wanted;
1433         if ( events2 == 0 ) {
1434             D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd );
1435             return;
1436         }
1437         node->wanted &= ~events2;
1438         if (!node->wanted) {
1439             *pnode = node->next;
1440             event_hook_free( node );
1441         }
1442     }
1443 }
1444
1445 static EventLooperRec  win32_looper;
1446
1447 static void fdevent_init(void)
1448 {
1449     win32_looper.htab_count = 0;
1450     win32_looper.hooks      = NULL;
1451 }
1452
1453 static void fdevent_connect(fdevent *fde)
1454 {
1455     EventLooper  looper = &win32_looper;
1456     int          events = fde->state & FDE_EVENTMASK;
1457
1458     if (events != 0)
1459         event_looper_hook( looper, fde->fd, events );
1460 }
1461
1462 static void fdevent_disconnect(fdevent *fde)
1463 {
1464     EventLooper  looper = &win32_looper;
1465     int          events = fde->state & FDE_EVENTMASK;
1466
1467     if (events != 0)
1468         event_looper_unhook( looper, fde->fd, events );
1469 }
1470
1471 static void fdevent_update(fdevent *fde, unsigned events)
1472 {
1473     EventLooper  looper  = &win32_looper;
1474     unsigned     events0 = fde->state & FDE_EVENTMASK;
1475
1476     if (events != events0) {
1477         int  removes = events0 & ~events;
1478         int  adds    = events  & ~events0;
1479         if (removes) {
1480             D("fdevent_update: remove %x from %d\n", removes, fde->fd);
1481             event_looper_unhook( looper, fde->fd, removes );
1482         }
1483         if (adds) {
1484             D("fdevent_update: add %x to %d\n", adds, fde->fd);
1485             event_looper_hook  ( looper, fde->fd, adds );
1486         }
1487     }
1488 }
1489
1490 static void fdevent_process()
1491 {
1492     EventLooper  looper = &win32_looper;
1493     EventHook    hook;
1494     int          gotone = 0;
1495
1496     /* if we have at least one ready hook, execute it/them */
1497     for (hook = looper->hooks; hook; hook = hook->next) {
1498         hook->ready = 0;
1499         if (hook->prepare) {
1500             hook->prepare(hook);
1501             if (hook->ready != 0) {
1502                 event_hook_signal( hook );
1503                 gotone = 1;
1504             }
1505         }
1506     }
1507
1508     /* nothing's ready yet, so wait for something to happen */
1509     if (!gotone)
1510     {
1511         looper->htab_count = 0;
1512
1513         for (hook = looper->hooks; hook; hook = hook->next) 
1514         {
1515             if (hook->start && !hook->start(hook)) {
1516                 D( "fdevent_process: error when starting a hook\n" );
1517                 return;
1518             }
1519             if (hook->h != INVALID_HANDLE_VALUE) {
1520                 int  nn;
1521
1522                 for (nn = 0; nn < looper->htab_count; nn++)
1523                 {
1524                     if ( looper->htab[nn] == hook->h )
1525                         goto DontAdd;
1526                 }
1527                 looper->htab[ looper->htab_count++ ] = hook->h;
1528             DontAdd:
1529                 ;
1530             }
1531         }
1532
1533         if (looper->htab_count == 0) {
1534             D( "fdevent_process: nothing to wait for !!\n" );
1535             return;
1536         }
1537
1538         do
1539         {
1540             int   wait_ret;
1541
1542             D( "sdb_win32: waiting for %d events\n", looper->htab_count );
1543             if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
1544                 D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS, aborting!\n", looper->htab_count);
1545                 abort();
1546             }
1547             wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
1548             if (wait_ret == (int)WAIT_FAILED) {
1549                 D( "sdb_win32: wait failed, error %ld\n", GetLastError() );
1550             } else {
1551                 D( "sdb_win32: got one (index %d)\n", wait_ret );
1552
1553                 /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
1554                  * like mouse movements. we need to filter these with the "check" function
1555                  */
1556                 if ((unsigned)wait_ret < (unsigned)looper->htab_count)
1557                 {
1558                     for (hook = looper->hooks; hook; hook = hook->next)
1559                     {
1560                         if ( looper->htab[wait_ret] == hook->h       &&
1561                          (!hook->check || hook->check(hook)) )
1562                         {
1563                             D( "sdb_win32: signaling %s for %x\n", hook->fh->name, hook->ready );
1564                             event_hook_signal( hook );
1565                             gotone = 1;
1566                             break;
1567                         }
1568                     }
1569                 }
1570             }
1571         }
1572         while (!gotone);
1573
1574         for (hook = looper->hooks; hook; hook = hook->next) {
1575             if (hook->stop)
1576                 hook->stop( hook );
1577         }
1578     }
1579
1580     for (hook = looper->hooks; hook; hook = hook->next) {
1581         if (hook->peek && hook->peek(hook))
1582                 event_hook_signal( hook );
1583     }
1584 }
1585
1586
1587 static void fdevent_register(fdevent *fde)
1588 {
1589     int  fd = fde->fd - WIN32_FH_BASE;
1590
1591     if(fd < 0) {
1592         FATAL("bogus negative fd (%d)\n", fde->fd);
1593     }
1594
1595     if(fd >= fd_table_max) {
1596         int oldmax = fd_table_max;
1597         if(fde->fd > 32000) {
1598             FATAL("bogus huuuuge fd (%d)\n", fde->fd);
1599         }
1600         if(fd_table_max == 0) {
1601             fdevent_init();
1602             fd_table_max = 256;
1603         }
1604         while(fd_table_max <= fd) {
1605             fd_table_max *= 2;
1606         }
1607         fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
1608         if(fd_table == 0) {
1609             FATAL("could not expand fd_table to %d entries\n", fd_table_max);
1610         }
1611         memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
1612     }
1613
1614     fd_table[fd] = fde;
1615 }
1616
1617 static void fdevent_unregister(fdevent *fde)
1618 {
1619     int  fd = fde->fd - WIN32_FH_BASE;
1620
1621     if((fd < 0) || (fd >= fd_table_max)) {
1622         FATAL("fd out of range (%d)\n", fde->fd);
1623     }
1624
1625     if(fd_table[fd] != fde) {
1626         FATAL("fd_table out of sync");
1627     }
1628
1629     fd_table[fd] = 0;
1630
1631     if(!(fde->state & FDE_DONT_CLOSE)) {
1632         dump_fde(fde, "close");
1633         sdb_close(fde->fd);
1634     }
1635 }
1636
1637 static void fdevent_plist_enqueue(fdevent *node)
1638 {
1639     fdevent *list = &list_pending;
1640
1641     node->next = list;
1642     node->prev = list->prev;
1643     node->prev->next = node;
1644     list->prev = node;
1645 }
1646
1647 static void fdevent_plist_remove(fdevent *node)
1648 {
1649     node->prev->next = node->next;
1650     node->next->prev = node->prev;
1651     node->next = 0;
1652     node->prev = 0;
1653 }
1654
1655 static fdevent *fdevent_plist_dequeue(void)
1656 {
1657     fdevent *list = &list_pending;
1658     fdevent *node = list->next;
1659
1660     if(node == list) return 0;
1661
1662     list->next = node->next;
1663     list->next->prev = list;
1664     node->next = 0;
1665     node->prev = 0;
1666
1667     return node;
1668 }
1669
1670 fdevent *fdevent_create(int fd, fd_func func, void *arg)
1671 {
1672     fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
1673     if(fde == 0) return 0;
1674     fdevent_install(fde, fd, func, arg);
1675     fde->state |= FDE_CREATED;
1676     return fde;
1677 }
1678
1679 void fdevent_destroy(fdevent *fde)
1680 {
1681     if(fde == 0) return;
1682     if(!(fde->state & FDE_CREATED)) {
1683         FATAL("fde %p not created by fdevent_create()\n", fde);
1684     }
1685     fdevent_remove(fde);
1686 }
1687
1688 void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) 
1689 {
1690     memset(fde, 0, sizeof(fdevent));
1691     fde->state = FDE_ACTIVE;
1692     fde->fd = fd;
1693     fde->func = func;
1694     fde->arg = arg;
1695
1696     fdevent_register(fde);
1697     dump_fde(fde, "connect");
1698     fdevent_connect(fde);
1699     fde->state |= FDE_ACTIVE;
1700 }
1701
1702 void fdevent_remove(fdevent *fde)
1703 {
1704     if(fde->state & FDE_PENDING) {
1705         fdevent_plist_remove(fde);
1706     }
1707
1708     if(fde->state & FDE_ACTIVE) {
1709         fdevent_disconnect(fde);
1710         dump_fde(fde, "disconnect");    
1711         fdevent_unregister(fde);
1712     }
1713
1714     fde->state = 0;
1715     fde->events = 0;
1716 }
1717
1718
1719 void fdevent_set(fdevent *fde, unsigned events)
1720 {
1721     events &= FDE_EVENTMASK;
1722
1723     if((fde->state & FDE_EVENTMASK) == (int)events) return;
1724
1725     if(fde->state & FDE_ACTIVE) {
1726         fdevent_update(fde, events);
1727         dump_fde(fde, "update");
1728     }
1729
1730     fde->state = (fde->state & FDE_STATEMASK) | events;
1731
1732     if(fde->state & FDE_PENDING) {
1733             /* if we're pending, make sure
1734             ** we don't signal an event that
1735             ** is no longer wanted.
1736             */
1737         fde->events &= (~events);
1738         if(fde->events == 0) {
1739             fdevent_plist_remove(fde);
1740             fde->state &= (~FDE_PENDING);
1741         }
1742     }
1743 }
1744
1745 void fdevent_add(fdevent *fde, unsigned events)
1746 {
1747     fdevent_set(
1748         fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
1749 }
1750
1751 void fdevent_del(fdevent *fde, unsigned events)
1752 {
1753     fdevent_set(
1754         fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
1755 }
1756
1757 void fdevent_loop()
1758 {
1759     fdevent *fde;
1760
1761     for(;;) {
1762 #if DEBUG
1763         fprintf(stderr,"--- ---- waiting for events\n");
1764 #endif
1765         fdevent_process();
1766
1767         while((fde = fdevent_plist_dequeue())) {
1768             unsigned events = fde->events;
1769             fde->events = 0;
1770             fde->state &= (~FDE_PENDING);
1771             dump_fde(fde, "callback");
1772             fde->func(fde->fd, events, fde->arg);
1773         }
1774     }
1775 }
1776
1777 /**  FILE EVENT HOOKS
1778  **/
1779
1780 static void  _event_file_prepare( EventHook  hook )
1781 {
1782     if (hook->wanted & (FDE_READ|FDE_WRITE)) {
1783         /* we can always read/write */
1784         hook->ready |= hook->wanted & (FDE_READ|FDE_WRITE);
1785     }
1786 }
1787
1788 static int  _event_file_peek( EventHook  hook )
1789 {
1790     return (hook->wanted & (FDE_READ|FDE_WRITE));
1791 }
1792
1793 static void  _fh_file_hook( FH  f, int  events, EventHook  hook )
1794 {
1795     hook->h       = f->fh_handle;
1796     hook->prepare = _event_file_prepare;
1797     hook->peek    = _event_file_peek;
1798 }
1799
1800 /** SOCKET EVENT HOOKS
1801  **/
1802
1803 static void  _event_socket_verify( EventHook  hook, WSANETWORKEVENTS*  evts )
1804 {
1805     if ( evts->lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE) ) {
1806         if (hook->wanted & FDE_READ)
1807             hook->ready |= FDE_READ;
1808         if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR)
1809             hook->ready |= FDE_ERROR;
1810     }
1811     if ( evts->lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE) ) {
1812         if (hook->wanted & FDE_WRITE)
1813             hook->ready |= FDE_WRITE;
1814         if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR)
1815             hook->ready |= FDE_ERROR;
1816     }
1817     if ( evts->lNetworkEvents & FD_OOB ) {
1818         if (hook->wanted & FDE_ERROR)
1819             hook->ready |= FDE_ERROR;
1820     }
1821 }
1822
1823 static void  _event_socket_prepare( EventHook  hook )
1824 {
1825     WSANETWORKEVENTS  evts;
1826
1827     /* look if some of the events we want already happened ? */
1828     if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
1829         _event_socket_verify( hook, &evts );
1830 }
1831
1832 static int  _socket_wanted_to_flags( int  wanted )
1833 {
1834     int  flags = 0;
1835     if (wanted & FDE_READ)
1836         flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
1837
1838     if (wanted & FDE_WRITE)
1839         flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
1840
1841     if (wanted & FDE_ERROR)
1842         flags |= FD_OOB;
1843
1844     return flags;
1845 }
1846
1847 static int _event_socket_start( EventHook  hook )
1848 {
1849     /* create an event which we're going to wait for */
1850     FH    fh    = hook->fh;
1851     long  flags = _socket_wanted_to_flags( hook->wanted );
1852
1853     hook->h = fh->event;
1854     if (hook->h == INVALID_HANDLE_VALUE) {
1855         D( "_event_socket_start: no event for %s\n", fh->name );
1856         return 0;
1857     }
1858
1859     if ( flags != fh->mask ) {
1860         D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags );
1861         if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
1862             D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError() );
1863             CloseHandle( hook->h );
1864             hook->h = INVALID_HANDLE_VALUE;
1865             exit(1);
1866             return 0;
1867         }
1868         fh->mask = flags;
1869     }
1870     return 1;
1871 }
1872
1873 static void _event_socket_stop( EventHook  hook )
1874 {
1875     hook->h = INVALID_HANDLE_VALUE;
1876 }
1877
1878 static int  _event_socket_check( EventHook  hook )
1879 {
1880     int               result = 0;
1881     FH                fh = hook->fh;
1882     WSANETWORKEVENTS  evts;
1883
1884     if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
1885         _event_socket_verify( hook, &evts );
1886         result = (hook->ready != 0);
1887         if (result) {
1888             ResetEvent( hook->h );
1889         }
1890     }
1891     D( "_event_socket_check %s returns %d\n", fh->name, result );
1892     return  result;
1893 }
1894
1895 static int  _event_socket_peek( EventHook  hook )
1896 {
1897     WSANETWORKEVENTS  evts;
1898     FH                fh = hook->fh;
1899
1900     /* look if some of the events we want already happened ? */
1901     if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
1902         _event_socket_verify( hook, &evts );
1903         if (hook->ready)
1904             ResetEvent( hook->h );
1905     }
1906
1907     return hook->ready != 0;
1908 }
1909
1910
1911
1912 static void  _fh_socket_hook( FH  f, int  events, EventHook  hook )
1913 {
1914     hook->prepare = _event_socket_prepare;
1915     hook->start   = _event_socket_start;
1916     hook->stop    = _event_socket_stop;
1917     hook->check   = _event_socket_check;
1918     hook->peek    = _event_socket_peek;
1919
1920     _event_socket_start( hook );
1921 }
1922
1923 /** SOCKETPAIR EVENT HOOKS
1924  **/
1925
1926 static void  _event_socketpair_prepare( EventHook  hook )
1927 {
1928     FH          fh   = hook->fh;
1929     SocketPair  pair = fh->fh_pair;
1930     BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
1931     BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
1932
1933     if (hook->wanted & FDE_READ && rbip->can_read)
1934         hook->ready |= FDE_READ;
1935
1936     if (hook->wanted & FDE_WRITE && wbip->can_write) 
1937         hook->ready |= FDE_WRITE;
1938  }
1939
1940  static int  _event_socketpair_start( EventHook  hook )
1941  {
1942     FH          fh   = hook->fh;
1943     SocketPair  pair = fh->fh_pair;
1944     BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
1945     BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
1946
1947     if (hook->wanted == FDE_READ)
1948         hook->h = rbip->evt_read;
1949
1950     else if (hook->wanted == FDE_WRITE)
1951         hook->h = wbip->evt_write;
1952
1953     else {
1954         D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" );
1955         return 0;
1956     }
1957     D( "_event_socketpair_start: hook %s for %x wanted=%x\n", 
1958        hook->fh->name, _fh_to_int(fh), hook->wanted);
1959     return 1;
1960 }
1961
1962 static int  _event_socketpair_peek( EventHook  hook )
1963 {
1964     _event_socketpair_prepare( hook );
1965     return hook->ready != 0;
1966 }
1967
1968 static void  _fh_socketpair_hook( FH  fh, int  events, EventHook  hook )
1969 {
1970     hook->prepare = _event_socketpair_prepare;
1971     hook->start   = _event_socketpair_start;
1972     hook->peek    = _event_socketpair_peek;
1973 }
1974
1975
1976 void
1977 sdb_sysdeps_init( void )
1978 {
1979 #define  SDB_MUTEX(x)  InitializeCriticalSection( & x );
1980 #include "mutex_list.h"
1981     InitializeCriticalSection( &_win32_lock );
1982 }