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