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