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