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