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