Fix TCP socket accept handling that I broke in a previous commit.
[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.22 2001/09/04 18:44:11 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 static HANDLE acceptMutex = INVALID_HANDLE_VALUE;
56
57 static BOOLEAN shutdownPending = FALSE;
58
59 /*
60  * An enumeration of the file types
61  * supported by the FD_TABLE structure.
62  *
63  * XXX: Not all currently supported.  This allows for future
64  *      functionality.
65  */
66 typedef enum {
67     FD_UNUSED,
68     FD_FILE_SYNC,
69     FD_FILE_ASYNC,
70     FD_SOCKET_SYNC,
71     FD_SOCKET_ASYNC,
72     FD_PIPE_SYNC,
73     FD_PIPE_ASYNC
74 } FILE_TYPE;
75
76 typedef union {
77     HANDLE fileHandle;
78     SOCKET sock;
79     unsigned int value;
80 } DESCRIPTOR;
81
82 /*
83  * Structure used to map file handle and socket handle
84  * values into values that can be used to create unix-like
85  * select bitmaps, read/write for both sockets/files.
86  */
87 struct FD_TABLE {
88     DESCRIPTOR fid;
89     FILE_TYPE type;
90     char *path;
91     DWORD Errno;
92     unsigned long instance;
93     int status;
94     int offset;                 /* only valid for async file writes */
95     LPDWORD offsetHighPtr;      /* pointers to offset high and low words */
96     LPDWORD offsetLowPtr;       /* only valid for async file writes (logs) */
97     HANDLE  hMapMutex;          /* mutex handle for multi-proc offset update */
98     LPVOID  ovList;             /* List of associated OVERLAPPED_REQUESTs */
99 };
100
101 /* 
102  * XXX Note there is no dyanmic sizing of this table, so if the
103  * number of open file descriptors exceeds WIN32_OPEN_MAX the 
104  * app will blow up.
105  */
106 static struct FD_TABLE fdTable[WIN32_OPEN_MAX];
107
108 static CRITICAL_SECTION  fdTableCritical;
109
110 struct OVERLAPPED_REQUEST {
111     OVERLAPPED overlapped;
112     unsigned long instance;     /* file instance (won't match after a close) */
113     OS_AsyncProc procPtr;       /* callback routine */
114     ClientData clientData;      /* callback argument */
115     ClientData clientData1;     /* additional clientData */
116 };
117 typedef struct OVERLAPPED_REQUEST *POVERLAPPED_REQUEST;
118
119 static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\";
120
121 static FILE_TYPE listenType = FD_UNUSED;
122
123 // XXX This should be a DESCRIPTOR
124 static HANDLE hListen = INVALID_HANDLE_VALUE;
125
126 static OVERLAPPED listenOverlapped;
127 static BOOLEAN libInitialized = FALSE;
128
129 /*
130  *--------------------------------------------------------------
131  *
132  * Win32NewDescriptor --
133  *
134  *      Set up for I/O descriptor masquerading.
135  *
136  * Results:
137  *      Returns "fake id" which masquerades as a UNIX-style "small
138  *      non-negative integer" file/socket descriptor.
139  *      Win32_* routine below will "do the right thing" based on the
140  *      descriptor's actual type. -1 indicates failure.
141  *
142  * Side effects:
143  *      Entry in fdTable is reserved to represent the socket/file.
144  *
145  *--------------------------------------------------------------
146  */
147 static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd)
148 {
149     int index = -1;
150
151     EnterCriticalSection(&fdTableCritical);
152
153     /*
154      * If desiredFd is set, try to get this entry (this is used for
155      * mapping stdio handles).  Otherwise try to get the fd entry.
156      * If this is not available, find a the first empty slot.  .
157      */
158     if (desiredFd >= 0 && desiredFd < WIN32_OPEN_MAX)
159     {
160         if (fdTable[desiredFd].type == FD_UNUSED) 
161         {
162             index = desiredFd;
163         }
164         }
165     else if (fd > 0)
166     {
167         if (fd < WIN32_OPEN_MAX && fdTable[fd].type == FD_UNUSED)
168         {
169                 index = fd;
170         }
171         else 
172         {
173             int i;
174
175             for (i = 1; i < WIN32_OPEN_MAX; ++i)
176             {
177                     if (fdTable[i].type == FD_UNUSED)
178                 {
179                     index = i;
180                     break;
181                 }
182             }
183         }
184     }
185     
186     if (index != -1) 
187     {
188         fdTable[index].fid.value = fd;
189         fdTable[index].type = type;
190         fdTable[index].path = NULL;
191         fdTable[index].Errno = NO_ERROR;
192         fdTable[index].status = 0;
193         fdTable[index].offset = -1;
194         fdTable[index].offsetHighPtr = fdTable[index].offsetLowPtr = NULL;
195         fdTable[index].hMapMutex = NULL;
196         fdTable[index].ovList = NULL;
197     }
198
199     LeaveCriticalSection(&fdTableCritical);
200     return index;
201 }
202
203 /*
204  *--------------------------------------------------------------
205  *
206  * StdinThread--
207  *
208  *      This thread performs I/O on stadard input.  It is needed
209  *      because you can't guarantee that all applications will
210  *      create standard input with sufficient access to perform
211  *      asynchronous I/O.  Since we don't want to block the app
212  *      reading from stdin we make it look like it's using I/O
213  *      completion ports to perform async I/O.
214  *
215  * Results:
216  *      Data is read from stdin and posted to the io completion
217  *      port.
218  *
219  * Side effects:
220  *      None.
221  *
222  *--------------------------------------------------------------
223  */
224 static void StdinThread(LPDWORD startup){
225
226     int doIo = TRUE;
227     unsigned long fd;
228     unsigned long bytesRead;
229     POVERLAPPED_REQUEST pOv;
230
231     // Touch the arg to prevent warning
232     startup = NULL;
233
234     while(doIo) {
235         /*
236          * Block until a request to read from stdin comes in or a
237          * request to terminate the thread arrives (fd = -1).
238          */
239         if (!GetQueuedCompletionStatus(hStdinCompPort, &bytesRead, &fd,
240             (LPOVERLAPPED *)&pOv, (DWORD)-1) && !pOv) {
241             doIo = 0;
242             break;
243         }
244
245         ASSERT((fd == STDIN_FILENO) || (fd == -1));
246         if(fd == -1) {
247             doIo = 0;
248             break;
249         }
250         ASSERT(pOv->clientData1 != NULL);
251
252         if(ReadFile(stdioHandles[STDIN_FILENO], pOv->clientData1, bytesRead,
253                     &bytesRead, NULL)) {
254             PostQueuedCompletionStatus(hIoCompPort, bytesRead,
255                                        STDIN_FILENO, (LPOVERLAPPED)pOv);
256         } else {
257             doIo = 0;
258             break;
259         }
260     }
261
262     ExitThread(0);
263 }
264
265 static DWORD WINAPI ShutdownRequestThread(LPVOID arg)
266 {
267     HANDLE shutdownEvent = (HANDLE) arg;
268     
269     if (WaitForSingleObject(shutdownEvent, INFINITE) == WAIT_FAILED)
270     {
271         // Assuming it will happen again, all we can do is exit the thread
272         return 1;
273     }
274     else
275     {
276         // "Simple reads and writes to properly-aligned 32-bit variables are atomic"
277         shutdownPending = TRUE;
278         
279         // Before an accept() is entered the shutdownPending flag is checked.
280         // If set, OS_Accept() will return -1.  If not, it waits
281         // on a connection request for one second, checks the flag, & repeats.
282         // Only one process/thread is allowed to do this at time by
283         // wrapping the accept() with mutex.
284         return 0;
285     }
286 }
287
288 /*
289  *--------------------------------------------------------------
290  *
291  * OS_LibInit --
292  *
293  *      Set up the OS library for use.
294  *
295  * Results:
296  *      Returns 0 if success, -1 if not.
297  *
298  * Side effects:
299  *      Sockets initialized, pseudo file descriptors setup, etc.
300  *
301  *--------------------------------------------------------------
302  */
303 int OS_LibInit(int stdioFds[3])
304 {
305     WORD  wVersion;
306     WSADATA wsaData;
307     int err;
308     int fakeFd;
309     DWORD threadId;
310     char *cLenPtr = NULL;
311     char *val = NULL;
312         
313     if(libInitialized)
314         return 0;
315
316     InitializeCriticalSection(&fdTableCritical);   
317         
318     /*
319      * Initialize windows sockets library.
320      */
321     wVersion = MAKEWORD(2,0);
322     err = WSAStartup( wVersion, &wsaData );
323     if (err) {
324         fprintf(stderr, "Error starting Windows Sockets.  Error: %d",
325                 WSAGetLastError());
326         exit(111);
327     }
328
329     /*
330      * Create the I/O completion port to be used for our I/O queue.
331      */
332     if (hIoCompPort == INVALID_HANDLE_VALUE) {
333         hIoCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
334                                               0, 1);
335         if(hIoCompPort == INVALID_HANDLE_VALUE) {
336             printf("<H2>OS_LibInit Failed CreateIoCompletionPort!  ERROR: %d</H2>\r\n\r\n",
337                GetLastError());
338             return -1;
339         }
340     }
341
342     /*
343      * If a shutdown event is in the env, save it (I don't see any to 
344      * remove it from the environment out from under the application).
345      * Spawn a thread to wait on the shutdown request.
346      */
347     val = getenv(SHUTDOWN_EVENT_NAME);
348     if (val != NULL) 
349     {
350         HANDLE shutdownEvent = (HANDLE) atoi(val);
351
352         if (! CreateThread(NULL, 0, ShutdownRequestThread, 
353                            shutdownEvent, 0, NULL))
354         {
355             return -1;
356         }
357     }
358
359     /*
360      * If an accept mutex is in the env, save it and remove it.
361      */
362     val = getenv(MUTEX_VARNAME);
363     if (val != NULL) 
364     {
365         acceptMutex = (HANDLE) atoi(val);
366     }
367
368
369     /*
370      * Determine if this library is being used to listen for FastCGI
371      * connections.  This is communicated by STDIN containing a
372      * valid handle to a listener object.  In this case, both the
373      * "stdout" and "stderr" handles will be INVALID (ie. closed) by
374      * the starting process.
375      *
376      * The trick is determining if this is a pipe or a socket...
377      *
378      * XXX: Add the async accept test to determine socket or handle to a
379      *      pipe!!!
380      */
381     if((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
382        (GetStdHandle(STD_ERROR_HANDLE)  == INVALID_HANDLE_VALUE) &&
383        (GetStdHandle(STD_INPUT_HANDLE)  != INVALID_HANDLE_VALUE) ) 
384     {
385         DWORD pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT;
386         HANDLE oldStdIn = GetStdHandle(STD_INPUT_HANDLE);
387
388         // Move the handle to a "low" number
389         if (! DuplicateHandle(GetCurrentProcess(), oldStdIn,
390                               GetCurrentProcess(), &hListen,
391                               0, TRUE, DUPLICATE_SAME_ACCESS))
392         {
393             return -1;
394         }
395
396         if (! SetStdHandle(STD_INPUT_HANDLE, hListen))
397         {
398             return -1;
399         }
400
401         CloseHandle(oldStdIn);
402
403         /*
404          * Set the pipe handle state so that it operates in wait mode.
405          *
406          * NOTE: The listenFd is not mapped to a pseudo file descriptor
407          *       as all work done on it is contained to the OS library.
408          *
409          * XXX: Initial assumption is that SetNamedPipeHandleState will
410          *      fail if this is an IP socket...
411          */
412         if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL)) 
413         {
414             listenType = FD_PIPE_SYNC;
415             listenOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
416         } 
417         else 
418         {
419             listenType = FD_SOCKET_SYNC;
420         }
421     }
422
423     /*
424      * If there are no stdioFds passed in, we're done.
425      */
426     if(stdioFds == NULL) {
427         libInitialized = 1;
428         return 0;
429     }
430
431     /*
432      * Setup standard input asynchronous I/O.  There is actually a separate
433      * thread spawned for this purpose.  The reason for this is that some
434      * web servers use anonymous pipes for the connection between itself
435      * and a CGI application.  Anonymous pipes can't perform asynchronous
436      * I/O or use I/O completion ports.  Therefore in order to present a
437      * consistent I/O dispatch model to an application we emulate I/O
438      * completion port behavior by having the standard input thread posting
439      * messages to the hIoCompPort which look like a complete overlapped
440      * I/O structure.  This keeps the event dispatching simple from the
441      * application perspective.
442      */
443     stdioHandles[STDIN_FILENO] = GetStdHandle(STD_INPUT_HANDLE);
444
445     if(!SetHandleInformation(stdioHandles[STDIN_FILENO],
446                              HANDLE_FLAG_INHERIT, 0)) {
447 /*
448  * XXX: Causes error when run from command line.  Check KB
449         err = GetLastError();
450         DebugBreak();
451         exit(99);
452  */
453     }
454
455     if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
456                                      (int)stdioHandles[STDIN_FILENO],
457                                      STDIN_FILENO)) == -1) {
458         return -1;
459     } else {
460         /*
461          * Set stdin equal to our pseudo FD and create the I/O completion
462          * port to be used for async I/O.
463          */
464         stdioFds[STDIN_FILENO] = fakeFd;
465     }
466
467     /*
468      * Create the I/O completion port to be used for communicating with
469      * the thread doing I/O on standard in.  This port will carry read
470      * and possibly thread termination requests to the StdinThread.
471      */
472     if (hStdinCompPort == INVALID_HANDLE_VALUE) {
473         hStdinCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
474                                               0, 1);
475         if(hStdinCompPort == INVALID_HANDLE_VALUE) {
476             printf("<H2>OS_LibInit Failed CreateIoCompletionPort: STDIN!  ERROR: %d</H2>\r\n\r\n",
477                GetLastError());
478             return -1;
479         }
480     }
481
482     /*
483      * Create the thread that will read stdin if the CONTENT_LENGTH
484      * is non-zero.
485      */
486     if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL &&
487        atoi(cLenPtr) > 0) {
488         hStdinThread = CreateThread(NULL, 8192,
489                                     (LPTHREAD_START_ROUTINE)&StdinThread,
490                                     NULL, 0, &threadId);
491         if (hStdinThread == NULL) {
492             printf("<H2>OS_LibInit Failed to create STDIN thread!  ERROR: %d</H2>\r\n\r\n",
493                    GetLastError());
494             return -1;
495         }
496     }
497
498     /*
499      * STDOUT will be used synchronously.
500      *
501      * XXX: May want to convert this so that it could be used for OVERLAPPED
502      *      I/O later.  If so, model it after the Stdin I/O as stdout is
503      *      also incapable of async I/O on some servers.
504      */
505     stdioHandles[STDOUT_FILENO] = GetStdHandle(STD_OUTPUT_HANDLE);
506     if(!SetHandleInformation(stdioHandles[STDOUT_FILENO],
507                              HANDLE_FLAG_INHERIT, FALSE)) {
508         DebugBreak();
509         exit(99);
510     }
511
512     if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
513                                      (int)stdioHandles[STDOUT_FILENO],
514                                      STDOUT_FILENO)) == -1) {
515         return -1;
516     } else {
517         /*
518          * Set stdout equal to our pseudo FD
519          */
520         stdioFds[STDOUT_FILENO] = fakeFd;
521     }
522
523     stdioHandles[STDERR_FILENO] = GetStdHandle(STD_ERROR_HANDLE);
524     if(!SetHandleInformation(stdioHandles[STDERR_FILENO],
525                              HANDLE_FLAG_INHERIT, FALSE)) {
526         DebugBreak();
527         exit(99);
528     }
529     if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
530                                      (int)stdioHandles[STDERR_FILENO],
531                                      STDERR_FILENO)) == -1) {
532         return -1;
533     } else {
534         /*
535          * Set stderr equal to our pseudo FD
536          */
537         stdioFds[STDERR_FILENO] = fakeFd;
538     }
539
540     return 0;
541 }
542
543 /*
544  *--------------------------------------------------------------
545  *
546  * OS_LibShutdown --
547  *
548  *      Shutdown the OS library.
549  *
550  * Results:
551  *      None.
552  *
553  * Side effects:
554  *      Memory freed, handles closed.
555  *
556  *--------------------------------------------------------------
557  */
558 void OS_LibShutdown()
559 {
560
561     if (hIoCompPort != INVALID_HANDLE_VALUE) 
562     {
563         CloseHandle(hIoCompPort);
564         hIoCompPort = INVALID_HANDLE_VALUE;
565     }
566
567     if (hStdinCompPort != INVALID_HANDLE_VALUE) 
568     {
569         CloseHandle(hStdinCompPort);
570         hStdinCompPort = INVALID_HANDLE_VALUE;
571     }
572
573     if (acceptMutex != INVALID_HANDLE_VALUE) 
574     {
575         ReleaseMutex(acceptMutex);
576     }
577
578     DisconnectNamedPipe(hListen);
579
580     CancelIo(hListen);
581
582
583     WSACleanup();
584 }
585
586 /*
587  *--------------------------------------------------------------
588  *
589  * Win32FreeDescriptor --
590  *
591  *      Free I/O descriptor entry in fdTable.
592  *
593  * Results:
594  *      Frees I/O descriptor entry in fdTable.
595  *
596  * Side effects:
597  *      None.
598  *
599  *--------------------------------------------------------------
600  */
601 static void Win32FreeDescriptor(int fd)
602 {
603     /* Catch it if fd is a bogus value */
604     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
605
606     EnterCriticalSection(&fdTableCritical);
607     
608     if (fdTable[fd].type != FD_UNUSED)
609     {   
610         switch (fdTable[fd].type) 
611         {
612             case FD_FILE_SYNC:
613             case FD_FILE_ASYNC:
614         
615                 /* Free file path string */
616                 ASSERT(fdTable[fd].path != NULL);
617                 free(fdTable[fd].path);
618                 fdTable[fd].path = NULL;
619                 break;
620
621             default:
622                 break;
623         }
624
625         ASSERT(fdTable[fd].path == NULL);
626
627         fdTable[fd].type = FD_UNUSED;
628         fdTable[fd].path = NULL;
629         fdTable[fd].Errno = NO_ERROR;
630         fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL;
631
632         if (fdTable[fd].hMapMutex != NULL) 
633         {
634             CloseHandle(fdTable[fd].hMapMutex);
635             fdTable[fd].hMapMutex = NULL;
636         }
637     }
638
639     LeaveCriticalSection(&fdTableCritical);
640
641     return;
642 }
643
644 static short getPort(const char * bindPath)
645 {
646     short port = 0;
647     char * p = strchr(bindPath, ':');
648
649     if (p && *++p) 
650     {
651         char buf[6];
652
653         strncpy(buf, p, 6);
654         buf[5] = '\0';
655
656         port = (short) atoi(buf);
657     }
658  
659     return port;
660 }
661
662 /*
663  * OS_CreateLocalIpcFd --
664  *
665  *   This procedure is responsible for creating the listener pipe
666  *   on Windows NT for local process communication.  It will create a
667  *   named pipe and return a file descriptor to it to the caller.
668  *
669  * Results:
670  *      Listener pipe created.  This call returns either a valid
671  *      pseudo file descriptor or -1 on error.
672  *
673  * Side effects:
674  *      Listener pipe and IPC address are stored in the FCGI info
675  *         structure.
676  *      'errno' will set on errors (-1 is returned).
677  *
678  *----------------------------------------------------------------------
679  */
680 int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
681 {
682     int pseudoFd = -1;
683     short port = getPort(bindPath);
684     HANDLE mutex = CreateMutex(NULL, FALSE, NULL);
685     char * mutexEnvString;
686
687     if (mutex == NULL)
688     {
689         return -2;
690     }
691
692     if (! SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE))
693     {
694         return -3;
695     }
696
697     // This is a nail for listening to more than one port..
698     // This should really be handled by the caller.
699
700     mutexEnvString = malloc(strlen(MUTEX_VARNAME) + 7);
701     sprintf(mutexEnvString, MUTEX_VARNAME "=%d", (int) mutex);
702     putenv(mutexEnvString);
703
704     // There's nothing to be gained (at the moment) by a shutdown Event    
705
706     if (port && *bindPath != ':' && strncmp(bindPath, LOCALHOST, strlen(LOCALHOST)))
707     {
708             fprintf(stderr, "To start a service on a TCP port can not "
709                             "specify a host name.\n"
710                             "You should either use \"localhost:<port>\" or "
711                             " just use \":<port>.\"\n");
712             exit(1);
713     }
714
715     listenType = (port) ? FD_SOCKET_SYNC : FD_PIPE_ASYNC;
716     
717     if (port) 
718     {
719         SOCKET listenSock;
720         struct  sockaddr_in     sockAddr;
721         int sockLen = sizeof(sockAddr);
722         
723         memset(&sockAddr, 0, sizeof(sockAddr));
724         sockAddr.sin_family = AF_INET;
725         sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
726         sockAddr.sin_port = htons(port);
727
728         listenSock = socket(AF_INET, SOCK_STREAM, 0);
729         if (listenSock == INVALID_SOCKET) 
730         {
731                 return -4;
732             }
733
734             if (bind(listenSock, (struct sockaddr *) &sockAddr, sockLen)  )
735         {
736                 return -12;
737             }
738
739             if (listen(listenSock, backlog)) 
740         {
741                 return -5;
742             }
743
744         pseudoFd = Win32NewDescriptor(listenType, listenSock, -1);
745         
746         if (pseudoFd == -1) 
747         {
748             closesocket(listenSock);
749             return -6;
750         }
751
752         hListen = (HANDLE) listenSock;        
753     }
754     else
755     {
756         HANDLE hListenPipe = INVALID_HANDLE_VALUE;
757         char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
758         
759         if (! pipePath) 
760         {
761             return -7;
762         }
763
764         strcpy(pipePath, bindPathPrefix);
765         strcat(pipePath, bindPath);
766
767         hListenPipe = CreateNamedPipe(pipePath,
768                         PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
769                         PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
770                         PIPE_UNLIMITED_INSTANCES,
771                         4096, 4096, 0, NULL);
772         
773         free(pipePath);
774
775         if (hListenPipe == INVALID_HANDLE_VALUE)
776         {
777             return -8;
778         }
779
780         if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE))
781         {
782             return -9;
783         }
784
785         pseudoFd = Win32NewDescriptor(listenType, (int) hListenPipe, -1);
786         
787         if (pseudoFd == -1) 
788         {
789             CloseHandle(hListenPipe);
790             return -10;
791         }
792
793         hListen = (HANDLE) hListenPipe;
794     }
795
796     return pseudoFd;
797 }
798
799 /*
800  *----------------------------------------------------------------------
801  *
802  * OS_FcgiConnect --
803  *
804  *      Create the pipe pathname connect to the remote application if
805  *      possible.
806  *
807  * Results:
808  *      -1 if fail or a valid handle if connection succeeds.
809  *
810  * Side effects:
811  *      Remote connection established.
812  *
813  *----------------------------------------------------------------------
814  */
815 int OS_FcgiConnect(char *bindPath)
816 {
817     short port = getPort(bindPath);
818     int pseudoFd = -1;
819     
820     if (port) 
821     {
822             struct hostent *hp;
823         char *host = NULL;
824         struct sockaddr_in sockAddr;
825         int sockLen = sizeof(sockAddr);
826         SOCKET sock;
827         
828         if (*bindPath != ':')
829         {
830             char * p = strchr(bindPath, ':');
831             int len = p - bindPath + 1;
832
833             host = malloc(len);
834             strncpy(host, bindPath, len);
835             host[len] = '\0';
836         }
837         
838         hp = gethostbyname(host ? host : LOCALHOST);
839
840         if (host)
841         {
842             free(host);
843         }
844
845             if (hp == NULL) 
846         {
847                 fprintf(stderr, "Unknown host: %s\n", bindPath);
848                 return -1;
849             }
850        
851         memset(&sockAddr, 0, sizeof(sockAddr));
852         sockAddr.sin_family = AF_INET;
853             memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length);
854             sockAddr.sin_port = htons(port);
855
856             sock = socket(AF_INET, SOCK_STREAM, 0);
857         if (sock == INVALID_SOCKET)
858         {
859             return -1;
860         }
861
862             if (! connect(sock, (struct sockaddr *) &sockAddr, sockLen)) 
863         {
864                 closesocket(sock);
865                 return -1;
866             }
867
868             pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, sock, -1);
869             if (pseudoFd == -1) 
870         {
871                 closesocket(sock);
872             return -1;
873             }
874     }
875     else
876     {
877         char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
878         HANDLE hPipe;
879         
880         if (! pipePath) 
881         {
882             return -1;
883         }
884
885         strcpy(pipePath, bindPathPrefix);
886         strcat(pipePath, bindPath);
887
888         hPipe = CreateFile(pipePath,
889                             GENERIC_WRITE | GENERIC_READ,
890                             FILE_SHARE_READ | FILE_SHARE_WRITE,
891                             NULL,
892                             OPEN_EXISTING,
893                             FILE_FLAG_OVERLAPPED,
894                             NULL);
895
896         free(pipePath);
897
898         if( hPipe == INVALID_HANDLE_VALUE) 
899         {
900             return -1;
901         }
902
903         pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int) hPipe, -1);
904         
905         if (pseudoFd == -1) 
906         {
907             CloseHandle(hPipe);
908             return -1;
909         } 
910         
911         /*
912              * Set stdin equal to our pseudo FD and create the I/O completion
913              * port to be used for async I/O.
914              */
915         if (! CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1))
916         {
917                 Win32FreeDescriptor(pseudoFd);
918                 CloseHandle(hPipe);
919                 return -1;
920             }
921     }
922
923     return pseudoFd;    
924 }
925
926 /*
927  *--------------------------------------------------------------
928  *
929  * OS_Read --
930  *
931  *      Pass through to the appropriate NT read function.
932  *
933  * Results:
934  *      Returns number of byes read. Mimics unix read:.
935  *              n bytes read, 0 or -1 failure: errno contains actual error
936  *
937  * Side effects:
938  *      None.
939  *
940  *--------------------------------------------------------------
941  */
942 int OS_Read(int fd, char * buf, size_t len)
943 {
944     DWORD bytesRead;
945     int ret = -1;
946
947     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
948
949     switch (fdTable[fd].type) 
950     {
951         case FD_FILE_SYNC:
952         case FD_FILE_ASYNC:
953         case FD_PIPE_SYNC:
954         case FD_PIPE_ASYNC:
955
956             if (ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, NULL)) 
957         {
958             ret = bytesRead;
959         }
960         else
961         {
962                     fdTable[fd].Errno = GetLastError();
963             }
964
965         break;
966
967         case FD_SOCKET_SYNC:
968         case FD_SOCKET_ASYNC:
969
970         ret = recv(fdTable[fd].fid.sock, buf, len, 0);
971             if (ret == SOCKET_ERROR) 
972         {
973                     fdTable[fd].Errno = WSAGetLastError();
974                     ret = -1;
975             }
976
977         break;
978         
979     default:
980
981         ASSERT(0);
982     }
983
984     return ret;
985 }
986
987 /*
988  *--------------------------------------------------------------
989  *
990  * OS_Write --
991  *
992  *      Perform a synchronous OS write.
993  *
994  * Results:
995  *      Returns number of bytes written. Mimics unix write:
996  *              n bytes written, 0 or -1 failure (??? couldn't find man page).
997  *
998  * Side effects:
999  *      none.
1000  *
1001  *--------------------------------------------------------------
1002  */
1003 int OS_Write(int fd, char * buf, size_t len)
1004 {
1005     DWORD bytesWritten;
1006     int ret = -1;
1007
1008     ASSERT(fd >= 0 && fd < WIN32_OPEN_MAX);
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