[WIN32] Raise SIGTERM from the ShutdownRequestThread to emulate
[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.35 2004/01/31 17:47:07 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 + 1;
826
827             host = malloc(len);
828             strncpy(host, bindPath, len);
829             host[len] = '\0';
830         }
831         
832         hp = gethostbyname(host ? host : LOCALHOST);
833
834         if (host)
835         {
836             free(host);
837         }
838
839             if (hp == NULL) 
840         {
841                 fprintf(stderr, "Unknown host: %s\n", bindPath);
842                 return -1;
843             }
844        
845         memset(&sockAddr, 0, sizeof(sockAddr));
846         sockAddr.sin_family = AF_INET;
847             memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length);
848             sockAddr.sin_port = htons(port);
849
850             sock = socket(AF_INET, SOCK_STREAM, 0);
851         if (sock == INVALID_SOCKET)
852         {
853             return -1;
854         }
855
856             if (! connect(sock, (struct sockaddr *) &sockAddr, sockLen)) 
857         {
858                 closesocket(sock);
859                 return -1;
860             }
861
862             pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, sock, -1);
863             if (pseudoFd == -1) 
864         {
865                 closesocket(sock);
866             return -1;
867             }
868     }
869     else
870     {
871         char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
872         HANDLE hPipe;
873         
874         if (! pipePath) 
875         {
876             return -1;
877         }
878
879         strcpy(pipePath, bindPathPrefix);
880         strcat(pipePath, bindPath);
881
882         hPipe = CreateFile(pipePath,
883                             GENERIC_WRITE | GENERIC_READ,
884                             FILE_SHARE_READ | FILE_SHARE_WRITE,
885                             NULL,
886                             OPEN_EXISTING,
887                             FILE_FLAG_OVERLAPPED,
888                             NULL);
889
890         free(pipePath);
891
892         if( hPipe == INVALID_HANDLE_VALUE) 
893         {
894             return -1;
895         }
896
897         pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int) hPipe, -1);
898         
899         if (pseudoFd == -1) 
900         {
901             CloseHandle(hPipe);
902             return -1;
903         } 
904         
905         /*
906              * Set stdin equal to our pseudo FD and create the I/O completion
907              * port to be used for async I/O.
908              */
909         if (! CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1))
910         {
911                 Win32FreeDescriptor(pseudoFd);
912                 CloseHandle(hPipe);
913                 return -1;
914             }
915     }
916
917     return pseudoFd;    
918 }
919
920 /*
921  *--------------------------------------------------------------
922  *
923  * OS_Read --
924  *
925  *      Pass through to the appropriate NT read function.
926  *
927  * Results:
928  *      Returns number of byes read. Mimics unix read:.
929  *              n bytes read, 0 or -1 failure: errno contains actual error
930  *
931  * Side effects:
932  *      None.
933  *
934  *--------------------------------------------------------------
935  */
936 int OS_Read(int fd, char * buf, size_t len)
937 {
938     DWORD bytesRead;
939     int ret = -1;
940
941     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
942
943     if (shutdownNow) return -1;
944
945     switch (fdTable[fd].type) 
946     {
947         case FD_FILE_SYNC:
948         case FD_FILE_ASYNC:
949         case FD_PIPE_SYNC:
950         case FD_PIPE_ASYNC:
951
952             if (ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, NULL)) 
953         {
954             ret = bytesRead;
955         }
956         else
957         {
958                     fdTable[fd].Errno = GetLastError();
959             }
960
961         break;
962
963         case FD_SOCKET_SYNC:
964         case FD_SOCKET_ASYNC:
965
966         ret = recv(fdTable[fd].fid.sock, buf, len, 0);
967             if (ret == SOCKET_ERROR) 
968         {
969                     fdTable[fd].Errno = WSAGetLastError();
970                     ret = -1;
971             }
972
973         break;
974         
975     default:
976
977         ASSERT(0);
978     }
979
980     return ret;
981 }
982
983 /*
984  *--------------------------------------------------------------
985  *
986  * OS_Write --
987  *
988  *      Perform a synchronous OS write.
989  *
990  * Results:
991  *      Returns number of bytes written. Mimics unix write:
992  *              n bytes written, 0 or -1 failure (??? couldn't find man page).
993  *
994  * Side effects:
995  *      none.
996  *
997  *--------------------------------------------------------------
998  */
999 int OS_Write(int fd, char * buf, size_t len)
1000 {
1001     DWORD bytesWritten;
1002     int ret = -1;
1003
1004     ASSERT(fd >= 0 && fd < WIN32_OPEN_MAX);
1005
1006     if (shutdownNow) return -1;
1007
1008     switch (fdTable[fd].type) 
1009     {
1010         case FD_FILE_SYNC:
1011         case FD_FILE_ASYNC:
1012         case FD_PIPE_SYNC:
1013         case FD_PIPE_ASYNC:
1014
1015         if (WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten, NULL)) 
1016         {
1017             ret = bytesWritten;
1018         }
1019         else
1020         {
1021                     fdTable[fd].Errno = GetLastError();
1022             }
1023
1024         break;
1025
1026         case FD_SOCKET_SYNC:
1027         case FD_SOCKET_ASYNC:
1028
1029         ret = send(fdTable[fd].fid.sock, buf, len, 0);
1030         if (ret == SOCKET_ERROR) 
1031         {
1032                     fdTable[fd].Errno = WSAGetLastError();
1033                     ret = -1;
1034             }
1035
1036         break;
1037
1038     default:
1039
1040         ASSERT(0);
1041     }
1042
1043     return ret;
1044 }
1045
1046 /*
1047  *----------------------------------------------------------------------
1048  *
1049  * OS_SpawnChild --
1050  *
1051  *      Spawns a new server listener process, and stores the information
1052  *      relating to the child in the supplied record.  A wait handler is
1053  *      registered on the child's completion.  This involves creating
1054  *        a process on NT and preparing a command line with the required
1055  *        state (currently a -childproc flag and the server socket to use
1056  *        for accepting connections).
1057  *
1058  * Results:
1059  *      0 if success, -1 if error.
1060  *
1061  * Side effects:
1062  *      Child process spawned.
1063  *
1064  *----------------------------------------------------------------------
1065  */
1066 int OS_SpawnChild(char *execPath, int listenFd)
1067 {
1068     STARTUPINFO StartupInfo;
1069     PROCESS_INFORMATION pInfo;
1070     BOOL success;
1071
1072     memset((void *)&StartupInfo, 0, sizeof(STARTUPINFO));
1073     StartupInfo.cb = sizeof (STARTUPINFO);
1074     StartupInfo.lpReserved = NULL;
1075     StartupInfo.lpReserved2 = NULL;
1076     StartupInfo.cbReserved2 = 0;
1077     StartupInfo.lpDesktop = NULL;
1078
1079     /*
1080      * FastCGI on NT will set the listener pipe HANDLE in the stdin of
1081      * the new process.  The fact that there is a stdin and NULL handles
1082      * for stdout and stderr tells the FastCGI process that this is a
1083      * FastCGI process and not a CGI process.
1084      */
1085     StartupInfo.dwFlags = STARTF_USESTDHANDLES;
1086     /*
1087      * XXX: Do I have to dup the handle before spawning the process or is
1088      *      it sufficient to use the handle as it's reference counted
1089      *      by NT anyway?
1090      */
1091     StartupInfo.hStdInput  = fdTable[listenFd].fid.fileHandle;
1092     StartupInfo.hStdOutput = INVALID_HANDLE_VALUE;
1093     StartupInfo.hStdError  = INVALID_HANDLE_VALUE;
1094
1095     /*
1096      * Make the listener socket inheritable.
1097      */
1098     success = SetHandleInformation(StartupInfo.hStdInput, HANDLE_FLAG_INHERIT,
1099                                    TRUE);
1100     if(!success) {
1101         exit(99);
1102     }
1103
1104     /*
1105      * XXX: Might want to apply some specific security attributes to the
1106      *      processes.
1107      */
1108     success = CreateProcess(execPath,   /* LPCSTR address of module name */
1109                         NULL,           /* LPCSTR address of command line */
1110                         NULL,           /* Process security attributes */
1111                         NULL,           /* Thread security attributes */
1112                         TRUE,           /* Inheritable Handes inherited. */
1113                         0,              /* DWORD creation flags  */
1114                         NULL,           /* Use parent environment block */
1115                         NULL,           /* Address of current directory name */
1116                         &StartupInfo,   /* Address of STARTUPINFO  */
1117                         &pInfo);        /* Address of PROCESS_INFORMATION   */
1118     if(success) {
1119         return 0;
1120     } else {
1121         return -1;
1122     }
1123 }
1124
1125 /*
1126  *--------------------------------------------------------------
1127  *
1128  * OS_AsyncReadStdin --
1129  *
1130  *      This initiates an asynchronous read on the standard
1131  *      input handle.  This handle is not guaranteed to be
1132  *      capable of performing asynchronous I/O so we send a
1133  *      message to the StdinThread to do the synchronous read.
1134  *
1135  * Results:
1136  *      -1 if error, 0 otherwise.
1137  *
1138  * Side effects:
1139  *      Asynchronous message is queued to the StdinThread and an
1140  *      overlapped structure is allocated/initialized.
1141  *
1142  *--------------------------------------------------------------
1143  */
1144 int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr,
1145                       ClientData clientData)
1146 {
1147     POVERLAPPED_REQUEST pOv;
1148
1149     ASSERT(fdTable[STDIN_FILENO].type != FD_UNUSED);
1150
1151     pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1152     ASSERT(pOv);
1153     memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1154     pOv->clientData1 = (ClientData)buf;
1155     pOv->instance = fdTable[STDIN_FILENO].instance;
1156     pOv->procPtr = procPtr;
1157     pOv->clientData = clientData;
1158
1159     PostQueuedCompletionStatus(hStdinCompPort, len, STDIN_FILENO,
1160                                (LPOVERLAPPED)pOv);
1161     return 0;
1162 }
1163
1164 /*
1165  *--------------------------------------------------------------
1166  *
1167  * OS_AsyncRead --
1168  *
1169  *      This initiates an asynchronous read on the file
1170  *      handle which may be a socket or named pipe.
1171  *
1172  *      We also must save the ProcPtr and ClientData, so later
1173  *      when the io completes, we know who to call.
1174  *
1175  *      We don't look at any results here (the ReadFile may
1176  *      return data if it is cached) but do all completion
1177  *      processing in OS_Select when we get the io completion
1178  *      port done notifications.  Then we call the callback.
1179  *
1180  * Results:
1181  *      -1 if error, 0 otherwise.
1182  *
1183  * Side effects:
1184  *      Asynchronous I/O operation is queued for completion.
1185  *
1186  *--------------------------------------------------------------
1187  */
1188 int OS_AsyncRead(int fd, int offset, void *buf, int len,
1189                  OS_AsyncProc procPtr, ClientData clientData)
1190 {
1191     DWORD bytesRead;
1192     POVERLAPPED_REQUEST pOv;
1193
1194     /*
1195      * Catch any bogus fd values
1196      */
1197     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1198     /*
1199      * Confirm that this is an async fd
1200      */
1201     ASSERT(fdTable[fd].type != FD_UNUSED);
1202     ASSERT(fdTable[fd].type != FD_FILE_SYNC);
1203     ASSERT(fdTable[fd].type != FD_PIPE_SYNC);
1204     ASSERT(fdTable[fd].type != FD_SOCKET_SYNC);
1205
1206     pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1207     ASSERT(pOv);
1208     memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1209     /*
1210      * Only file offsets should be non-zero, but make sure.
1211      */
1212     if (fdTable[fd].type == FD_FILE_ASYNC)
1213         if (fdTable[fd].offset >= 0)
1214             pOv->overlapped.Offset = fdTable[fd].offset;
1215         else
1216             pOv->overlapped.Offset = offset;
1217     pOv->instance = fdTable[fd].instance;
1218     pOv->procPtr = procPtr;
1219     pOv->clientData = clientData;
1220     bytesRead = fd;
1221     /*
1222      * ReadFile returns: TRUE success, FALSE failure
1223      */
1224     if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead,
1225         (LPOVERLAPPED)pOv)) {
1226         fdTable[fd].Errno = GetLastError();
1227         if(fdTable[fd].Errno == ERROR_NO_DATA ||
1228            fdTable[fd].Errno == ERROR_PIPE_NOT_CONNECTED) {
1229             PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1230             return 0;
1231         }
1232         if(fdTable[fd].Errno != ERROR_IO_PENDING) {
1233             PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1234             return -1;
1235         }
1236         fdTable[fd].Errno = 0;
1237     }
1238     return 0;
1239 }
1240
1241 /*
1242  *--------------------------------------------------------------
1243  *
1244  * OS_AsyncWrite --
1245  *
1246  *      This initiates an asynchronous write on the "fake" file
1247  *      descriptor (which may be a file, socket, or named pipe).
1248  *      We also must save the ProcPtr and ClientData, so later
1249  *      when the io completes, we know who to call.
1250  *
1251  *      We don't look at any results here (the WriteFile generally
1252  *      completes immediately) but do all completion processing
1253  *      in OS_DoIo when we get the io completion port done
1254  *      notifications.  Then we call the callback.
1255  *
1256  * Results:
1257  *      -1 if error, 0 otherwise.
1258  *
1259  * Side effects:
1260  *      Asynchronous I/O operation is queued for completion.
1261  *
1262  *--------------------------------------------------------------
1263  */
1264 int OS_AsyncWrite(int fd, int offset, void *buf, int len,
1265                   OS_AsyncProc procPtr, ClientData clientData)
1266 {
1267     DWORD bytesWritten;
1268     POVERLAPPED_REQUEST pOv;
1269
1270     /*
1271      * Catch any bogus fd values
1272      */
1273     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1274     /*
1275      * Confirm that this is an async fd
1276      */
1277     ASSERT(fdTable[fd].type != FD_UNUSED);
1278     ASSERT(fdTable[fd].type != FD_FILE_SYNC);
1279     ASSERT(fdTable[fd].type != FD_PIPE_SYNC);
1280     ASSERT(fdTable[fd].type != FD_SOCKET_SYNC);
1281
1282     pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1283     ASSERT(pOv);
1284     memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1285     /*
1286      * Only file offsets should be non-zero, but make sure.
1287      */
1288     if (fdTable[fd].type == FD_FILE_ASYNC)
1289         /*
1290          * Only file opened via OS_AsyncWrite with
1291          * O_APPEND will have an offset != -1.
1292          */
1293         if (fdTable[fd].offset >= 0)
1294             /*
1295              * If the descriptor has a memory mapped file
1296              * handle, take the offsets from there.
1297              */
1298             if (fdTable[fd].hMapMutex != NULL) {
1299                 /*
1300                  * Wait infinitely; this *should* not cause problems.
1301                  */
1302                 WaitForSingleObject(fdTable[fd].hMapMutex, INFINITE);
1303
1304                 /*
1305                  * Retrieve the shared offset values.
1306                  */
1307                 pOv->overlapped.OffsetHigh = *(fdTable[fd].offsetHighPtr);
1308                 pOv->overlapped.Offset = *(fdTable[fd].offsetLowPtr);
1309
1310                 /*
1311                  * Update the shared offset values for the next write
1312                  */
1313                 *(fdTable[fd].offsetHighPtr) += 0;      /* XXX How do I handle overflow */
1314                 *(fdTable[fd].offsetLowPtr) += len;
1315
1316                 ReleaseMutex(fdTable[fd].hMapMutex);
1317             } else
1318                 pOv->overlapped.Offset = fdTable[fd].offset;
1319         else
1320             pOv->overlapped.Offset = offset;
1321     pOv->instance = fdTable[fd].instance;
1322     pOv->procPtr = procPtr;
1323     pOv->clientData = clientData;
1324     bytesWritten = fd;
1325     /*
1326      * WriteFile returns: TRUE success, FALSE failure
1327      */
1328     if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten,
1329         (LPOVERLAPPED)pOv)) {
1330         fdTable[fd].Errno = GetLastError();
1331         if(fdTable[fd].Errno != ERROR_IO_PENDING) {
1332             PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1333             return -1;
1334         }
1335         fdTable[fd].Errno = 0;
1336     }
1337     if (fdTable[fd].offset >= 0)
1338         fdTable[fd].offset += len;
1339     return 0;
1340 }
1341
1342 /*
1343  *--------------------------------------------------------------
1344  *
1345  * OS_Close --
1346  *
1347  *      Closes the descriptor with routine appropriate for
1348  *      descriptor's type.
1349  *
1350  * Results:
1351  *      Socket or file is closed. Return values mimic Unix close:
1352  *              0 success, -1 failure
1353  *
1354  * Side effects:
1355  *      Entry in fdTable is marked as free.
1356  *
1357  *--------------------------------------------------------------
1358  */
1359 int OS_Close(int fd, int shutdown_ok)
1360 {
1361     int ret = 0;
1362
1363     /*
1364      * Catch it if fd is a bogus value
1365      */
1366     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1367     ASSERT(fdTable[fd].type != FD_UNUSED);
1368
1369     switch (fdTable[fd].type) {
1370         case FD_PIPE_SYNC:
1371         case FD_PIPE_ASYNC:
1372         case FD_FILE_SYNC:
1373         case FD_FILE_ASYNC:
1374             
1375         break;
1376
1377     case FD_SOCKET_SYNC:
1378         case FD_SOCKET_ASYNC:
1379
1380         /*
1381          * shutdown() the send side and then read() from client until EOF
1382          * or a timeout expires.  This is done to minimize the potential
1383          * that a TCP RST will be sent by our TCP stack in response to 
1384          * receipt of additional data from the client.  The RST would
1385          * cause the client to discard potentially useful response data.
1386          */
1387
1388         if (shutdown_ok)
1389         {
1390             if (shutdown(fdTable[fd].fid.sock, SD_SEND) == 0)
1391             {
1392                 struct timeval tv;
1393                 fd_set rfds;
1394                 int sock = fdTable[fd].fid.sock;
1395                 int rv;
1396                 char trash[1024];
1397    
1398                 FD_ZERO(&rfds);
1399
1400                 do 
1401                 {
1402 #pragma warning( disable : 4127 ) 
1403                     FD_SET((unsigned) sock, &rfds);
1404 #pragma warning( default : 4127 )
1405                     
1406                     tv.tv_sec = 2;
1407                     tv.tv_usec = 0;
1408                     rv = select(sock + 1, &rfds, NULL, NULL, &tv);
1409                 }
1410                 while (rv > 0 && recv(sock, trash, sizeof(trash), 0) > 0);
1411             }
1412         }
1413         
1414         closesocket(fdTable[fd].fid.sock);
1415
1416         break;
1417
1418         default:
1419
1420             ret = -1;           /* fake failure */
1421     }
1422
1423     Win32FreeDescriptor(fd);
1424     return ret;
1425 }
1426
1427 /*
1428  *--------------------------------------------------------------
1429  *
1430  * OS_CloseRead --
1431  *
1432  *      Cancel outstanding asynchronous reads and prevent subsequent
1433  *      reads from completing.
1434  *
1435  * Results:
1436  *      Socket or file is shutdown. Return values mimic Unix shutdown:
1437  *              0 success, -1 failure
1438  *
1439  *--------------------------------------------------------------
1440  */
1441 int OS_CloseRead(int fd)
1442 {
1443     int ret = 0;
1444
1445     /*
1446      * Catch it if fd is a bogus value
1447      */
1448     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1449     ASSERT(fdTable[fd].type == FD_SOCKET_ASYNC
1450         || fdTable[fd].type == FD_SOCKET_SYNC);
1451
1452     if (shutdown(fdTable[fd].fid.sock,0) == SOCKET_ERROR)
1453         ret = -1;
1454     return ret;
1455 }
1456
1457 /*
1458  *--------------------------------------------------------------
1459  *
1460  * OS_DoIo --
1461  *
1462  *      This function was formerly OS_Select.  It's purpose is
1463  *      to pull I/O completion events off the queue and dispatch
1464  *      them to the appropriate place.
1465  *
1466  * Results:
1467  *      Returns 0.
1468  *
1469  * Side effects:
1470  *      Handlers are called.
1471  *
1472  *--------------------------------------------------------------
1473  */
1474 int OS_DoIo(struct timeval *tmo)
1475 {
1476     unsigned long fd;
1477     unsigned long bytes;
1478     POVERLAPPED_REQUEST pOv;
1479     struct timeb tb;
1480     int ms;
1481     int ms_last;
1482     int err;
1483
1484     /* XXX
1485      * We can loop in here, but not too long, as wait handlers
1486      * must run.
1487      * For cgi stdin, apparently select returns when io completion
1488      * ports don't, so don't wait the full timeout.
1489      */
1490     if(tmo)
1491         ms = (tmo->tv_sec*1000 + tmo->tv_usec/1000) / 2;
1492     else
1493         ms = 1000;
1494     ftime(&tb);
1495     ms_last = tb.time*1000 + tb.millitm;
1496     while (ms >= 0) {
1497         if(tmo && (ms = tmo->tv_sec*1000 + tmo->tv_usec/1000)> 100)
1498             ms = 100;
1499         if (!GetQueuedCompletionStatus(hIoCompPort, &bytes, &fd,
1500             (LPOVERLAPPED *)&pOv, ms) && !pOv) {
1501             err = WSAGetLastError();
1502             return 0; /* timeout */
1503         }
1504
1505         ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1506         /* call callback if descriptor still valid */
1507         ASSERT(pOv);
1508         if(pOv->instance == fdTable[fd].instance)
1509           (*pOv->procPtr)(pOv->clientData, bytes);
1510         free(pOv);
1511
1512         ftime(&tb);
1513         ms -= (tb.time*1000 + tb.millitm - ms_last);
1514         ms_last = tb.time*1000 + tb.millitm;
1515     }
1516     return 0;
1517 }
1518
1519 static int isAddrOK(struct sockaddr_in * inet_sockaddr, const char * okAddrs)
1520 {
1521     static const char *token = " ,;:\t";
1522     char *ipaddr;
1523     char *p;
1524
1525     if (okAddrs == NULL) return TRUE;
1526
1527     ipaddr = inet_ntoa(inet_sockaddr->sin_addr);
1528     p = strstr(okAddrs, ipaddr);
1529
1530     if (p == NULL) return FALSE;
1531
1532     if (p == okAddrs)
1533     {
1534         p += strlen(ipaddr);
1535         return (strchr(token, *p) != NULL);
1536     }
1537
1538     if (strchr(token, *--p) != NULL)
1539     {
1540         p += strlen(ipaddr) + 1;
1541         return (strchr(token, *p) != NULL);
1542     }
1543
1544     return FALSE;
1545 }
1546
1547 #ifndef NO_WSAACEPT
1548 static int CALLBACK isAddrOKCallback(LPWSABUF  lpCallerId,
1549                                      LPWSABUF  dc0,
1550                                      LPQOS     dc1,
1551                                      LPQOS     dc2,
1552                                      LPWSABUF  dc3,
1553                                      LPWSABUF  dc4,
1554                                      GROUP     *dc5,
1555                                      DWORD     data)
1556 {
1557     struct sockaddr_in *sockaddr = (struct sockaddr_in *) lpCallerId->buf;
1558
1559     // Touch the args to avoid warnings
1560     dc0 = NULL; dc1 = NULL; dc2 = NULL; dc3 = NULL; dc4 = NULL; dc5 = NULL;
1561
1562     if ((void *) data == NULL) return CF_ACCEPT;
1563
1564     if (sockaddr->sin_family != AF_INET) return CF_ACCEPT;
1565
1566     return isAddrOK(sockaddr, (const char *) data) ? CF_ACCEPT : CF_REJECT;
1567 }
1568 #endif
1569
1570 static void printLastError(const char * text)
1571 {
1572     LPVOID buf;
1573
1574     FormatMessage( 
1575         FORMAT_MESSAGE_ALLOCATE_BUFFER | 
1576         FORMAT_MESSAGE_FROM_SYSTEM | 
1577         FORMAT_MESSAGE_IGNORE_INSERTS,
1578         NULL,
1579         GetLastError(),
1580         0,
1581         (LPTSTR) &buf,
1582         0,
1583         NULL 
1584     );
1585     
1586     fprintf(stderr, "%s: %s\n", text, (LPCTSTR) buf);
1587     LocalFree(buf);
1588 }
1589
1590 static int acceptNamedPipe()
1591 {
1592     int ipcFd = -1;
1593
1594     if (! ConnectNamedPipe(hListen, NULL))
1595     {
1596         switch (GetLastError())
1597         {
1598             case ERROR_PIPE_CONNECTED:
1599
1600                 // A client connected after CreateNamedPipe but
1601                 // before ConnectNamedPipe. Its a good connection.
1602
1603                 break;
1604         
1605             case ERROR_IO_PENDING:
1606
1607                 // The NamedPipe was opened with an Overlapped structure
1608                 // and there is a pending io operation.  mod_fastcgi 
1609                 // did this in 2.2.12 (fcgi_pm.c v1.52).
1610
1611             case ERROR_PIPE_LISTENING:
1612
1613                 // The pipe handle is in nonblocking mode.
1614
1615             case ERROR_NO_DATA:
1616
1617                 // The previous client closed its handle (and we failed
1618                 // to call DisconnectNamedPipe)
1619
1620             default:
1621
1622                 printLastError("unexpected ConnectNamedPipe() error");
1623         }
1624     }
1625
1626     ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1);
1627         if (ipcFd == -1) 
1628     {
1629         DisconnectNamedPipe(hListen);
1630     }
1631
1632     return ipcFd;
1633 }
1634
1635 static int acceptSocket(const char *webServerAddrs)
1636 {
1637     SOCKET hSock;
1638     int ipcFd = -1;
1639
1640     for (;;)
1641     {
1642         struct sockaddr sockaddr;
1643         int sockaddrLen = sizeof(sockaddr);
1644
1645         for (;;)
1646         {
1647             const struct timeval timeout = {1, 0};
1648             fd_set readfds;
1649
1650             FD_ZERO(&readfds);
1651
1652 #pragma warning( disable : 4127 ) 
1653             FD_SET((unsigned int) hListen, &readfds);
1654 #pragma warning( default : 4127 ) 
1655
1656             if (select(0, &readfds, NULL, NULL, &timeout) == 0)
1657             {
1658                 if (shutdownPending) 
1659                 {
1660                     OS_LibShutdown();
1661                     return -1;
1662                 }
1663             }
1664             else 
1665             {
1666                 break;
1667             }
1668         }
1669     
1670 #if NO_WSAACEPT
1671         hSock = accept((SOCKET) hListen, &sockaddr, &sockaddrLen);
1672
1673         if (hSock == INVALID_SOCKET)
1674         {
1675             break;
1676         }
1677
1678         if (isAddrOK((struct sockaddr_in *) &sockaddr, webServerAddrs))
1679         {
1680             break;
1681         }
1682
1683         closesocket(hSock);
1684 #else
1685         hSock = WSAAccept((unsigned int) hListen,                    
1686                           &sockaddr,  
1687                           &sockaddrLen,               
1688                           isAddrOKCallback,  
1689                           (DWORD) webServerAddrs);
1690
1691         if (hSock != INVALID_SOCKET)
1692         {
1693             break;
1694         }
1695         
1696         if (WSAGetLastError() != WSAECONNREFUSED)
1697         {
1698             break;
1699         }
1700 #endif
1701     }
1702
1703     if (hSock == INVALID_SOCKET) 
1704     {
1705         /* Use FormatMessage() */
1706         fprintf(stderr, "accept()/WSAAccept() failed: %d", WSAGetLastError());
1707         return -1;
1708     }
1709     
1710     ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1);
1711         if (ipcFd == -1) 
1712     {
1713             closesocket(hSock);
1714         }
1715
1716     return ipcFd;
1717 }
1718
1719 /*
1720  *----------------------------------------------------------------------
1721  *
1722  * OS_Accept --
1723  *
1724  *  Accepts a new FastCGI connection.  This routine knows whether
1725  *  we're dealing with TCP based sockets or NT Named Pipes for IPC.
1726  *
1727  *  fail_on_intr is ignored in the Win lib.
1728  *
1729  * Results:
1730  *      -1 if the operation fails, otherwise this is a valid IPC fd.
1731  *
1732  *----------------------------------------------------------------------
1733  */
1734 int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
1735 {
1736     int ipcFd = -1;
1737
1738     // Touch args to prevent warnings
1739     listen_sock = 0; fail_on_intr = 0;
1740
1741     // @todo Muliple listen sockets and sockets other than 0 are not
1742     // supported due to the use of globals.
1743
1744     if (shutdownPending) 
1745     {
1746         OS_LibShutdown();
1747         return -1;
1748     }
1749
1750     // The mutex is to keep other processes (and threads, when supported)
1751     // from going into the accept cycle.  The accept cycle needs to
1752     // periodically break out to check the state of the shutdown flag
1753     // and there's no point to having more than one thread do that.
1754     
1755     if (acceptMutex != INVALID_HANDLE_VALUE) 
1756     {
1757         if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED) 
1758         {
1759             printLastError("WaitForSingleObject() failed");
1760             return -1;
1761         }
1762     }
1763     
1764     if (shutdownPending) 
1765     {
1766         OS_LibShutdown();
1767     }
1768     else if (listenType == FD_PIPE_SYNC) 
1769     {
1770         ipcFd = acceptNamedPipe();
1771     }
1772     else if (listenType == FD_SOCKET_SYNC)
1773     {
1774         ipcFd = acceptSocket(webServerAddrs);
1775     }
1776     else
1777     {
1778         fprintf(stderr, "unknown listenType (%d)\n", listenType);
1779     }
1780             
1781     if (acceptMutex != INVALID_HANDLE_VALUE) 
1782     {
1783         ReleaseMutex(acceptMutex);
1784     }
1785
1786     return ipcFd;
1787 }
1788
1789 /*
1790  *----------------------------------------------------------------------
1791  *
1792  * OS_IpcClose
1793  *
1794  *      OS IPC routine to close an IPC connection.
1795  *
1796  * Results:
1797  *
1798  *
1799  * Side effects:
1800  *      IPC connection is closed.
1801  *
1802  *----------------------------------------------------------------------
1803  */
1804 int OS_IpcClose(int ipcFd, int shutdown)
1805 {
1806     if (ipcFd == -1) return 0;
1807
1808     /*
1809      * Catch it if fd is a bogus value
1810      */
1811     ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX));
1812     ASSERT(fdTable[ipcFd].type != FD_UNUSED);
1813
1814     switch (listenType) 
1815     {
1816     case FD_PIPE_SYNC:
1817             /*
1818              * Make sure that the client (ie. a Web Server in this case) has
1819              * read all data from the pipe before we disconnect.
1820              */
1821             if (! FlushFileBuffers(fdTable[ipcFd].fid.fileHandle)) return -1;
1822
1823             if (! DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) return -1;
1824
1825         /* fall through */
1826
1827     case FD_SOCKET_SYNC:
1828
1829             OS_Close(ipcFd, shutdown);
1830             break;
1831
1832     case FD_UNUSED:
1833     default:
1834
1835             exit(106);
1836             break;
1837     }
1838
1839     return 0; 
1840 }
1841
1842 /*
1843  *----------------------------------------------------------------------
1844  *
1845  * OS_IsFcgi --
1846  *
1847  *      Determines whether this process is a FastCGI process or not.
1848  *
1849  * Results:
1850  *      Returns 1 if FastCGI, 0 if not.
1851  *
1852  * Side effects:
1853  *      None.
1854  *
1855  *----------------------------------------------------------------------
1856  */
1857 int OS_IsFcgi(int sock)
1858 {
1859     // Touch args to prevent warnings
1860     sock = 0;
1861
1862     /* XXX This is broken for sock */
1863
1864         return (listenType != FD_UNUSED); 
1865 }
1866
1867 /*
1868  *----------------------------------------------------------------------
1869  *
1870  * OS_SetFlags --
1871  *
1872  *      Sets selected flag bits in an open file descriptor.  Currently
1873  *      this is only to put a SOCKET into non-blocking mode.
1874  *
1875  *----------------------------------------------------------------------
1876  */
1877 void OS_SetFlags(int fd, int flags)
1878 {
1879     unsigned long pLong = 1L;
1880     int err;
1881
1882     if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) {
1883         if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) ==
1884             SOCKET_ERROR) {
1885             exit(WSAGetLastError());
1886         }
1887         if (!CreateIoCompletionPort((HANDLE)fdTable[fd].fid.sock,
1888                                     hIoCompPort, fd, 1)) {
1889             err = GetLastError();
1890             exit(err);
1891         }
1892
1893         fdTable[fd].type = FD_SOCKET_ASYNC;
1894     }
1895     return;
1896 }
1897