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