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