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