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