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