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