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