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