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