1 /*
2  * os_win32.c --
3  *
4  *  Bill Snapper
5  *  snapper@openmarket.com
6  *
7  * (Special thanks to Karen and Bill.  They made my job much easier and
8  *  significantly more enjoyable.)
9  *
10  * Copyright (c) 1996 Open Market, Inc.
11  *
12  * See the file "LICENSE" for information on usage and redistribution
13  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14  */
15 #ifndef lint
16 static const char rcsid[] = "$Id: os_win32.c,v 1.35 2004/01/31 17:47:07 robs Exp $";
17 #endif /* not lint */
18 
19 #define WIN32_LEAN_AND_MEAN
20 #include <windows.h>
21 #include <winsock2.h>
22 #include <stdlib.h>
23 #include <assert.h>
24 #include <stdio.h>
25 #include <sys/timeb.h>
26 #include <process.h>
27 #include <signal.h>
28 
29 #define DLLAPI  __declspec(dllexport)
30 
31 #include "fcgimisc.h"
32 #include "fcgios.h"
33 
34 #define WIN32_OPEN_MAX 128 /* XXX: Small hack */
35 
36 /*
37  * millisecs to wait for a client connection before checking the
38  * shutdown flag (then go back to waiting for a connection, etc).
39  */
40 #define ACCEPT_TIMEOUT 1000
41 
42 #define MUTEX_VARNAME "_FCGI_MUTEX_"
43 #define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_"
44 #define LOCALHOST "localhost"
45 
46 static HANDLE hIoCompPort = INVALID_HANDLE_VALUE;
47 static HANDLE hStdinCompPort = INVALID_HANDLE_VALUE;
48 static HANDLE hStdinThread = INVALID_HANDLE_VALUE;
49 
50 static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
51 				 INVALID_HANDLE_VALUE};
52 
53 // This is a nail for listening to more than one port..
54 static HANDLE acceptMutex = INVALID_HANDLE_VALUE;
55 
56 static BOOLEAN shutdownPending = FALSE;
57 static BOOLEAN shutdownNow = FALSE;
58 
59 /*
60  * An enumeration of the file types
61  * supported by the FD_TABLE structure.
62  *
63  * XXX: Not all currently supported.  This allows for future
64  *      functionality.
65  */
66 typedef enum {
67     FD_UNUSED,
68     FD_FILE_SYNC,
69     FD_FILE_ASYNC,
70     FD_SOCKET_SYNC,
71     FD_SOCKET_ASYNC,
72     FD_PIPE_SYNC,
73     FD_PIPE_ASYNC
74 } FILE_TYPE;
75 
76 typedef union {
77     HANDLE fileHandle;
78     SOCKET sock;
79     unsigned int value;
80 } DESCRIPTOR;
81 
82 /*
83  * Structure used to map file handle and socket handle
84  * values into values that can be used to create unix-like
85  * select bitmaps, read/write for both sockets/files.
86  */
87 struct FD_TABLE {
88     DESCRIPTOR fid;
89     FILE_TYPE type;
90     char *path;
91     DWORD Errno;
92     unsigned long instance;
93     int status;
94     int offset;			/* only valid for async file writes */
95     LPDWORD offsetHighPtr;	/* pointers to offset high and low words */
96     LPDWORD offsetLowPtr;	/* only valid for async file writes (logs) */
97     HANDLE  hMapMutex;		/* mutex handle for multi-proc offset update */
98     LPVOID  ovList;		/* List of associated OVERLAPPED_REQUESTs */
99 };
100 
101 /*
102  * XXX Note there is no dyanmic sizing of this table, so if the
103  * number of open file descriptors exceeds WIN32_OPEN_MAX the
104  * app will blow up.
105  */
106 static struct FD_TABLE fdTable[WIN32_OPEN_MAX];
107 
108 static CRITICAL_SECTION  fdTableCritical;
109 
110 struct OVERLAPPED_REQUEST {
111     OVERLAPPED overlapped;
112     unsigned long instance;	/* file instance (won't match after a close) */
113     OS_AsyncProc procPtr;	/* callback routine */
114     ClientData clientData;	/* callback argument */
115     ClientData clientData1;	/* additional clientData */
116 };
117 typedef struct OVERLAPPED_REQUEST *POVERLAPPED_REQUEST;
118 
119 static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\";
120 
121 static FILE_TYPE listenType = FD_UNUSED;
122 
123 // XXX This should be a DESCRIPTOR
124 static HANDLE hListen = INVALID_HANDLE_VALUE;
125 
126 static 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  */
Win32NewDescriptor(FILE_TYPE type,int fd,int desiredFd)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  */
StdinThread(void * startup)223 static void StdinThread(void * 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 
OS_ShutdownPending(void)264 void OS_ShutdownPending(void)
265 {
266     shutdownPending = TRUE;
267 }
268 
ShutdownRequestThread(void * arg)269 static void ShutdownRequestThread(void * arg)
270 {
271     HANDLE shutdownEvent = (HANDLE) arg;
272 
273     WaitForSingleObject(shutdownEvent, INFINITE);
274 
275     shutdownPending = TRUE;
276 
277     // emulate the unix behaviour
278     raise(SIGTERM);
279 
280     if (listenType == FD_PIPE_SYNC)
281     {
282         // Its a hassle to get ConnectNamedPipe to return early,
283         // so just wack the whole process - yes, this will toast
284         // any requests in progress, but at least its a clean
285         // shutdown (its better than TerminateProcess())
286         exit(0);
287     }
288 
289     // FD_SOCKET_SYNC: When in Accept(), select() is used to poll
290     // the shutdownPending flag - yeah this isn't pretty either
291     // but its only one process doing it if an Accept mutex is used.
292     // This at least buys no toasted requests.
293 }
294 
295 /*
296  *--------------------------------------------------------------
297  *
298  * OS_LibInit --
299  *
300  *	Set up the OS library for use.
301  *
302  * Results:
303  *	Returns 0 if success, -1 if not.
304  *
305  * Side effects:
306  *	Sockets initialized, pseudo file descriptors setup, etc.
307  *
308  *--------------------------------------------------------------
309  */
OS_LibInit(int stdioFds[3])310 int OS_LibInit(int stdioFds[3])
311 {
312     WORD  wVersion;
313     WSADATA wsaData;
314     int err;
315     int fakeFd;
316     char *cLenPtr = NULL;
317     char *val = NULL;
318 
319     if(libInitialized)
320         return 0;
321 
322     InitializeCriticalSection(&fdTableCritical);
323 
324     /*
325      * Initialize windows sockets library.
326      */
327     wVersion = MAKEWORD(2,0);
328     err = WSAStartup( wVersion, &wsaData );
329     if (err) {
330         fprintf(stderr, "Error starting Windows Sockets.  Error: %d",
331 		WSAGetLastError());
332 	exit(111);
333     }
334 
335     /*
336      * Create the I/O completion port to be used for our I/O queue.
337      */
338     if (hIoCompPort == INVALID_HANDLE_VALUE) {
339 	hIoCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
340 					      0, 1);
341 	if(hIoCompPort == INVALID_HANDLE_VALUE) {
342 	    printf("<H2>OS_LibInit Failed CreateIoCompletionPort!  ERROR: %d</H2>\r\n\r\n",
343 	       GetLastError());
344 	    return -1;
345 	}
346     }
347 
348     /*
349      * If a shutdown event is in the env, save it (I don't see any to
350      * remove it from the environment out from under the application).
351      * Spawn a thread to wait on the shutdown request.
352      */
353     val = getenv(SHUTDOWN_EVENT_NAME);
354     if (val != NULL)
355     {
356         HANDLE shutdownEvent = (HANDLE) atoi(val);
357 
358         if (_beginthread(ShutdownRequestThread, 0, shutdownEvent) == -1)
359         {
360             return -1;
361         }
362     }
363 
364     if (acceptMutex == INVALID_HANDLE_VALUE)
365     {
366         /* If an accept mutex is in the env, use it */
367         val = getenv(MUTEX_VARNAME);
368         if (val != NULL)
369         {
370             acceptMutex = (HANDLE) atoi(val);
371         }
372     }
373 
374     /*
375      * Determine if this library is being used to listen for FastCGI
376      * connections.  This is communicated by STDIN containing a
377      * valid handle to a listener object.  In this case, both the
378      * "stdout" and "stderr" handles will be INVALID (ie. closed) by
379      * the starting process.
380      *
381      * The trick is determining if this is a pipe or a socket...
382      *
383      * XXX: Add the async accept test to determine socket or handle to a
384      *      pipe!!!
385      */
386     if((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
387        (GetStdHandle(STD_ERROR_HANDLE)  == INVALID_HANDLE_VALUE) &&
388        (GetStdHandle(STD_INPUT_HANDLE)  != INVALID_HANDLE_VALUE) )
389     {
390         DWORD pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT;
391         HANDLE oldStdIn = GetStdHandle(STD_INPUT_HANDLE);
392 
393         // Move the handle to a "low" number
394         if (! DuplicateHandle(GetCurrentProcess(), oldStdIn,
395                               GetCurrentProcess(), &hListen,
396                               0, TRUE, DUPLICATE_SAME_ACCESS))
397         {
398             return -1;
399         }
400 
401         if (! SetStdHandle(STD_INPUT_HANDLE, hListen))
402         {
403             return -1;
404         }
405 
406         CloseHandle(oldStdIn);
407 
408 	/*
409 	 * Set the pipe handle state so that it operates in wait mode.
410 	 *
411 	 * NOTE: The listenFd is not mapped to a pseudo file descriptor
412 	 *       as all work done on it is contained to the OS library.
413 	 *
414 	 * XXX: Initial assumption is that SetNamedPipeHandleState will
415 	 *      fail if this is an IP socket...
416 	 */
417         if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL))
418         {
419             listenType = FD_PIPE_SYNC;
420         }
421         else
422         {
423             listenType = FD_SOCKET_SYNC;
424         }
425     }
426 
427     /*
428      * If there are no stdioFds passed in, we're done.
429      */
430     if(stdioFds == NULL) {
431         libInitialized = 1;
432         return 0;
433     }
434 
435     /*
436      * Setup standard input asynchronous I/O.  There is actually a separate
437      * thread spawned for this purpose.  The reason for this is that some
438      * web servers use anonymous pipes for the connection between itself
439      * and a CGI application.  Anonymous pipes can't perform asynchronous
440      * I/O or use I/O completion ports.  Therefore in order to present a
441      * consistent I/O dispatch model to an application we emulate I/O
442      * completion port behavior by having the standard input thread posting
443      * messages to the hIoCompPort which look like a complete overlapped
444      * I/O structure.  This keeps the event dispatching simple from the
445      * application perspective.
446      */
447     stdioHandles[STDIN_FILENO] = GetStdHandle(STD_INPUT_HANDLE);
448 
449     if(!SetHandleInformation(stdioHandles[STDIN_FILENO],
450 			     HANDLE_FLAG_INHERIT, 0)) {
451 /*
452  * XXX: Causes error when run from command line.  Check KB
453         err = GetLastError();
454         DebugBreak();
455 	exit(99);
456  */
457     }
458 
459     if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
460 				     (int)stdioHandles[STDIN_FILENO],
461 				     STDIN_FILENO)) == -1) {
462         return -1;
463     } else {
464         /*
465 	 * Set stdin equal to our pseudo FD and create the I/O completion
466 	 * port to be used for async I/O.
467 	 */
468 	stdioFds[STDIN_FILENO] = fakeFd;
469     }
470 
471     /*
472      * Create the I/O completion port to be used for communicating with
473      * the thread doing I/O on standard in.  This port will carry read
474      * and possibly thread termination requests to the StdinThread.
475      */
476     if (hStdinCompPort == INVALID_HANDLE_VALUE) {
477 	hStdinCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
478 					      0, 1);
479 	if(hStdinCompPort == INVALID_HANDLE_VALUE) {
480 	    printf("<H2>OS_LibInit Failed CreateIoCompletionPort: STDIN!  ERROR: %d</H2>\r\n\r\n",
481 	       GetLastError());
482 	    return -1;
483 	}
484     }
485 
486     /*
487      * Create the thread that will read stdin if the CONTENT_LENGTH
488      * is non-zero.
489      */
490     if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL &&
491        atoi(cLenPtr) > 0) {
492         hStdinThread = (HANDLE) _beginthread(StdinThread, 0, NULL);
493 	if (hStdinThread == (HANDLE) -1) {
494 	    printf("<H2>OS_LibInit Failed to create STDIN thread!  ERROR: %d</H2>\r\n\r\n",
495 		   GetLastError());
496 	    return -1;
497         }
498     }
499 
500     /*
501      * STDOUT will be used synchronously.
502      *
503      * XXX: May want to convert this so that it could be used for OVERLAPPED
504      *      I/O later.  If so, model it after the Stdin I/O as stdout is
505      *      also incapable of async I/O on some servers.
506      */
507     stdioHandles[STDOUT_FILENO] = GetStdHandle(STD_OUTPUT_HANDLE);
508     if(!SetHandleInformation(stdioHandles[STDOUT_FILENO],
509 			     HANDLE_FLAG_INHERIT, FALSE)) {
510         DebugBreak();
511 	exit(99);
512     }
513 
514     if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
515 				     (int)stdioHandles[STDOUT_FILENO],
516 				     STDOUT_FILENO)) == -1) {
517         return -1;
518     } else {
519         /*
520 	 * Set stdout equal to our pseudo FD
521 	 */
522 	stdioFds[STDOUT_FILENO] = fakeFd;
523     }
524 
525     stdioHandles[STDERR_FILENO] = GetStdHandle(STD_ERROR_HANDLE);
526     if(!SetHandleInformation(stdioHandles[STDERR_FILENO],
527 			     HANDLE_FLAG_INHERIT, FALSE)) {
528         DebugBreak();
529 	exit(99);
530     }
531     if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
532 				     (int)stdioHandles[STDERR_FILENO],
533 				     STDERR_FILENO)) == -1) {
534         return -1;
535     } else {
536         /*
537 	 * Set stderr equal to our pseudo FD
538 	 */
539 	stdioFds[STDERR_FILENO] = fakeFd;
540     }
541 
542     return 0;
543 }
544 
545 /*
546  *--------------------------------------------------------------
547  *
548  * OS_LibShutdown --
549  *
550  *	Shutdown the OS library.
551  *
552  * Results:
553  *	None.
554  *
555  * Side effects:
556  *	Memory freed, handles closed.
557  *
558  *--------------------------------------------------------------
559  */
OS_LibShutdown()560 void OS_LibShutdown()
561 {
562 
563     if (hIoCompPort != INVALID_HANDLE_VALUE)
564     {
565         CloseHandle(hIoCompPort);
566         hIoCompPort = INVALID_HANDLE_VALUE;
567     }
568 
569     if (hStdinCompPort != INVALID_HANDLE_VALUE)
570     {
571         CloseHandle(hStdinCompPort);
572         hStdinCompPort = INVALID_HANDLE_VALUE;
573     }
574 
575     if (acceptMutex != INVALID_HANDLE_VALUE)
576     {
577         ReleaseMutex(acceptMutex);
578     }
579 
580     DisconnectNamedPipe(hListen);
581 
582     CancelIo(hListen);
583 
584 
585     WSACleanup();
586 }
587 
588 /*
589  *--------------------------------------------------------------
590  *
591  * Win32FreeDescriptor --
592  *
593  *	Free I/O descriptor entry in fdTable.
594  *
595  * Results:
596  *	Frees I/O descriptor entry in fdTable.
597  *
598  * Side effects:
599  *	None.
600  *
601  *--------------------------------------------------------------
602  */
Win32FreeDescriptor(int fd)603 static void Win32FreeDescriptor(int fd)
604 {
605     /* Catch it if fd is a bogus value */
606     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
607 
608     EnterCriticalSection(&fdTableCritical);
609 
610     if (fdTable[fd].type != FD_UNUSED)
611     {
612         switch (fdTable[fd].type)
613         {
614 	    case FD_FILE_SYNC:
615 	    case FD_FILE_ASYNC:
616 
617 	        /* Free file path string */
618 	        ASSERT(fdTable[fd].path != NULL);
619 	        free(fdTable[fd].path);
620 	        fdTable[fd].path = NULL;
621 	        break;
622 
623 	    default:
624 	        break;
625         }
626 
627         ASSERT(fdTable[fd].path == NULL);
628 
629         fdTable[fd].type = FD_UNUSED;
630         fdTable[fd].path = NULL;
631         fdTable[fd].Errno = NO_ERROR;
632         fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL;
633 
634         if (fdTable[fd].hMapMutex != NULL)
635         {
636             CloseHandle(fdTable[fd].hMapMutex);
637             fdTable[fd].hMapMutex = NULL;
638         }
639     }
640 
641     LeaveCriticalSection(&fdTableCritical);
642 
643     return;
644 }
645 
getPort(const char * bindPath)646 static short getPort(const char * bindPath)
647 {
648     short port = 0;
649     char * p = strchr(bindPath, ':');
650 
651     if (p && *++p)
652     {
653         char buf[6];
654 
655         strncpy(buf, p, 6);
656         buf[5] = '\0';
657 
658         port = (short) atoi(buf);
659     }
660 
661     return port;
662 }
663 
664 /*
665  * OS_CreateLocalIpcFd --
666  *
667  *   This procedure is responsible for creating the listener pipe
668  *   on Windows NT for local process communication.  It will create a
669  *   named pipe and return a file descriptor to it to the caller.
670  *
671  * Results:
672  *      Listener pipe created.  This call returns either a valid
673  *      pseudo file descriptor or -1 on error.
674  *
675  * Side effects:
676  *      Listener pipe and IPC address are stored in the FCGI info
677  *         structure.
678  *      'errno' will set on errors (-1 is returned).
679  *
680  *----------------------------------------------------------------------
681  */
OS_CreateLocalIpcFd(const char * bindPath,int backlog)682 int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
683 {
684     int pseudoFd = -1;
685     short port = getPort(bindPath);
686 
687     if (acceptMutex == INVALID_HANDLE_VALUE)
688     {
689         acceptMutex = CreateMutex(NULL, FALSE, NULL);
690         if (acceptMutex == NULL) return -2;
691         if (! SetHandleInformation(acceptMutex, HANDLE_FLAG_INHERIT, TRUE)) return -3;
692     }
693 
694     // There's nothing to be gained (at the moment) by a shutdown Event
695 
696     if (port && *bindPath != ':' && strncmp(bindPath, LOCALHOST, strlen(LOCALHOST)))
697     {
698 	    fprintf(stderr, "To start a service on a TCP port can not "
699 			    "specify a host name.\n"
700 			    "You should either use \"localhost:<port>\" or "
701 			    " just use \":<port>.\"\n");
702 	    exit(1);
703     }
704 
705     listenType = (port) ? FD_SOCKET_SYNC : FD_PIPE_ASYNC;
706 
707     if (port)
708     {
709         SOCKET listenSock;
710         struct  sockaddr_in	sockAddr;
711         int sockLen = sizeof(sockAddr);
712 
713         memset(&sockAddr, 0, sizeof(sockAddr));
714         sockAddr.sin_family = AF_INET;
715         sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
716         sockAddr.sin_port = htons(port);
717 
718         listenSock = socket(AF_INET, SOCK_STREAM, 0);
719         if (listenSock == INVALID_SOCKET)
720         {
721 	        return -4;
722 	    }
723 
724 	    if (bind(listenSock, (struct sockaddr *) &sockAddr, sockLen)  )
725         {
726 	        return -12;
727 	    }
728 
729 	    if (listen(listenSock, backlog))
730         {
731 	        return -5;
732 	    }
733 
734         pseudoFd = Win32NewDescriptor(listenType, listenSock, -1);
735 
736         if (pseudoFd == -1)
737         {
738             closesocket(listenSock);
739             return -6;
740         }
741 
742         hListen = (HANDLE) listenSock;
743     }
744     else
745     {
746         HANDLE hListenPipe = INVALID_HANDLE_VALUE;
747         char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
748 
749         if (! pipePath)
750         {
751             return -7;
752         }
753 
754         strcpy(pipePath, bindPathPrefix);
755         strcat(pipePath, bindPath);
756 
757         hListenPipe = CreateNamedPipe(pipePath,
758 		        PIPE_ACCESS_DUPLEX,
759 		        PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
760 		        PIPE_UNLIMITED_INSTANCES,
761 		        4096, 4096, 0, NULL);
762 
763         free(pipePath);
764 
765         if (hListenPipe == INVALID_HANDLE_VALUE)
766         {
767             return -8;
768         }
769 
770         if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE))
771         {
772             return -9;
773         }
774 
775         pseudoFd = Win32NewDescriptor(listenType, (int) hListenPipe, -1);
776 
777         if (pseudoFd == -1)
778         {
779             CloseHandle(hListenPipe);
780             return -10;
781         }
782 
783         hListen = (HANDLE) hListenPipe;
784     }
785 
786     return pseudoFd;
787 }
788 
789 /*
790  *----------------------------------------------------------------------
791  *
792  * OS_FcgiConnect --
793  *
794  *	Create the pipe pathname connect to the remote application if
795  *      possible.
796  *
797  * Results:
798  *      -1 if fail or a valid handle if connection succeeds.
799  *
800  * Side effects:
801  *      Remote connection established.
802  *
803  *----------------------------------------------------------------------
804  */
OS_FcgiConnect(char * bindPath)805 int OS_FcgiConnect(char *bindPath)
806 {
807     short port = getPort(bindPath);
808     int pseudoFd = -1;
809 
810     if (port)
811     {
812 	    struct hostent *hp;
813         char *host = NULL;
814         struct sockaddr_in sockAddr;
815         int sockLen = sizeof(sockAddr);
816         SOCKET sock;
817 
818         if (*bindPath != ':')
819         {
820             char * p = strchr(bindPath, ':');
821             int len = p - bindPath + 1;
822 
823             host = malloc(len);
824             strncpy(host, bindPath, len);
825             host[len] = '\0';
826         }
827 
828         hp = gethostbyname(host ? host : LOCALHOST);
829 
830         if (host)
831         {
832             free(host);
833         }
834 
835 	    if (hp == NULL)
836         {
837 	        fprintf(stderr, "Unknown host: %s\n", bindPath);
838 	        return -1;
839 	    }
840 
841         memset(&sockAddr, 0, sizeof(sockAddr));
842         sockAddr.sin_family = AF_INET;
843 	    memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length);
844 	    sockAddr.sin_port = htons(port);
845 
846 	    sock = socket(AF_INET, SOCK_STREAM, 0);
847         if (sock == INVALID_SOCKET)
848         {
849             return -1;
850         }
851 
852 	    if (! connect(sock, (struct sockaddr *) &sockAddr, sockLen))
853         {
854 	        closesocket(sock);
855 	        return -1;
856 	    }
857 
858 	    pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, sock, -1);
859 	    if (pseudoFd == -1)
860         {
861 	        closesocket(sock);
862             return -1;
863 	    }
864     }
865     else
866     {
867         char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
868         HANDLE hPipe;
869 
870         if (! pipePath)
871         {
872             return -1;
873         }
874 
875         strcpy(pipePath, bindPathPrefix);
876         strcat(pipePath, bindPath);
877 
878         hPipe = CreateFile(pipePath,
879 			    GENERIC_WRITE | GENERIC_READ,
880 			    FILE_SHARE_READ | FILE_SHARE_WRITE,
881 			    NULL,
882 			    OPEN_EXISTING,
883 			    FILE_FLAG_OVERLAPPED,
884 			    NULL);
885 
886         free(pipePath);
887 
888         if( hPipe == INVALID_HANDLE_VALUE)
889         {
890             return -1;
891         }
892 
893         pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int) hPipe, -1);
894 
895         if (pseudoFd == -1)
896         {
897             CloseHandle(hPipe);
898             return -1;
899         }
900 
901         /*
902 	     * Set stdin equal to our pseudo FD and create the I/O completion
903 	     * port to be used for async I/O.
904 	     */
905         if (! CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1))
906         {
907 	        Win32FreeDescriptor(pseudoFd);
908 	        CloseHandle(hPipe);
909 	        return -1;
910 	    }
911     }
912 
913     return pseudoFd;
914 }
915 
916 /*
917  *--------------------------------------------------------------
918  *
919  * OS_Read --
920  *
921  *	Pass through to the appropriate NT read function.
922  *
923  * Results:
924  *	Returns number of byes read. Mimics unix read:.
925  *		n bytes read, 0 or -1 failure: errno contains actual error
926  *
927  * Side effects:
928  *	None.
929  *
930  *--------------------------------------------------------------
931  */
OS_Read(int fd,char * buf,size_t len)932 int OS_Read(int fd, char * buf, size_t len)
933 {
934     DWORD bytesRead;
935     int ret = -1;
936 
937     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
938 
939     if (shutdownNow) return -1;
940 
941     switch (fdTable[fd].type)
942     {
943 	case FD_FILE_SYNC:
944 	case FD_FILE_ASYNC:
945 	case FD_PIPE_SYNC:
946 	case FD_PIPE_ASYNC:
947 
948 	    if (ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, NULL))
949         {
950             ret = bytesRead;
951         }
952         else
953         {
954 		    fdTable[fd].Errno = GetLastError();
955 	    }
956 
957         break;
958 
959 	case FD_SOCKET_SYNC:
960 	case FD_SOCKET_ASYNC:
961 
962         ret = recv(fdTable[fd].fid.sock, buf, len, 0);
963 	    if (ret == SOCKET_ERROR)
964         {
965 		    fdTable[fd].Errno = WSAGetLastError();
966 		    ret = -1;
967 	    }
968 
969         break;
970 
971     default:
972 
973         ASSERT(0);
974     }
975 
976     return ret;
977 }
978 
979 /*
980  *--------------------------------------------------------------
981  *
982  * OS_Write --
983  *
984  *	Perform a synchronous OS write.
985  *
986  * Results:
987  *	Returns number of bytes written. Mimics unix write:
988  *		n bytes written, 0 or -1 failure (??? couldn't find man page).
989  *
990  * Side effects:
991  *	none.
992  *
993  *--------------------------------------------------------------
994  */
OS_Write(int fd,char * buf,size_t len)995 int OS_Write(int fd, char * buf, size_t len)
996 {
997     DWORD bytesWritten;
998     int ret = -1;
999 
1000     ASSERT(fd >= 0 && fd < WIN32_OPEN_MAX);
1001 
1002     if (shutdownNow) return -1;
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  */
OS_SpawnChild(char * execPath,int listenFd)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  */
OS_AsyncReadStdin(void * buf,int len,OS_AsyncProc procPtr,ClientData clientData)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  */
OS_AsyncRead(int fd,int offset,void * buf,int len,OS_AsyncProc procPtr,ClientData clientData)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  */
OS_AsyncWrite(int fd,int offset,void * buf,int len,OS_AsyncProc procPtr,ClientData clientData)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  */
OS_Close(int fd,int shutdown_ok)1355 int OS_Close(int fd, int shutdown_ok)
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 
1371         break;
1372 
1373     case FD_SOCKET_SYNC:
1374 	case FD_SOCKET_ASYNC:
1375 
1376         /*
1377          * shutdown() the send side and then read() from client until EOF
1378          * or a timeout expires.  This is done to minimize the potential
1379          * that a TCP RST will be sent by our TCP stack in response to
1380          * receipt of additional data from the client.  The RST would
1381          * cause the client to discard potentially useful response data.
1382          */
1383 
1384         if (shutdown_ok)
1385         {
1386             if (shutdown(fdTable[fd].fid.sock, SD_SEND) == 0)
1387             {
1388                 struct timeval tv;
1389                 fd_set rfds;
1390                 int sock = fdTable[fd].fid.sock;
1391                 int rv;
1392                 char trash[1024];
1393 
1394                 FD_ZERO(&rfds);
1395 
1396                 do
1397                 {
1398 #pragma warning( disable : 4127 )
1399 	            FD_SET((unsigned) sock, &rfds);
1400 #pragma warning( default : 4127 )
1401 
1402 	            tv.tv_sec = 2;
1403 	            tv.tv_usec = 0;
1404 	            rv = select(sock + 1, &rfds, NULL, NULL, &tv);
1405                 }
1406                 while (rv > 0 && recv(sock, trash, sizeof(trash), 0) > 0);
1407             }
1408         }
1409 
1410         closesocket(fdTable[fd].fid.sock);
1411 
1412         break;
1413 
1414 	default:
1415 
1416 	    ret = -1;		/* fake failure */
1417     }
1418 
1419     Win32FreeDescriptor(fd);
1420     return ret;
1421 }
1422 
1423 /*
1424  *--------------------------------------------------------------
1425  *
1426  * OS_CloseRead --
1427  *
1428  *	Cancel outstanding asynchronous reads and prevent subsequent
1429  *      reads from completing.
1430  *
1431  * Results:
1432  *	Socket or file is shutdown. Return values mimic Unix shutdown:
1433  *		0 success, -1 failure
1434  *
1435  *--------------------------------------------------------------
1436  */
OS_CloseRead(int fd)1437 int OS_CloseRead(int fd)
1438 {
1439     int ret = 0;
1440 
1441     /*
1442      * Catch it if fd is a bogus value
1443      */
1444     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1445     ASSERT(fdTable[fd].type == FD_SOCKET_ASYNC
1446 	|| fdTable[fd].type == FD_SOCKET_SYNC);
1447 
1448     if (shutdown(fdTable[fd].fid.sock,0) == SOCKET_ERROR)
1449 	ret = -1;
1450     return ret;
1451 }
1452 
1453 /*
1454  *--------------------------------------------------------------
1455  *
1456  * OS_DoIo --
1457  *
1458  *	This function was formerly OS_Select.  It's purpose is
1459  *      to pull I/O completion events off the queue and dispatch
1460  *      them to the appropriate place.
1461  *
1462  * Results:
1463  *	Returns 0.
1464  *
1465  * Side effects:
1466  *	Handlers are called.
1467  *
1468  *--------------------------------------------------------------
1469  */
OS_DoIo(struct timeval * tmo)1470 int OS_DoIo(struct timeval *tmo)
1471 {
1472     unsigned long fd;
1473     unsigned long bytes;
1474     POVERLAPPED_REQUEST pOv;
1475     struct timeb tb;
1476     int ms;
1477     int ms_last;
1478     int err;
1479 
1480     /* XXX
1481      * We can loop in here, but not too long, as wait handlers
1482      * must run.
1483      * For cgi stdin, apparently select returns when io completion
1484      * ports don't, so don't wait the full timeout.
1485      */
1486     if(tmo)
1487 	ms = (tmo->tv_sec*1000 + tmo->tv_usec/1000) / 2;
1488     else
1489 	ms = 1000;
1490     ftime(&tb);
1491     ms_last = tb.time*1000 + tb.millitm;
1492     while (ms >= 0) {
1493 	if(tmo && (ms = tmo->tv_sec*1000 + tmo->tv_usec/1000)> 100)
1494 	    ms = 100;
1495 	if (!GetQueuedCompletionStatus(hIoCompPort, &bytes, &fd,
1496 	    (LPOVERLAPPED *)&pOv, ms) && !pOv) {
1497 	    err = WSAGetLastError();
1498 	    return 0; /* timeout */
1499         }
1500 
1501 	ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1502 	/* call callback if descriptor still valid */
1503 	ASSERT(pOv);
1504 	if(pOv->instance == fdTable[fd].instance)
1505 	  (*pOv->procPtr)(pOv->clientData, bytes);
1506 	free(pOv);
1507 
1508 	ftime(&tb);
1509 	ms -= (tb.time*1000 + tb.millitm - ms_last);
1510 	ms_last = tb.time*1000 + tb.millitm;
1511     }
1512     return 0;
1513 }
1514 
isAddrOK(struct sockaddr_in * inet_sockaddr,const char * okAddrs)1515 static int isAddrOK(struct sockaddr_in * inet_sockaddr, const char * okAddrs)
1516 {
1517     static const char *token = " ,;:\t";
1518     char *ipaddr;
1519     char *p;
1520 
1521     if (okAddrs == NULL) return TRUE;
1522 
1523     ipaddr = inet_ntoa(inet_sockaddr->sin_addr);
1524     p = strstr(okAddrs, ipaddr);
1525 
1526     if (p == NULL) return FALSE;
1527 
1528     if (p == okAddrs)
1529     {
1530         p += strlen(ipaddr);
1531         return (strchr(token, *p) != NULL);
1532     }
1533 
1534     if (strchr(token, *--p) != NULL)
1535     {
1536         p += strlen(ipaddr) + 1;
1537         return (strchr(token, *p) != NULL);
1538     }
1539 
1540     return FALSE;
1541 }
1542 
1543 #ifndef NO_WSAACEPT
isAddrOKCallback(LPWSABUF lpCallerId,LPWSABUF dc0,LPQOS dc1,LPQOS dc2,LPWSABUF dc3,LPWSABUF dc4,GROUP * dc5,DWORD data)1544 static int CALLBACK isAddrOKCallback(LPWSABUF  lpCallerId,
1545                                      LPWSABUF  dc0,
1546                                      LPQOS     dc1,
1547                                      LPQOS     dc2,
1548                                      LPWSABUF  dc3,
1549                                      LPWSABUF  dc4,
1550                                      GROUP     *dc5,
1551                                      DWORD     data)
1552 {
1553     struct sockaddr_in *sockaddr = (struct sockaddr_in *) lpCallerId->buf;
1554 
1555     // Touch the args to avoid warnings
1556     dc0 = NULL; dc1 = NULL; dc2 = NULL; dc3 = NULL; dc4 = NULL; dc5 = NULL;
1557 
1558     if ((void *) data == NULL) return CF_ACCEPT;
1559 
1560     if (sockaddr->sin_family != AF_INET) return CF_ACCEPT;
1561 
1562     return isAddrOK(sockaddr, (const char *) data) ? CF_ACCEPT : CF_REJECT;
1563 }
1564 #endif
1565 
printLastError(const char * text)1566 static void printLastError(const char * text)
1567 {
1568     LPVOID buf;
1569 
1570     FormatMessage(
1571         FORMAT_MESSAGE_ALLOCATE_BUFFER |
1572         FORMAT_MESSAGE_FROM_SYSTEM |
1573         FORMAT_MESSAGE_IGNORE_INSERTS,
1574         NULL,
1575         GetLastError(),
1576         0,
1577         (LPTSTR) &buf,
1578         0,
1579         NULL
1580     );
1581 
1582     fprintf(stderr, "%s: %s\n", text, (LPCTSTR) buf);
1583     LocalFree(buf);
1584 }
1585 
acceptNamedPipe()1586 static int acceptNamedPipe()
1587 {
1588     int ipcFd = -1;
1589 
1590     if (! ConnectNamedPipe(hListen, NULL))
1591     {
1592         switch (GetLastError())
1593         {
1594             case ERROR_PIPE_CONNECTED:
1595 
1596                 // A client connected after CreateNamedPipe but
1597                 // before ConnectNamedPipe. Its a good connection.
1598 
1599                 break;
1600 
1601             case ERROR_IO_PENDING:
1602 
1603                 // The NamedPipe was opened with an Overlapped structure
1604                 // and there is a pending io operation.  mod_fastcgi
1605                 // did this in 2.2.12 (fcgi_pm.c v1.52).
1606 
1607             case ERROR_PIPE_LISTENING:
1608 
1609                 // The pipe handle is in nonblocking mode.
1610 
1611             case ERROR_NO_DATA:
1612 
1613                 // The previous client closed its handle (and we failed
1614                 // to call DisconnectNamedPipe)
1615 
1616             default:
1617 
1618                 printLastError("unexpected ConnectNamedPipe() error");
1619         }
1620     }
1621 
1622     ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1);
1623 	if (ipcFd == -1)
1624     {
1625         DisconnectNamedPipe(hListen);
1626     }
1627 
1628     return ipcFd;
1629 }
1630 
acceptSocket(const char * webServerAddrs)1631 static int acceptSocket(const char *webServerAddrs)
1632 {
1633     SOCKET hSock;
1634     int ipcFd = -1;
1635 
1636     for (;;)
1637     {
1638         struct sockaddr sockaddr;
1639         int sockaddrLen = sizeof(sockaddr);
1640 
1641         for (;;)
1642         {
1643             const struct timeval timeout = {1, 0};
1644             fd_set readfds;
1645 
1646             FD_ZERO(&readfds);
1647 
1648 #pragma warning( disable : 4127 )
1649             FD_SET((unsigned int) hListen, &readfds);
1650 #pragma warning( default : 4127 )
1651 
1652             if (select(0, &readfds, NULL, NULL, &timeout) == 0)
1653             {
1654                 if (shutdownPending)
1655                 {
1656                     OS_LibShutdown();
1657                     return -1;
1658                 }
1659             }
1660             else
1661             {
1662                 break;
1663             }
1664         }
1665 
1666 #if NO_WSAACEPT
1667         hSock = accept((SOCKET) hListen, &sockaddr, &sockaddrLen);
1668 
1669         if (hSock == INVALID_SOCKET)
1670         {
1671             break;
1672         }
1673 
1674         if (isAddrOK((struct sockaddr_in *) &sockaddr, webServerAddrs))
1675         {
1676             break;
1677         }
1678 
1679         closesocket(hSock);
1680 #else
1681         hSock = WSAAccept((unsigned int) hListen,
1682                           &sockaddr,
1683                           &sockaddrLen,
1684                           isAddrOKCallback,
1685                           (DWORD) webServerAddrs);
1686 
1687         if (hSock != INVALID_SOCKET)
1688         {
1689             break;
1690         }
1691 
1692         if (WSAGetLastError() != WSAECONNREFUSED)
1693         {
1694             break;
1695         }
1696 #endif
1697     }
1698 
1699     if (hSock == INVALID_SOCKET)
1700     {
1701         /* Use FormatMessage() */
1702         fprintf(stderr, "accept()/WSAAccept() failed: %d", WSAGetLastError());
1703         return -1;
1704     }
1705 
1706     ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1);
1707 	if (ipcFd == -1)
1708     {
1709 	    closesocket(hSock);
1710 	}
1711 
1712     return ipcFd;
1713 }
1714 
1715 /*
1716  *----------------------------------------------------------------------
1717  *
1718  * OS_Accept --
1719  *
1720  *  Accepts a new FastCGI connection.  This routine knows whether
1721  *  we're dealing with TCP based sockets or NT Named Pipes for IPC.
1722  *
1723  *  fail_on_intr is ignored in the Win lib.
1724  *
1725  * Results:
1726  *      -1 if the operation fails, otherwise this is a valid IPC fd.
1727  *
1728  *----------------------------------------------------------------------
1729  */
OS_Accept(int listen_sock,int fail_on_intr,const char * webServerAddrs)1730 int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
1731 {
1732     int ipcFd = -1;
1733 
1734     // Touch args to prevent warnings
1735     listen_sock = 0; fail_on_intr = 0;
1736 
1737     // @todo Muliple listen sockets and sockets other than 0 are not
1738     // supported due to the use of globals.
1739 
1740     if (shutdownPending)
1741     {
1742         OS_LibShutdown();
1743         return -1;
1744     }
1745 
1746     // The mutex is to keep other processes (and threads, when supported)
1747     // from going into the accept cycle.  The accept cycle needs to
1748     // periodically break out to check the state of the shutdown flag
1749     // and there's no point to having more than one thread do that.
1750 
1751     if (acceptMutex != INVALID_HANDLE_VALUE)
1752     {
1753         if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED)
1754         {
1755             printLastError("WaitForSingleObject() failed");
1756             return -1;
1757         }
1758     }
1759 
1760     if (shutdownPending)
1761     {
1762         OS_LibShutdown();
1763     }
1764     else if (listenType == FD_PIPE_SYNC)
1765     {
1766         ipcFd = acceptNamedPipe();
1767     }
1768     else if (listenType == FD_SOCKET_SYNC)
1769     {
1770         ipcFd = acceptSocket(webServerAddrs);
1771     }
1772     else
1773     {
1774         fprintf(stderr, "unknown listenType (%d)\n", listenType);
1775     }
1776 
1777     if (acceptMutex != INVALID_HANDLE_VALUE)
1778     {
1779         ReleaseMutex(acceptMutex);
1780     }
1781 
1782     return ipcFd;
1783 }
1784 
1785 /*
1786  *----------------------------------------------------------------------
1787  *
1788  * OS_IpcClose
1789  *
1790  *	OS IPC routine to close an IPC connection.
1791  *
1792  * Results:
1793  *
1794  *
1795  * Side effects:
1796  *      IPC connection is closed.
1797  *
1798  *----------------------------------------------------------------------
1799  */
OS_IpcClose(int ipcFd,int shutdown)1800 int OS_IpcClose(int ipcFd, int shutdown)
1801 {
1802     if (ipcFd == -1) return 0;
1803 
1804     /*
1805      * Catch it if fd is a bogus value
1806      */
1807     ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX));
1808     ASSERT(fdTable[ipcFd].type != FD_UNUSED);
1809 
1810     switch (listenType)
1811     {
1812     case FD_PIPE_SYNC:
1813 	    /*
1814 	     * Make sure that the client (ie. a Web Server in this case) has
1815 	     * read all data from the pipe before we disconnect.
1816 	     */
1817 	    if (! FlushFileBuffers(fdTable[ipcFd].fid.fileHandle)) return -1;
1818 
1819 	    if (! DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) return -1;
1820 
1821         /* fall through */
1822 
1823     case FD_SOCKET_SYNC:
1824 
1825 	    OS_Close(ipcFd, shutdown);
1826 	    break;
1827 
1828     case FD_UNUSED:
1829     default:
1830 
1831 	    exit(106);
1832 	    break;
1833     }
1834 
1835     return 0;
1836 }
1837 
1838 /*
1839  *----------------------------------------------------------------------
1840  *
1841  * OS_IsFcgi --
1842  *
1843  *	Determines whether this process is a FastCGI process or not.
1844  *
1845  * Results:
1846  *      Returns 1 if FastCGI, 0 if not.
1847  *
1848  * Side effects:
1849  *      None.
1850  *
1851  *----------------------------------------------------------------------
1852  */
OS_IsFcgi(int sock)1853 int OS_IsFcgi(int sock)
1854 {
1855     // Touch args to prevent warnings
1856     sock = 0;
1857 
1858     /* XXX This is broken for sock */
1859 
1860 	return (listenType != FD_UNUSED);
1861 }
1862 
1863 /*
1864  *----------------------------------------------------------------------
1865  *
1866  * OS_SetFlags --
1867  *
1868  *      Sets selected flag bits in an open file descriptor.  Currently
1869  *      this is only to put a SOCKET into non-blocking mode.
1870  *
1871  *----------------------------------------------------------------------
1872  */
OS_SetFlags(int fd,int flags)1873 void OS_SetFlags(int fd, int flags)
1874 {
1875     unsigned long pLong = 1L;
1876     int err;
1877 
1878     if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) {
1879         if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) ==
1880 	    SOCKET_ERROR) {
1881 	    exit(WSAGetLastError());
1882         }
1883         if (!CreateIoCompletionPort((HANDLE)fdTable[fd].fid.sock,
1884 				    hIoCompPort, fd, 1)) {
1885 	    err = GetLastError();
1886 	    exit(err);
1887 	}
1888 
1889         fdTable[fd].type = FD_SOCKET_ASYNC;
1890     }
1891     return;
1892 }
1893 
1894