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