Add support the shutdown Event.
[catagits/fcgi2.git] / libfcgi / os_win32.c
1 /*
2  * os_win32.c --
3  *
4  *
5  *  Copyright (c) 1995 Open Market, Inc.
6  *  All rights reserved.
7  *
8  *  This file contains proprietary and confidential information and
9  *  remains the unpublished property of Open Market, Inc. Use,
10  *  disclosure, or reproduction is prohibited except as permitted by
11  *  express written license agreement with Open Market, Inc.
12  *
13  *  Bill Snapper
14  *  snapper@openmarket.com
15  *
16  * (Special thanks to Karen and Bill.  They made my job much easier and
17  *  significantly more enjoyable.)
18  */
19 #ifndef lint
20 static const char rcsid[] = "$Id: os_win32.c,v 1.9 2001/03/26 20:04:56 robs Exp $";
21 #endif /* not lint */
22
23 #include "fcgi_config.h"
24
25 #define DLLAPI  __declspec(dllexport)
26
27 #include <assert.h>
28 #include <stdio.h>
29 #include <sys/timeb.h>
30 #include <Winsock2.h>
31 #include <Windows.h>
32
33 #include "fcgios.h"
34
35 #define ASSERT assert
36
37 #define WIN32_OPEN_MAX 128 /* XXX: Small hack */
38 #define MUTEX_VARNAME "_FCGI_MUTEX_"
39 #define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_"
40
41 static HANDLE hIoCompPort = INVALID_HANDLE_VALUE;
42 static HANDLE hStdinCompPort = INVALID_HANDLE_VALUE;
43 static HANDLE hStdinThread = INVALID_HANDLE_VALUE;
44
45 static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
46                                  INVALID_HANDLE_VALUE};
47
48 static HANDLE acceptMutex = INVALID_HANDLE_VALUE;
49
50 static BOOLEAN shutdownPending = FALSE;
51
52 /*
53  * An enumeration of the file types
54  * supported by the FD_TABLE structure.
55  *
56  * XXX: Not all currently supported.  This allows for future
57  *      functionality.
58  */
59 typedef enum {
60     FD_UNUSED,
61     FD_FILE_SYNC,
62     FD_FILE_ASYNC,
63     FD_SOCKET_SYNC,
64     FD_SOCKET_ASYNC,
65     FD_PIPE_SYNC,
66     FD_PIPE_ASYNC
67 } FILE_TYPE;
68
69 typedef union {
70     HANDLE fileHandle;
71     SOCKET sock;
72     unsigned int value;
73 } DESCRIPTOR;
74
75 /*
76  * Structure used to map file handle and socket handle
77  * values into values that can be used to create unix-like
78  * select bitmaps, read/write for both sockets/files.
79  */
80 struct FD_TABLE {
81     DESCRIPTOR fid;
82     FILE_TYPE type;
83     char *path;
84     DWORD Errno;
85     unsigned long instance;
86     int status;
87     int offset;                 /* only valid for async file writes */
88     LPDWORD offsetHighPtr;      /* pointers to offset high and low words */
89     LPDWORD offsetLowPtr;       /* only valid for async file writes (logs) */
90     HANDLE  hMapMutex;          /* mutex handle for multi-proc offset update */
91     LPVOID  ovList;             /* List of associated OVERLAPPED_REQUESTs */
92 };
93
94 typedef struct FD_TABLE *PFD_TABLE;
95
96 /* 
97  * XXX Note there is no dyanmic sizing of this table, so if the
98  * number of open file descriptors exceeds WIN32_OPEN_MAX the 
99  * app will blow up.
100  */
101 static struct FD_TABLE fdTable[WIN32_OPEN_MAX];
102
103 struct OVERLAPPED_REQUEST {
104     OVERLAPPED overlapped;
105     unsigned long instance;     /* file instance (won't match after a close) */
106     OS_AsyncProc procPtr;       /* callback routine */
107     ClientData clientData;      /* callback argument */
108     ClientData clientData1;     /* additional clientData */
109 };
110 typedef struct OVERLAPPED_REQUEST *POVERLAPPED_REQUEST;
111
112 static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\";
113
114 static int listenType = FD_UNUSED;
115
116 // XXX This should be a DESCRIPTOR
117 static HANDLE hListen = INVALID_HANDLE_VALUE;
118
119 static OVERLAPPED listenOverlapped;
120 static BOOLEAN libInitialized = FALSE;
121
122 \f
123 /*
124  *--------------------------------------------------------------
125  *
126  * Win32NewDescriptor --
127  *
128  *      Set up for I/O descriptor masquerading.
129  *
130  * Results:
131  *      Returns "fake id" which masquerades as a UNIX-style "small
132  *      non-negative integer" file/socket descriptor.
133  *      Win32_* routine below will "do the right thing" based on the
134  *      descriptor's actual type. -1 indicates failure.
135  *
136  * Side effects:
137  *      Entry in fdTable is reserved to represent the socket/file.
138  *
139  *--------------------------------------------------------------
140  */
141 static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd)
142 {
143     int index;
144
145     /*
146      * If the "desiredFd" is not -1, try to get this entry for our
147      * pseudo file descriptor.  If this is not available, return -1
148      * as the caller wanted to get this mapping.  This is typically
149      * only used for mapping stdio handles.
150      */
151     if (desiredFd >= 0 && desiredFd < WIN32_OPEN_MAX)
152     {
153         if (fdTable[desiredFd].type != FD_UNUSED) 
154         {
155             return -1;
156         }
157             index = desiredFd;
158         }
159     else
160     {
161         // See if the entry that matches "fd" is available.
162
163         if (fd <= 0 || fd >= WIN32_OPEN_MAX)
164         {
165             return -1;
166         }
167
168         if (fdTable[fd].type == FD_UNUSED)
169         {
170                 index = fd;
171         }
172         else 
173         {
174             // Find an entry we can use. 
175             // Start at 1 (0 fake id fails in some cases).
176
177             for (index = 1; index < WIN32_OPEN_MAX; index++)
178             {
179                     if (fdTable[index].type == FD_UNUSED)
180                 {
181                     break;
182                 }
183             }
184
185             if (index == WIN32_OPEN_MAX) 
186             {
187                     SetLastError(WSAEMFILE);
188                     return -1;
189             }
190         }
191     }
192
193     fdTable[index].fid.value = fd;
194     fdTable[index].type = type;
195     fdTable[index].path = NULL;
196     fdTable[index].Errno = NO_ERROR;
197     fdTable[index].status = 0;
198     fdTable[index].offset = -1;
199     fdTable[index].offsetHighPtr = fdTable[index].offsetLowPtr = NULL;
200     fdTable[index].hMapMutex = NULL;
201     fdTable[index].ovList = NULL;
202
203     return index;
204 }
205 \f
206 /*
207  *--------------------------------------------------------------
208  *
209  * StdinThread--
210  *
211  *      This thread performs I/O on stadard input.  It is needed
212  *      because you can't guarantee that all applications will
213  *      create standard input with sufficient access to perform
214  *      asynchronous I/O.  Since we don't want to block the app
215  *      reading from stdin we make it look like it's using I/O
216  *      completion ports to perform async I/O.
217  *
218  * Results:
219  *      Data is read from stdin and posted to the io completion
220  *      port.
221  *
222  * Side effects:
223  *      None.
224  *
225  *--------------------------------------------------------------
226  */
227 static void StdinThread(LPDWORD startup){
228
229     int doIo = TRUE;
230     int fd;
231     int bytesRead;
232     POVERLAPPED_REQUEST pOv;
233
234     while(doIo) {
235         /*
236          * Block until a request to read from stdin comes in or a
237          * request to terminate the thread arrives (fd = -1).
238          */
239         if (!GetQueuedCompletionStatus(hStdinCompPort, &bytesRead, &fd,
240             (LPOVERLAPPED *)&pOv, (DWORD)-1) && !pOv) {
241             doIo = 0;
242             break;
243         }
244
245         ASSERT((fd == STDIN_FILENO) || (fd == -1));
246         if(fd == -1) {
247             doIo = 0;
248             break;
249         }
250         ASSERT(pOv->clientData1 != NULL);
251
252         if(ReadFile(stdioHandles[STDIN_FILENO], pOv->clientData1, bytesRead,
253                     &bytesRead, NULL)) {
254             PostQueuedCompletionStatus(hIoCompPort, bytesRead,
255                                        STDIN_FILENO, (LPOVERLAPPED)pOv);
256         } else {
257             doIo = 0;
258             break;
259         }
260     }
261
262     ExitThread(0);
263 }
264
265 static DWORD WINAPI ShutdownRequestThread(LPVOID arg)
266 {
267     HANDLE shutdownEvent = (HANDLE) arg;
268     
269     if (WaitForSingleObject(shutdownEvent, INFINITE) == WAIT_FAILED)
270     {
271         // Assuming it will happen again, all we can do is exit the thread
272         return -1;
273     }
274     else
275     {
276         // "Simple reads and writes to properly-aligned 32-bit variables are atomic"
277         shutdownPending = TRUE;
278         
279         // Before an accept() is entered the shutdownPending flag is checked.
280         // If set, OS_Accept() will return -1.  If not, it waits
281         // on a connection request for one second, checks the flag, & repeats.
282         // Only one process/thread is allowed to do this at time by
283         // wrapping the accept() with mutex.
284         return 0;
285     }
286 }
287
288 /*
289  *--------------------------------------------------------------
290  *
291  * OS_LibInit --
292  *
293  *      Set up the OS library for use.
294  *
295  * Results:
296  *      Returns 0 if success, -1 if not.
297  *
298  * Side effects:
299  *      Sockets initialized, pseudo file descriptors setup, etc.
300  *
301  *--------------------------------------------------------------
302  */
303 int OS_LibInit(int stdioFds[3])
304 {
305     WORD  wVersion;
306     WSADATA wsaData;
307     int err;
308     int fakeFd;
309     DWORD threadId;
310     char *cLenPtr = NULL;
311     char *val = NULL;
312         
313     if(libInitialized)
314         return 0;
315
316     /*
317      * Initialize windows sockets library.
318      */
319     wVersion = MAKEWORD(2,0);
320     err = WSAStartup( wVersion, &wsaData );
321     if (err) {
322         fprintf(stderr, "Error starting Windows Sockets.  Error: %d",
323                 WSAGetLastError());
324         exit(111);
325     }
326
327     /*
328      * Create the I/O completion port to be used for our I/O queue.
329      */
330     if (hIoCompPort == INVALID_HANDLE_VALUE) {
331         hIoCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
332                                               0, 1);
333         if(hIoCompPort == INVALID_HANDLE_VALUE) {
334             printf("<H2>OS_LibInit Failed CreateIoCompletionPort!  ERROR: %d</H2>\r\n\r\n",
335                GetLastError());
336             return -1;
337         }
338     }
339
340     /*
341      * If a shutdown event is in the env, save it (I don't see any to 
342      * remove it from the environment out from under the application).
343      * Spawn a thread to wait on the shutdown request.
344      */
345     val = getenv(SHUTDOWN_EVENT_NAME);
346     if (val != NULL) 
347     {
348         HANDLE shutdownEvent = (HANDLE) atoi(val);
349
350         putenv(SHUTDOWN_EVENT_NAME"=");
351
352         if (! CreateThread(NULL, 0, ShutdownRequestThread, 
353                            shutdownEvent, 0, NULL))
354         {
355             return -1;
356         }
357     }
358
359     /*
360      * If an accept mutex is in the env, save it and remove it.
361      */
362     val = getenv(MUTEX_VARNAME);
363     if (val != NULL) 
364     {
365         acceptMutex = (HANDLE) atoi(val);
366     }
367
368
369     /*
370      * Determine if this library is being used to listen for FastCGI
371      * connections.  This is communicated by STDIN containing a
372      * valid handle to a listener object.  In this case, both the
373      * "stdout" and "stderr" handles will be INVALID (ie. closed) by
374      * the starting process.
375      *
376      * The trick is determining if this is a pipe or a socket...
377      *
378      * XXX: Add the async accept test to determine socket or handle to a
379      *      pipe!!!
380      */
381     if((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
382        (GetStdHandle(STD_ERROR_HANDLE)  == INVALID_HANDLE_VALUE) &&
383        (GetStdHandle(STD_INPUT_HANDLE)  != INVALID_HANDLE_VALUE) ) 
384     {
385         DWORD pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT;
386         HANDLE oldStdIn = GetStdHandle(STD_INPUT_HANDLE);
387
388         // Move the handle to a "low" number
389         if (! DuplicateHandle(GetCurrentProcess(), oldStdIn,
390                               GetCurrentProcess(), &hListen,
391                               0, TRUE, DUPLICATE_SAME_ACCESS))
392         {
393             return -1;
394         }
395
396         if (! SetStdHandle(STD_INPUT_HANDLE, hListen))
397         {
398             return -1;
399         }
400
401         CloseHandle(oldStdIn);
402
403         /*
404          * Set the pipe handle state so that it operates in wait mode.
405          *
406          * NOTE: The listenFd is not mapped to a pseudo file descriptor
407          *       as all work done on it is contained to the OS library.
408          *
409          * XXX: Initial assumption is that SetNamedPipeHandleState will
410          *      fail if this is an IP socket...
411          */
412         if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL)) 
413         {
414             listenType = FD_PIPE_SYNC;
415             listenOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
416         } 
417         else 
418         {
419             listenType = FD_SOCKET_SYNC;
420         }
421     }
422
423     /*
424      * If there are no stdioFds passed in, we're done.
425      */
426     if(stdioFds == NULL) {
427         libInitialized = 1;
428         return 0;
429     }
430
431     /*
432      * Setup standard input asynchronous I/O.  There is actually a separate
433      * thread spawned for this purpose.  The reason for this is that some
434      * web servers use anonymous pipes for the connection between itself
435      * and a CGI application.  Anonymous pipes can't perform asynchronous
436      * I/O or use I/O completion ports.  Therefore in order to present a
437      * consistent I/O dispatch model to an application we emulate I/O
438      * completion port behavior by having the standard input thread posting
439      * messages to the hIoCompPort which look like a complete overlapped
440      * I/O structure.  This keeps the event dispatching simple from the
441      * application perspective.
442      */
443     stdioHandles[STDIN_FILENO] = GetStdHandle(STD_INPUT_HANDLE);
444
445     if(!SetHandleInformation(stdioHandles[STDIN_FILENO],
446                              HANDLE_FLAG_INHERIT, 0)) {
447 /*
448  * XXX: Causes error when run from command line.  Check KB
449         err = GetLastError();
450         DebugBreak();
451         exit(99);
452  */
453     }
454
455     if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
456                                      (int)stdioHandles[STDIN_FILENO],
457                                      STDIN_FILENO)) == -1) {
458         return -1;
459     } else {
460         /*
461          * Set stdin equal to our pseudo FD and create the I/O completion
462          * port to be used for async I/O.
463          */
464         stdioFds[STDIN_FILENO] = fakeFd;
465     }
466
467     /*
468      * Create the I/O completion port to be used for communicating with
469      * the thread doing I/O on standard in.  This port will carry read
470      * and possibly thread termination requests to the StdinThread.
471      */
472     if (hStdinCompPort == INVALID_HANDLE_VALUE) {
473         hStdinCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
474                                               0, 1);
475         if(hStdinCompPort == INVALID_HANDLE_VALUE) {
476             printf("<H2>OS_LibInit Failed CreateIoCompletionPort: STDIN!  ERROR: %d</H2>\r\n\r\n",
477                GetLastError());
478             return -1;
479         }
480     }
481
482     /*
483      * Create the thread that will read stdin if the CONTENT_LENGTH
484      * is non-zero.
485      */
486     if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL &&
487        atoi(cLenPtr) > 0) {
488         hStdinThread = CreateThread(NULL, 8192,
489                                     (LPTHREAD_START_ROUTINE)&StdinThread,
490                                     NULL, 0, &threadId);
491         if (hStdinThread == NULL) {
492             printf("<H2>OS_LibInit Failed to create STDIN thread!  ERROR: %d</H2>\r\n\r\n",
493                    GetLastError());
494             return -1;
495         }
496     }
497
498     /*
499      * STDOUT will be used synchronously.
500      *
501      * XXX: May want to convert this so that it could be used for OVERLAPPED
502      *      I/O later.  If so, model it after the Stdin I/O as stdout is
503      *      also incapable of async I/O on some servers.
504      */
505     stdioHandles[STDOUT_FILENO] = GetStdHandle(STD_OUTPUT_HANDLE);
506     if(!SetHandleInformation(stdioHandles[STDOUT_FILENO],
507                              HANDLE_FLAG_INHERIT, FALSE)) {
508         DebugBreak();
509         exit(99);
510     }
511
512     if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
513                                      (int)stdioHandles[STDOUT_FILENO],
514                                      STDOUT_FILENO)) == -1) {
515         return -1;
516     } else {
517         /*
518          * Set stdout equal to our pseudo FD
519          */
520         stdioFds[STDOUT_FILENO] = fakeFd;
521     }
522
523     stdioHandles[STDERR_FILENO] = GetStdHandle(STD_ERROR_HANDLE);
524     if(!SetHandleInformation(stdioHandles[STDERR_FILENO],
525                              HANDLE_FLAG_INHERIT, FALSE)) {
526         DebugBreak();
527         exit(99);
528     }
529     if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
530                                      (int)stdioHandles[STDERR_FILENO],
531                                      STDERR_FILENO)) == -1) {
532         return -1;
533     } else {
534         /*
535          * Set stderr equal to our pseudo FD
536          */
537         stdioFds[STDERR_FILENO] = fakeFd;
538     }
539
540     return 0;
541 }
542
543 \f
544 /*
545  *--------------------------------------------------------------
546  *
547  * OS_LibShutdown --
548  *
549  *      Shutdown the OS library.
550  *
551  * Results:
552  *      None.
553  *
554  * Side effects:
555  *      Memory freed, handles closed.
556  *
557  *--------------------------------------------------------------
558  */
559 void OS_LibShutdown()
560 {
561
562     if(hIoCompPort != INVALID_HANDLE_VALUE) {
563         CloseHandle(hIoCompPort);
564         hIoCompPort = INVALID_HANDLE_VALUE;
565     }
566
567     if(hStdinCompPort != INVALID_HANDLE_VALUE) {
568         CloseHandle(hStdinCompPort);
569         hStdinCompPort = INVALID_HANDLE_VALUE;
570     }
571
572     /*
573      * Shutdown the socket library.
574      */
575     WSACleanup();
576     return;
577 }
578
579 \f
580 /*
581  *--------------------------------------------------------------
582  *
583  * Win32FreeDescriptor --
584  *
585  *      Free I/O descriptor entry in fdTable.
586  *
587  * Results:
588  *      Frees I/O descriptor entry in fdTable.
589  *
590  * Side effects:
591  *      None.
592  *
593  *--------------------------------------------------------------
594  */
595 static void Win32FreeDescriptor(int fd)
596 {
597     /* Catch it if fd is a bogus value */
598     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
599     ASSERT(fdTable[fd].type != FD_UNUSED);
600
601     switch (fdTable[fd].type) {
602         case FD_FILE_SYNC:
603         case FD_FILE_ASYNC:
604             /* Free file path string */
605             ASSERT(fdTable[fd].path != NULL);
606             free(fdTable[fd].path);
607             fdTable[fd].path = NULL;
608             break;
609         default:
610             /*
611              * Break through to generic fdTable free-descriptor code
612              */
613             break;
614
615     }
616     ASSERT(fdTable[fd].path == NULL);
617     fdTable[fd].type = FD_UNUSED;
618     fdTable[fd].path = NULL;
619     fdTable[fd].Errno = NO_ERROR;
620     fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL;
621     if (fdTable[fd].hMapMutex != NULL) {
622         CloseHandle(fdTable[fd].hMapMutex);
623         fdTable[fd].hMapMutex = NULL;
624     }
625     return;
626 }
627
628 \f
629 /*
630  * OS_CreateLocalIpcFd --
631  *
632  *   This procedure is responsible for creating the listener pipe
633  *   on Windows NT for local process communication.  It will create a
634  *   named pipe and return a file descriptor to it to the caller.
635  *
636  * Results:
637  *      Listener pipe created.  This call returns either a valid
638  *      pseudo file descriptor or -1 on error.
639  *
640  * Side effects:
641  *      Listener pipe and IPC address are stored in the FCGI info
642  *         structure.
643  *      'errno' will set on errors (-1 is returned).
644  *
645  *----------------------------------------------------------------------
646  */
647 int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
648 {
649     int retFd = -1;
650     SECURITY_ATTRIBUTES     sa;
651     HANDLE hListenPipe = INVALID_HANDLE_VALUE;
652     char *localPath;
653     SOCKET listenSock;
654     int bpLen;
655     int servLen;
656     struct  sockaddr_in sockAddr;
657     char    buf[1024];
658     short   port;
659     int     tcp = FALSE;
660     int flag = 1;
661     char    *tp;
662     HANDLE mutex = CreateMutex(NULL, FALSE, NULL);
663
664     if (mutex == NULL)
665     {
666         return -1;
667     }
668
669     if (! SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE))
670     {
671         return -1;
672     }
673
674     // This is a nail for listening to more than one port..
675     // This should really be handled by the caller.
676     _snprintf(buf, 1024, MUTEX_VARNAME "=%d", (int) mutex);
677     buf[1023] = '\0';
678     putenv(strdup(buf));
679
680     // There's nothing to be gained (at the moment) by a shutdown Event    
681
682     strncpy(buf, bindPath, 1024);
683     buf[1023] = '\0';
684
685     if((tp = strchr(buf, ':')) != 0) {
686         *tp++ = 0;
687         if((port = atoi(tp)) == 0) {
688             *--tp = ':';
689          } else {
690             tcp = TRUE;
691          }
692     }
693     
694     if(tcp && (*buf && strcmp(buf, "localhost") != 0)) {
695         fprintf(stderr, "To start a service on a TCP port can not "
696                         "specify a host name.\n"
697                         "You should either use \"localhost:<port>\" or "
698                         " just use \":<port>.\"\n");
699         exit(1);
700     }
701
702     if(tcp) {
703         listenSock = socket(AF_INET, SOCK_STREAM, 0);
704         if(listenSock == SOCKET_ERROR) {
705             return -1;
706         }
707         /*
708          * Bind the listening socket.
709          */
710         memset((char *) &sockAddr, 0, sizeof(sockAddr));
711         sockAddr.sin_family = AF_INET;
712         sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
713         sockAddr.sin_port = htons(port);
714         servLen = sizeof(sockAddr);
715
716         if(bind(listenSock, (struct sockaddr *) &sockAddr, servLen) < 0
717            || listen(listenSock, backlog) < 0) {
718             perror("bind/listen");
719             exit(errno);
720         }
721
722         retFd = Win32NewDescriptor(FD_SOCKET_SYNC, (int)listenSock, -1);
723         return retFd;
724     }
725
726
727     /*
728      * Initialize the SECURITY_ATTRIUBTES structure.
729      */
730     sa.nLength = sizeof(sa);
731     sa.lpSecurityDescriptor = NULL;
732     sa.bInheritHandle = TRUE;       /* This will be inherited by the
733                                      * FastCGI process
734                                      */
735     /*
736      * Create a unique name to be used for the socket bind path.
737      * Make sure that this name is unique and that there's no process
738      * bound to it.
739      *
740      * Named Pipe Pathname: \\.\pipe\FastCGI\OM_WS.pid.N
741      * Where: N is the pipe instance on the machine.
742      *
743      */
744     bpLen = (int)strlen(bindPathPrefix);
745     bpLen += strlen(bindPath);
746     localPath = malloc(bpLen+2);
747     strcpy(localPath, bindPathPrefix);
748     strcat(localPath, bindPath);
749
750     /*
751      * Create and setup the named pipe to be used by the fcgi server.
752      */
753     hListenPipe = CreateNamedPipe(localPath, /* name of pipe */
754                     PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
755                     PIPE_TYPE_BYTE | PIPE_WAIT |
756                     PIPE_READMODE_BYTE,         /* pipe IO type */
757                     PIPE_UNLIMITED_INSTANCES,   /* number of instances */
758                     4096,                       /* size of outbuf (0 == allocate as necessary) */
759                     4096,                               /* size of inbuf */
760                     0, /*1000,*/                /* default time-out value */
761                     &sa);                       /* security attributes */
762     free(localPath);
763     /*
764      * Can't create an instance of the pipe, fail...
765      */
766     if (hListenPipe == INVALID_HANDLE_VALUE) {
767         return -1;
768     }
769
770     retFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)hListenPipe, -1);
771     return retFd;
772 }
773
774 \f
775 /*
776  *----------------------------------------------------------------------
777  *
778  * OS_FcgiConnect --
779  *
780  *      Create the pipe pathname connect to the remote application if
781  *      possible.
782  *
783  * Results:
784  *      -1 if fail or a valid handle if connection succeeds.
785  *
786  * Side effects:
787  *      Remote connection established.
788  *
789  *----------------------------------------------------------------------
790  */
791 int OS_FcgiConnect(char *bindPath)
792 {
793     char *pipePath = NULL;
794     HANDLE hPipe;
795     int pseudoFd, err;
796
797     struct  sockaddr_in sockAddr;
798     int servLen, resultSock;
799     int connectStatus;
800     char    *tp;
801     char    host[1024];
802     short   port;
803     int     tcp = FALSE;
804
805     strncpy(host, bindPath, 1024);
806     host[1023] = '\0';
807
808     if ((tp = strchr(host, ':')) != 0) {
809         *tp++ = 0;
810         if((port = atoi(tp)) == 0) {
811             *--tp = ':';
812          } else {
813             tcp = TRUE;
814          }
815     }
816     
817     if(tcp == TRUE) {
818         struct  hostent *hp;
819         if((hp = gethostbyname((*host ? host : "localhost"))) == NULL) {
820             fprintf(stderr, "Unknown host: %s\n", bindPath);
821             exit(1000);
822         }
823         sockAddr.sin_family = AF_INET;
824         memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length);
825         sockAddr.sin_port = htons(port);
826         servLen = sizeof(sockAddr);
827         resultSock = socket(AF_INET, SOCK_STREAM, 0);
828
829         ASSERT(resultSock >= 0);
830         connectStatus = connect(resultSock, (struct sockaddr *)
831                                 &sockAddr, servLen);
832         if(connectStatus < 0) {
833             /*
834              * Most likely (errno == ENOENT || errno == ECONNREFUSED)
835              * and no FCGI application server is running.
836              */
837             closesocket(resultSock);
838             return -1;
839         }
840         pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, resultSock, -1);
841         if(pseudoFd == -1) {
842             closesocket(resultSock);
843         }
844         return pseudoFd;
845     }
846
847     /*
848      * Not a TCP connection, create and connect to a named pipe.
849      */
850     pipePath = malloc((size_t)(strlen(bindPathPrefix) + strlen(bindPath) + 2));
851     if(pipePath == NULL) {
852         return -1;
853     }
854     strcpy(pipePath, bindPathPrefix);
855     strcat(pipePath, bindPath);
856
857     hPipe = CreateFile (pipePath,
858                         /* Generic access, read/write. */
859                         GENERIC_WRITE | GENERIC_READ,
860                         /* Share both read and write. */
861                         FILE_SHARE_READ | FILE_SHARE_WRITE ,
862                         NULL,                  /* No security.*/
863                         OPEN_EXISTING,         /* Fail if not existing. */
864                         FILE_FLAG_OVERLAPPED,  /* Use overlap. */
865                         NULL);                 /* No template. */
866
867     free(pipePath);
868     if(hPipe == INVALID_HANDLE_VALUE) {
869         return -1;
870     }
871
872     if ((pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int)hPipe, -1)) == -1) {
873         CloseHandle(hPipe);
874         return -1;
875     } else {
876         /*
877          * Set stdin equal to our pseudo FD and create the I/O completion
878          * port to be used for async I/O.
879          */
880         if (!CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1)) {
881             err = GetLastError();
882             Win32FreeDescriptor(pseudoFd);
883             CloseHandle(hPipe);
884             return -1;
885         }
886     }
887     return pseudoFd;
888 }
889
890 \f
891 /*
892  *--------------------------------------------------------------
893  *
894  * OS_Read --
895  *
896  *      Pass through to the appropriate NT read function.
897  *
898  * Results:
899  *      Returns number of byes read. Mimics unix read:.
900  *              n bytes read, 0 or -1 failure: errno contains actual error
901  *
902  * Side effects:
903  *      None.
904  *
905  *--------------------------------------------------------------
906  */
907 int OS_Read(int fd, char * buf, size_t len)
908 {
909     DWORD bytesRead;
910     int ret;
911
912     /*
913      * Catch any bogus fd values
914      */
915     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
916
917     switch (fdTable[fd].type) {
918         case FD_FILE_SYNC:
919         case FD_FILE_ASYNC:
920         case FD_PIPE_SYNC:
921         case FD_PIPE_ASYNC:
922             bytesRead = fd;
923             /*
924              * ReadFile returns: TRUE success, FALSE failure
925              */
926             if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead,
927                 NULL)) {
928                 fdTable[fd].Errno = GetLastError();
929                 return -1;
930             }
931             return bytesRead;
932
933         case FD_SOCKET_SYNC:
934         case FD_SOCKET_ASYNC:
935             /* winsock recv returns n bytes recv'ed, SOCKET_ERROR failure */
936             /*
937              * XXX: Test this with ReadFile.  If it works, remove this code
938              *      to simplify the routine.
939              */
940             if ((ret = recv(fdTable[fd].fid.sock, buf, len, 0)) ==
941                 SOCKET_ERROR) {
942                 fdTable[fd].Errno = WSAGetLastError();
943                 return -1;
944             }
945             return ret;
946         default:
947                 return -1;
948     }
949 }
950 \f
951 /*
952  *--------------------------------------------------------------
953  *
954  * OS_Write --
955  *
956  *      Perform a synchronous OS write.
957  *
958  * Results:
959  *      Returns number of bytes written. Mimics unix write:
960  *              n bytes written, 0 or -1 failure (??? couldn't find man page).
961  *
962  * Side effects:
963  *      none.
964  *
965  *--------------------------------------------------------------
966  */
967 int OS_Write(int fd, char * buf, size_t len)
968 {
969     DWORD bytesWritten;
970     int ret;
971
972     /*
973      * Catch any bogus fd values
974      */
975     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
976     ASSERT((fdTable[fd].type > FD_UNUSED) &&
977            (fdTable[fd].type <= FD_PIPE_ASYNC));
978
979     switch (fdTable[fd].type) {
980         case FD_FILE_SYNC:
981         case FD_FILE_ASYNC:
982         case FD_PIPE_SYNC:
983         case FD_PIPE_ASYNC:
984             bytesWritten = fd;
985             /*
986              * WriteFile returns: TRUE success, FALSE failure
987              */
988             if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len,
989                 &bytesWritten, NULL)) {
990                 fdTable[fd].Errno = GetLastError();
991                 return -1;
992             }
993             return bytesWritten;
994         case FD_SOCKET_SYNC:
995         case FD_SOCKET_ASYNC:
996             /* winsock send returns n bytes written, SOCKET_ERROR failure */
997             /*
998              * XXX: Test this with WriteFile.  If it works, remove this code
999              *      to simplify the routine.
1000              */
1001             if ((ret = send(fdTable[fd].fid.sock, buf, len, 0)) ==
1002                 SOCKET_ERROR) {
1003                 fdTable[fd].Errno = WSAGetLastError();
1004                 return -1;
1005             }
1006             return ret;
1007         default:
1008             return -1;
1009     }
1010 }
1011
1012 \f
1013 /*
1014  *----------------------------------------------------------------------
1015  *
1016  * OS_SpawnChild --
1017  *
1018  *      Spawns a new server listener process, and stores the information
1019  *      relating to the child in the supplied record.  A wait handler is
1020  *      registered on the child's completion.  This involves creating
1021  *        a process on NT and preparing a command line with the required
1022  *        state (currently a -childproc flag and the server socket to use
1023  *        for accepting connections).
1024  *
1025  * Results:
1026  *      0 if success, -1 if error.
1027  *
1028  * Side effects:
1029  *      Child process spawned.
1030  *
1031  *----------------------------------------------------------------------
1032  */
1033 int OS_SpawnChild(char *execPath, int listenFd)
1034 {
1035     STARTUPINFO StartupInfo;
1036     PROCESS_INFORMATION pInfo;
1037     BOOL success;
1038
1039     memset((void *)&StartupInfo, 0, sizeof(STARTUPINFO));
1040     StartupInfo.cb = sizeof (STARTUPINFO);
1041     StartupInfo.lpReserved = NULL;
1042     StartupInfo.lpReserved2 = NULL;
1043     StartupInfo.cbReserved2 = 0;
1044     StartupInfo.lpDesktop = NULL;
1045
1046     /*
1047      * FastCGI on NT will set the listener pipe HANDLE in the stdin of
1048      * the new process.  The fact that there is a stdin and NULL handles
1049      * for stdout and stderr tells the FastCGI process that this is a
1050      * FastCGI process and not a CGI process.
1051      */
1052     StartupInfo.dwFlags = STARTF_USESTDHANDLES;
1053     /*
1054      * XXX: Do I have to dup the handle before spawning the process or is
1055      *      it sufficient to use the handle as it's reference counted
1056      *      by NT anyway?
1057      */
1058     StartupInfo.hStdInput  = fdTable[listenFd].fid.fileHandle;
1059     StartupInfo.hStdOutput = INVALID_HANDLE_VALUE;
1060     StartupInfo.hStdError  = INVALID_HANDLE_VALUE;
1061
1062     /*
1063      * Make the listener socket inheritable.
1064      */
1065     success = SetHandleInformation(StartupInfo.hStdInput, HANDLE_FLAG_INHERIT,
1066                                    TRUE);
1067     if(!success) {
1068         exit(99);
1069     }
1070
1071     /*
1072      * XXX: Might want to apply some specific security attributes to the
1073      *      processes.
1074      */
1075     success = CreateProcess(execPath,   /* LPCSTR address of module name */
1076                         NULL,           /* LPCSTR address of command line */
1077                         NULL,           /* Process security attributes */
1078                         NULL,           /* Thread security attributes */
1079                         TRUE,           /* Inheritable Handes inherited. */
1080                         0,              /* DWORD creation flags  */
1081                         NULL,           /* Use parent environment block */
1082                         NULL,           /* Address of current directory name */
1083                         &StartupInfo,   /* Address of STARTUPINFO  */
1084                         &pInfo);        /* Address of PROCESS_INFORMATION   */
1085     if(success) {
1086         return 0;
1087     } else {
1088         return -1;
1089     }
1090 }
1091
1092 \f
1093 /*
1094  *--------------------------------------------------------------
1095  *
1096  * OS_AsyncReadStdin --
1097  *
1098  *      This initiates an asynchronous read on the standard
1099  *      input handle.  This handle is not guaranteed to be
1100  *      capable of performing asynchronous I/O so we send a
1101  *      message to the StdinThread to do the synchronous read.
1102  *
1103  * Results:
1104  *      -1 if error, 0 otherwise.
1105  *
1106  * Side effects:
1107  *      Asynchronous message is queued to the StdinThread and an
1108  *      overlapped structure is allocated/initialized.
1109  *
1110  *--------------------------------------------------------------
1111  */
1112 int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr,
1113                       ClientData clientData)
1114 {
1115     POVERLAPPED_REQUEST pOv;
1116
1117     ASSERT(fdTable[STDIN_FILENO].type != FD_UNUSED);
1118
1119     pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1120     ASSERT(pOv);
1121     memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1122     pOv->clientData1 = (ClientData)buf;
1123     pOv->instance = fdTable[STDIN_FILENO].instance;
1124     pOv->procPtr = procPtr;
1125     pOv->clientData = clientData;
1126
1127     PostQueuedCompletionStatus(hStdinCompPort, len, STDIN_FILENO,
1128                                (LPOVERLAPPED)pOv);
1129     return 0;
1130 }
1131
1132 \f
1133 /*
1134  *--------------------------------------------------------------
1135  *
1136  * OS_AsyncRead --
1137  *
1138  *      This initiates an asynchronous read on the file
1139  *      handle which may be a socket or named pipe.
1140  *
1141  *      We also must save the ProcPtr and ClientData, so later
1142  *      when the io completes, we know who to call.
1143  *
1144  *      We don't look at any results here (the ReadFile may
1145  *      return data if it is cached) but do all completion
1146  *      processing in OS_Select when we get the io completion
1147  *      port done notifications.  Then we call the callback.
1148  *
1149  * Results:
1150  *      -1 if error, 0 otherwise.
1151  *
1152  * Side effects:
1153  *      Asynchronous I/O operation is queued for completion.
1154  *
1155  *--------------------------------------------------------------
1156  */
1157 int OS_AsyncRead(int fd, int offset, void *buf, int len,
1158                  OS_AsyncProc procPtr, ClientData clientData)
1159 {
1160     DWORD bytesRead;
1161     POVERLAPPED_REQUEST pOv;
1162
1163     /*
1164      * Catch any bogus fd values
1165      */
1166     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1167     /*
1168      * Confirm that this is an async fd
1169      */
1170     ASSERT(fdTable[fd].type != FD_UNUSED);
1171     ASSERT(fdTable[fd].type != FD_FILE_SYNC);
1172     ASSERT(fdTable[fd].type != FD_PIPE_SYNC);
1173     ASSERT(fdTable[fd].type != FD_SOCKET_SYNC);
1174
1175     pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1176     ASSERT(pOv);
1177     memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1178     /*
1179      * Only file offsets should be non-zero, but make sure.
1180      */
1181     if (fdTable[fd].type == FD_FILE_ASYNC)
1182         if (fdTable[fd].offset >= 0)
1183             pOv->overlapped.Offset = fdTable[fd].offset;
1184         else
1185             pOv->overlapped.Offset = offset;
1186     pOv->instance = fdTable[fd].instance;
1187     pOv->procPtr = procPtr;
1188     pOv->clientData = clientData;
1189     bytesRead = fd;
1190     /*
1191      * ReadFile returns: TRUE success, FALSE failure
1192      */
1193     if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead,
1194         (LPOVERLAPPED)pOv)) {
1195         fdTable[fd].Errno = GetLastError();
1196         if(fdTable[fd].Errno == ERROR_NO_DATA ||
1197            fdTable[fd].Errno == ERROR_PIPE_NOT_CONNECTED) {
1198             PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1199             return 0;
1200         }
1201         if(fdTable[fd].Errno != ERROR_IO_PENDING) {
1202             PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1203             return -1;
1204         }
1205         fdTable[fd].Errno = 0;
1206     }
1207     return 0;
1208 }
1209 \f
1210 /*
1211  *--------------------------------------------------------------
1212  *
1213  * OS_AsyncWrite --
1214  *
1215  *      This initiates an asynchronous write on the "fake" file
1216  *      descriptor (which may be a file, socket, or named pipe).
1217  *      We also must save the ProcPtr and ClientData, so later
1218  *      when the io completes, we know who to call.
1219  *
1220  *      We don't look at any results here (the WriteFile generally
1221  *      completes immediately) but do all completion processing
1222  *      in OS_DoIo when we get the io completion port done
1223  *      notifications.  Then we call the callback.
1224  *
1225  * Results:
1226  *      -1 if error, 0 otherwise.
1227  *
1228  * Side effects:
1229  *      Asynchronous I/O operation is queued for completion.
1230  *
1231  *--------------------------------------------------------------
1232  */
1233 int OS_AsyncWrite(int fd, int offset, void *buf, int len,
1234                   OS_AsyncProc procPtr, ClientData clientData)
1235 {
1236     DWORD bytesWritten;
1237     POVERLAPPED_REQUEST pOv;
1238
1239     /*
1240      * Catch any bogus fd values
1241      */
1242     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1243     /*
1244      * Confirm that this is an async fd
1245      */
1246     ASSERT(fdTable[fd].type != FD_UNUSED);
1247     ASSERT(fdTable[fd].type != FD_FILE_SYNC);
1248     ASSERT(fdTable[fd].type != FD_PIPE_SYNC);
1249     ASSERT(fdTable[fd].type != FD_SOCKET_SYNC);
1250
1251     pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1252     ASSERT(pOv);
1253     memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1254     /*
1255      * Only file offsets should be non-zero, but make sure.
1256      */
1257     if (fdTable[fd].type == FD_FILE_ASYNC)
1258         /*
1259          * Only file opened via OS_AsyncWrite with
1260          * O_APPEND will have an offset != -1.
1261          */
1262         if (fdTable[fd].offset >= 0)
1263             /*
1264              * If the descriptor has a memory mapped file
1265              * handle, take the offsets from there.
1266              */
1267             if (fdTable[fd].hMapMutex != NULL) {
1268                 /*
1269                  * Wait infinitely; this *should* not cause problems.
1270                  */
1271                 WaitForSingleObject(fdTable[fd].hMapMutex, INFINITE);
1272
1273                 /*
1274                  * Retrieve the shared offset values.
1275                  */
1276                 pOv->overlapped.OffsetHigh = *(fdTable[fd].offsetHighPtr);
1277                 pOv->overlapped.Offset = *(fdTable[fd].offsetLowPtr);
1278
1279                 /*
1280                  * Update the shared offset values for the next write
1281                  */
1282                 *(fdTable[fd].offsetHighPtr) += 0;      /* XXX How do I handle overflow */
1283                 *(fdTable[fd].offsetLowPtr) += len;
1284
1285                 ReleaseMutex(fdTable[fd].hMapMutex);
1286             } else
1287                 pOv->overlapped.Offset = fdTable[fd].offset;
1288         else
1289             pOv->overlapped.Offset = offset;
1290     pOv->instance = fdTable[fd].instance;
1291     pOv->procPtr = procPtr;
1292     pOv->clientData = clientData;
1293     bytesWritten = fd;
1294     /*
1295      * WriteFile returns: TRUE success, FALSE failure
1296      */
1297     if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten,
1298         (LPOVERLAPPED)pOv)) {
1299         fdTable[fd].Errno = GetLastError();
1300         if(fdTable[fd].Errno != ERROR_IO_PENDING) {
1301             PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1302             return -1;
1303         }
1304         fdTable[fd].Errno = 0;
1305     }
1306     if (fdTable[fd].offset >= 0)
1307         fdTable[fd].offset += len;
1308     return 0;
1309 }
1310
1311 \f
1312 /*
1313  *--------------------------------------------------------------
1314  *
1315  * OS_Close --
1316  *
1317  *      Closes the descriptor with routine appropriate for
1318  *      descriptor's type.
1319  *
1320  * Results:
1321  *      Socket or file is closed. Return values mimic Unix close:
1322  *              0 success, -1 failure
1323  *
1324  * Side effects:
1325  *      Entry in fdTable is marked as free.
1326  *
1327  *--------------------------------------------------------------
1328  */
1329 int OS_Close(int fd)
1330 {
1331     int ret = 0;
1332
1333     /*
1334      * Catch it if fd is a bogus value
1335      */
1336     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1337     ASSERT(fdTable[fd].type != FD_UNUSED);
1338
1339     switch (fdTable[fd].type) {
1340         case FD_PIPE_SYNC:
1341         case FD_PIPE_ASYNC:
1342         case FD_FILE_SYNC:
1343         case FD_FILE_ASYNC:
1344             break;
1345
1346         case FD_SOCKET_SYNC:
1347         case FD_SOCKET_ASYNC:
1348             /*
1349              * Closing a socket that has an async read outstanding causes a
1350              * tcp reset and possible data loss.  The shutdown call seems to
1351              * prevent this.
1352              */
1353             shutdown(fdTable[fd].fid.sock, 2);
1354             /*
1355              * closesocket returns: 0 success, SOCKET_ERROR failure
1356              */
1357             if (closesocket(fdTable[fd].fid.sock) == SOCKET_ERROR)
1358                 ret = -1;
1359             break;
1360         default:
1361             return -1;          /* fake failure */
1362     }
1363
1364     Win32FreeDescriptor(fd);
1365     return ret;
1366 }
1367 \f
1368 /*
1369  *--------------------------------------------------------------
1370  *
1371  * OS_CloseRead --
1372  *
1373  *      Cancel outstanding asynchronous reads and prevent subsequent
1374  *      reads from completing.
1375  *
1376  * Results:
1377  *      Socket or file is shutdown. Return values mimic Unix shutdown:
1378  *              0 success, -1 failure
1379  *
1380  *--------------------------------------------------------------
1381  */
1382 int OS_CloseRead(int fd)
1383 {
1384     int ret = 0;
1385
1386     /*
1387      * Catch it if fd is a bogus value
1388      */
1389     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1390     ASSERT(fdTable[fd].type == FD_SOCKET_ASYNC
1391         || fdTable[fd].type == FD_SOCKET_SYNC);
1392
1393     if (shutdown(fdTable[fd].fid.sock,0) == SOCKET_ERROR)
1394         ret = -1;
1395     return ret;
1396 }
1397 \f
1398 /*
1399  *--------------------------------------------------------------
1400  *
1401  * OS_DoIo --
1402  *
1403  *      This function was formerly OS_Select.  It's purpose is
1404  *      to pull I/O completion events off the queue and dispatch
1405  *      them to the appropriate place.
1406  *
1407  * Results:
1408  *      Returns 0.
1409  *
1410  * Side effects:
1411  *      Handlers are called.
1412  *
1413  *--------------------------------------------------------------
1414  */
1415 int OS_DoIo(struct timeval *tmo)
1416 {
1417     int fd;
1418     int bytes;
1419     POVERLAPPED_REQUEST pOv;
1420     struct timeb tb;
1421     int ms;
1422     int ms_last;
1423     int err;
1424
1425     /* XXX
1426      * We can loop in here, but not too long, as wait handlers
1427      * must run.
1428      * For cgi stdin, apparently select returns when io completion
1429      * ports don't, so don't wait the full timeout.
1430      */
1431     if(tmo)
1432         ms = (tmo->tv_sec*1000 + tmo->tv_usec/1000) / 2;
1433     else
1434         ms = 1000;
1435     ftime(&tb);
1436     ms_last = tb.time*1000 + tb.millitm;
1437     while (ms >= 0) {
1438         if(tmo && (ms = tmo->tv_sec*1000 + tmo->tv_usec/1000)> 100)
1439             ms = 100;
1440         if (!GetQueuedCompletionStatus(hIoCompPort, &bytes, &fd,
1441             (LPOVERLAPPED *)&pOv, ms) && !pOv) {
1442             err = WSAGetLastError();
1443             return 0; /* timeout */
1444         }
1445
1446         ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1447         /* call callback if descriptor still valid */
1448         ASSERT(pOv);
1449         if(pOv->instance == fdTable[fd].instance)
1450           (*pOv->procPtr)(pOv->clientData, bytes);
1451         free(pOv);
1452
1453         ftime(&tb);
1454         ms -= (tb.time*1000 + tb.millitm - ms_last);
1455         ms_last = tb.time*1000 + tb.millitm;
1456     }
1457     return 0;
1458 }
1459
1460
1461 static int CALLBACK isAddrOK(LPWSABUF  lpCallerId,
1462                              LPWSABUF  dc0,
1463                              LPQOS     dc1,
1464                              LPQOS     dc2,
1465                              LPWSABUF  dc3,
1466                              LPWSABUF  dc4,
1467                              GROUP     *dc5,
1468                              DWORD     dwCallbackData)
1469 {
1470     const char *okAddrs = (char *) dwCallbackData;
1471     struct sockaddr *sockaddr = (struct sockaddr *) lpCallerId->buf;
1472
1473     if (okAddrs == NULL || sockaddr->sa_family != AF_INET)
1474     {
1475         return TRUE;
1476     }
1477     else
1478     {
1479         static const char *token = " ,;:\t";
1480         struct sockaddr_in * inet_sockaddr = (struct sockaddr_in *) sockaddr;
1481         char *ipaddr = inet_ntoa(inet_sockaddr->sin_addr);
1482         char *p = strstr(okAddrs, ipaddr);
1483
1484         if (p == NULL)
1485         {
1486             return FALSE;
1487         }
1488         else if (p == okAddrs)
1489         {
1490             p += strlen(ipaddr);
1491             return (strchr(token, *p) != NULL);
1492         }
1493         else if (strchr(token, *--p))
1494         {
1495             p += strlen(ipaddr) + 1;
1496             return (strchr(token, *p) != NULL);
1497         }
1498         else
1499         {
1500             return FALSE;
1501         }
1502     }
1503 }
1504     
1505 \f
1506 /*
1507  *----------------------------------------------------------------------
1508  *
1509  * OS_Accept --
1510  *
1511  *      Accepts a new FastCGI connection.  This routine knows whether
1512  *      we're dealing with TCP based sockets or NT Named Pipes for IPC.
1513  *
1514  * Results:
1515  *      -1 if the operation fails, otherwise this is a valid IPC fd.
1516  *
1517  * Side effects:
1518  *      New IPC connection is accepted.
1519  *
1520  *----------------------------------------------------------------------
1521  */
1522 int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
1523 {
1524     /* XXX This is broken for listen_sock & fail_on_intr */
1525     int ipcFd = -1;
1526     BOOL pConnected;
1527     SOCKET hSock;
1528
1529     if (shutdownPending) 
1530     {
1531         return -1;
1532     }
1533
1534     // The mutex is to keep other processes (and threads, when supported)
1535     // from going into the accept cycle.  The accept cycle needs to
1536     // periodically break out to check the state of the shutdown flag
1537     // and there's no point to having more than one thread do that.
1538     
1539     if (acceptMutex != INVALID_HANDLE_VALUE) 
1540     {
1541         if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED) 
1542         {
1543             return -1;
1544         }
1545     }
1546     
1547     if (shutdownPending) 
1548     {
1549         if (acceptMutex != INVALID_HANDLE_VALUE) 
1550         {
1551             ReleaseMutex(acceptMutex);
1552         }
1553         return -1;
1554     }
1555     
1556     if (listenType == FD_PIPE_SYNC) 
1557     {
1558         pConnected = ConnectNamedPipe(hListen, &listenOverlapped) 
1559             ? TRUE 
1560             : (GetLastError() == ERROR_PIPE_CONNECTED);
1561
1562         if (! pConnected) 
1563         {
1564             while (WaitForSingleObject(listenOverlapped.hEvent, 1000) == WAIT_TIMEOUT) 
1565             {
1566                 if (shutdownPending) 
1567                 {
1568                     if (acceptMutex != INVALID_HANDLE_VALUE) 
1569                     {
1570                         ReleaseMutex(acceptMutex);
1571                     }
1572                     CancelIo(hListen);
1573                     return -1;
1574                 }            
1575             }
1576         }
1577         
1578         if (acceptMutex != INVALID_HANDLE_VALUE) 
1579         {
1580             ReleaseMutex(acceptMutex);
1581         }
1582
1583         ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1);
1584             if (ipcFd == -1) 
1585         {
1586             DisconnectNamedPipe(hListen);
1587         }
1588     }
1589     else if (listenType == FD_SOCKET_SYNC)
1590     {
1591         struct sockaddr sockaddr;
1592         int sockaddrLen = sizeof(sockaddr);
1593         fd_set readfds;
1594         const struct timeval timeout = {1, 0};
1595      
1596         FD_ZERO(&readfds);
1597         FD_SET((unsigned int) hListen, &readfds);
1598         
1599         while (select(0, &readfds, NULL, NULL, &timeout) == 0)
1600         {
1601             if (shutdownPending) 
1602             {
1603                 return -1;
1604             }
1605         }
1606         
1607         hSock = (webServerAddrs == NULL)
1608             ? accept((SOCKET) hListen, 
1609                               &sockaddr, 
1610                               &sockaddrLen)
1611             : WSAAccept((unsigned int) hListen,                    
1612                                        &sockaddr,  
1613                                        &sockaddrLen,               
1614                                        isAddrOK,  
1615                                (DWORD) webServerAddrs);
1616         
1617         if (acceptMutex != INVALID_HANDLE_VALUE) 
1618         {
1619             ReleaseMutex(acceptMutex);
1620         }
1621
1622         if (hSock == -1) 
1623         {
1624             return -1;
1625         }
1626         
1627         ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1);
1628             if (ipcFd == -1) 
1629         {
1630                 closesocket(hSock);
1631             }
1632     }
1633     else
1634     {
1635         ASSERT(0);
1636     }
1637             
1638     return ipcFd;
1639 }
1640 \f
1641 /*
1642  *----------------------------------------------------------------------
1643  *
1644  * OS_IpcClose
1645  *
1646  *      OS IPC routine to close an IPC connection.
1647  *
1648  * Results:
1649  *
1650  *
1651  * Side effects:
1652  *      IPC connection is closed.
1653  *
1654  *----------------------------------------------------------------------
1655  */
1656 int OS_IpcClose(int ipcFd)
1657 {
1658     if (ipcFd == -1)
1659         return 0;
1660
1661     /*
1662      * Catch it if fd is a bogus value
1663      */
1664     ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX));
1665     ASSERT(fdTable[ipcFd].type != FD_UNUSED);
1666
1667     switch(listenType) {
1668
1669     case FD_PIPE_SYNC:
1670         /*
1671          * Make sure that the client (ie. a Web Server in this case) has
1672          * read all data from the pipe before we disconnect.
1673          */
1674         if(!FlushFileBuffers(fdTable[ipcFd].fid.fileHandle))
1675             return -1;
1676         if(DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) {
1677             OS_Close(ipcFd);
1678             return 0;
1679         } else {
1680             return -1;
1681         }
1682         break;
1683
1684     case FD_SOCKET_SYNC:
1685         OS_Close(ipcFd);
1686         return 0;
1687         break;
1688
1689     case FD_UNUSED:
1690     default:
1691         exit(106);
1692         break;
1693     }
1694 }
1695
1696 \f
1697 /*
1698  *----------------------------------------------------------------------
1699  *
1700  * OS_IsFcgi --
1701  *
1702  *      Determines whether this process is a FastCGI process or not.
1703  *
1704  * Results:
1705  *      Returns 1 if FastCGI, 0 if not.
1706  *
1707  * Side effects:
1708  *      None.
1709  *
1710  *----------------------------------------------------------------------
1711  */
1712 int OS_IsFcgi(int sock)
1713 {
1714     /* XXX This is broken for sock */
1715     if(listenType == FD_UNUSED) {
1716         return FALSE;
1717     } else {
1718         return TRUE;
1719     }
1720 }
1721
1722 \f
1723 /*
1724  *----------------------------------------------------------------------
1725  *
1726  * OS_SetFlags --
1727  *
1728  *      Sets selected flag bits in an open file descriptor.  Currently
1729  *      this is only to put a SOCKET into non-blocking mode.
1730  *
1731  *----------------------------------------------------------------------
1732  */
1733 void OS_SetFlags(int fd, int flags)
1734 {
1735     unsigned long pLong = 1L;
1736     int err;
1737
1738     if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) {
1739         if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) ==
1740             SOCKET_ERROR) {
1741             exit(WSAGetLastError());
1742         }
1743         if (!CreateIoCompletionPort((HANDLE)fdTable[fd].fid.sock,
1744                                     hIoCompPort, fd, 1)) {
1745             err = GetLastError();
1746             exit(err);
1747         }
1748
1749         fdTable[fd].type = FD_SOCKET_ASYNC;
1750     }
1751     return;
1752 }
1753