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