5 * Copyright (c) 1995 Open Market, Inc.
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.
14 * snapper@openmarket.com
16 * (Special thanks to Karen and Bill. They made my job much easier and
17 * significantly more enjoyable.)
20 static const char rcsid[] = "$Id: os_win32.c,v 1.11 2001/03/27 14:03:21 robs Exp $";
23 #include "fcgi_config.h"
25 #define DLLAPI __declspec(dllexport)
29 #include <sys/timeb.h>
37 #define WIN32_OPEN_MAX 128 /* XXX: Small hack */
39 #define MUTEX_VARNAME "_FCGI_MUTEX_"
40 #define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_"
41 #define LOCALHOST "localhost"
43 static HANDLE hIoCompPort = INVALID_HANDLE_VALUE;
44 static HANDLE hStdinCompPort = INVALID_HANDLE_VALUE;
45 static HANDLE hStdinThread = INVALID_HANDLE_VALUE;
47 static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
48 INVALID_HANDLE_VALUE};
50 static HANDLE acceptMutex = INVALID_HANDLE_VALUE;
52 static BOOLEAN shutdownPending = FALSE;
55 * An enumeration of the file types
56 * supported by the FD_TABLE structure.
58 * XXX: Not all currently supported. This allows for future
78 * Structure used to map file handle and socket handle
79 * values into values that can be used to create unix-like
80 * select bitmaps, read/write for both sockets/files.
87 unsigned long instance;
89 int offset; /* only valid for async file writes */
90 LPDWORD offsetHighPtr; /* pointers to offset high and low words */
91 LPDWORD offsetLowPtr; /* only valid for async file writes (logs) */
92 HANDLE hMapMutex; /* mutex handle for multi-proc offset update */
93 LPVOID ovList; /* List of associated OVERLAPPED_REQUESTs */
96 typedef struct FD_TABLE *PFD_TABLE;
99 * XXX Note there is no dyanmic sizing of this table, so if the
100 * number of open file descriptors exceeds WIN32_OPEN_MAX the
103 static struct FD_TABLE fdTable[WIN32_OPEN_MAX];
105 struct OVERLAPPED_REQUEST {
106 OVERLAPPED overlapped;
107 unsigned long instance; /* file instance (won't match after a close) */
108 OS_AsyncProc procPtr; /* callback routine */
109 ClientData clientData; /* callback argument */
110 ClientData clientData1; /* additional clientData */
112 typedef struct OVERLAPPED_REQUEST *POVERLAPPED_REQUEST;
114 static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\";
116 static enum FILE_TYPE listenType = FD_UNUSED;
118 // XXX This should be a DESCRIPTOR
119 static HANDLE hListen = INVALID_HANDLE_VALUE;
121 static OVERLAPPED listenOverlapped;
122 static BOOLEAN libInitialized = FALSE;
125 *--------------------------------------------------------------
127 * Win32NewDescriptor --
129 * Set up for I/O descriptor masquerading.
132 * Returns "fake id" which masquerades as a UNIX-style "small
133 * non-negative integer" file/socket descriptor.
134 * Win32_* routine below will "do the right thing" based on the
135 * descriptor's actual type. -1 indicates failure.
138 * Entry in fdTable is reserved to represent the socket/file.
140 *--------------------------------------------------------------
142 static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd)
147 * If the "desiredFd" is not -1, try to get this entry for our
148 * pseudo file descriptor. If this is not available, return -1
149 * as the caller wanted to get this mapping. This is typically
150 * only used for mapping stdio handles.
152 if (desiredFd >= 0 && desiredFd < WIN32_OPEN_MAX)
154 if (fdTable[desiredFd].type != FD_UNUSED)
162 // See if the entry that matches "fd" is available.
164 if (fd <= 0 || fd >= WIN32_OPEN_MAX)
169 if (fdTable[fd].type == FD_UNUSED)
175 // Find an entry we can use.
176 // Start at 1 (0 fake id fails in some cases).
178 for (index = 1; index < WIN32_OPEN_MAX; index++)
180 if (fdTable[index].type == FD_UNUSED)
186 if (index == WIN32_OPEN_MAX)
188 SetLastError(WSAEMFILE);
194 fdTable[index].fid.value = fd;
195 fdTable[index].type = type;
196 fdTable[index].path = NULL;
197 fdTable[index].Errno = NO_ERROR;
198 fdTable[index].status = 0;
199 fdTable[index].offset = -1;
200 fdTable[index].offsetHighPtr = fdTable[index].offsetLowPtr = NULL;
201 fdTable[index].hMapMutex = NULL;
202 fdTable[index].ovList = NULL;
208 *--------------------------------------------------------------
212 * This thread performs I/O on stadard input. It is needed
213 * because you can't guarantee that all applications will
214 * create standard input with sufficient access to perform
215 * asynchronous I/O. Since we don't want to block the app
216 * reading from stdin we make it look like it's using I/O
217 * completion ports to perform async I/O.
220 * Data is read from stdin and posted to the io completion
226 *--------------------------------------------------------------
228 static void StdinThread(LPDWORD startup){
233 POVERLAPPED_REQUEST pOv;
237 * Block until a request to read from stdin comes in or a
238 * request to terminate the thread arrives (fd = -1).
240 if (!GetQueuedCompletionStatus(hStdinCompPort, &bytesRead, &fd,
241 (LPOVERLAPPED *)&pOv, (DWORD)-1) && !pOv) {
246 ASSERT((fd == STDIN_FILENO) || (fd == -1));
251 ASSERT(pOv->clientData1 != NULL);
253 if(ReadFile(stdioHandles[STDIN_FILENO], pOv->clientData1, bytesRead,
255 PostQueuedCompletionStatus(hIoCompPort, bytesRead,
256 STDIN_FILENO, (LPOVERLAPPED)pOv);
266 static DWORD WINAPI ShutdownRequestThread(LPVOID arg)
268 HANDLE shutdownEvent = (HANDLE) arg;
270 if (WaitForSingleObject(shutdownEvent, INFINITE) == WAIT_FAILED)
272 // Assuming it will happen again, all we can do is exit the thread
277 // "Simple reads and writes to properly-aligned 32-bit variables are atomic"
278 shutdownPending = TRUE;
280 // Before an accept() is entered the shutdownPending flag is checked.
281 // If set, OS_Accept() will return -1. If not, it waits
282 // on a connection request for one second, checks the flag, & repeats.
283 // Only one process/thread is allowed to do this at time by
284 // wrapping the accept() with mutex.
290 *--------------------------------------------------------------
294 * Set up the OS library for use.
297 * Returns 0 if success, -1 if not.
300 * Sockets initialized, pseudo file descriptors setup, etc.
302 *--------------------------------------------------------------
304 int OS_LibInit(int stdioFds[3])
311 char *cLenPtr = NULL;
318 * Initialize windows sockets library.
320 wVersion = MAKEWORD(2,0);
321 err = WSAStartup( wVersion, &wsaData );
323 fprintf(stderr, "Error starting Windows Sockets. Error: %d",
329 * Create the I/O completion port to be used for our I/O queue.
331 if (hIoCompPort == INVALID_HANDLE_VALUE) {
332 hIoCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
334 if(hIoCompPort == INVALID_HANDLE_VALUE) {
335 printf("<H2>OS_LibInit Failed CreateIoCompletionPort! ERROR: %d</H2>\r\n\r\n",
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.
346 val = getenv(SHUTDOWN_EVENT_NAME);
349 HANDLE shutdownEvent = (HANDLE) atoi(val);
351 putenv(SHUTDOWN_EVENT_NAME"=");
353 if (! CreateThread(NULL, 0, ShutdownRequestThread,
354 shutdownEvent, 0, NULL))
361 * If an accept mutex is in the env, save it and remove it.
363 val = getenv(MUTEX_VARNAME);
366 acceptMutex = (HANDLE) atoi(val);
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.
377 * The trick is determining if this is a pipe or a socket...
379 * XXX: Add the async accept test to determine socket or handle to a
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) )
386 DWORD pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT;
387 HANDLE oldStdIn = GetStdHandle(STD_INPUT_HANDLE);
389 // Move the handle to a "low" number
390 if (! DuplicateHandle(GetCurrentProcess(), oldStdIn,
391 GetCurrentProcess(), &hListen,
392 0, TRUE, DUPLICATE_SAME_ACCESS))
397 if (! SetStdHandle(STD_INPUT_HANDLE, hListen))
402 CloseHandle(oldStdIn);
405 * Set the pipe handle state so that it operates in wait mode.
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.
410 * XXX: Initial assumption is that SetNamedPipeHandleState will
411 * fail if this is an IP socket...
413 if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL))
415 listenType = FD_PIPE_SYNC;
416 listenOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
420 listenType = FD_SOCKET_SYNC;
425 * If there are no stdioFds passed in, we're done.
427 if(stdioFds == NULL) {
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.
444 stdioHandles[STDIN_FILENO] = GetStdHandle(STD_INPUT_HANDLE);
446 if(!SetHandleInformation(stdioHandles[STDIN_FILENO],
447 HANDLE_FLAG_INHERIT, 0)) {
449 * XXX: Causes error when run from command line. Check KB
450 err = GetLastError();
456 if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
457 (int)stdioHandles[STDIN_FILENO],
458 STDIN_FILENO)) == -1) {
462 * Set stdin equal to our pseudo FD and create the I/O completion
463 * port to be used for async I/O.
465 stdioFds[STDIN_FILENO] = fakeFd;
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.
473 if (hStdinCompPort == INVALID_HANDLE_VALUE) {
474 hStdinCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
476 if(hStdinCompPort == INVALID_HANDLE_VALUE) {
477 printf("<H2>OS_LibInit Failed CreateIoCompletionPort: STDIN! ERROR: %d</H2>\r\n\r\n",
484 * Create the thread that will read stdin if the CONTENT_LENGTH
487 if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL &&
489 hStdinThread = CreateThread(NULL, 8192,
490 (LPTHREAD_START_ROUTINE)&StdinThread,
492 if (hStdinThread == NULL) {
493 printf("<H2>OS_LibInit Failed to create STDIN thread! ERROR: %d</H2>\r\n\r\n",
500 * STDOUT will be used synchronously.
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.
506 stdioHandles[STDOUT_FILENO] = GetStdHandle(STD_OUTPUT_HANDLE);
507 if(!SetHandleInformation(stdioHandles[STDOUT_FILENO],
508 HANDLE_FLAG_INHERIT, FALSE)) {
513 if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
514 (int)stdioHandles[STDOUT_FILENO],
515 STDOUT_FILENO)) == -1) {
519 * Set stdout equal to our pseudo FD
521 stdioFds[STDOUT_FILENO] = fakeFd;
524 stdioHandles[STDERR_FILENO] = GetStdHandle(STD_ERROR_HANDLE);
525 if(!SetHandleInformation(stdioHandles[STDERR_FILENO],
526 HANDLE_FLAG_INHERIT, FALSE)) {
530 if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
531 (int)stdioHandles[STDERR_FILENO],
532 STDERR_FILENO)) == -1) {
536 * Set stderr equal to our pseudo FD
538 stdioFds[STDERR_FILENO] = fakeFd;
545 *--------------------------------------------------------------
549 * Shutdown the OS library.
555 * Memory freed, handles closed.
557 *--------------------------------------------------------------
559 void OS_LibShutdown()
562 if(hIoCompPort != INVALID_HANDLE_VALUE) {
563 CloseHandle(hIoCompPort);
564 hIoCompPort = INVALID_HANDLE_VALUE;
567 if(hStdinCompPort != INVALID_HANDLE_VALUE) {
568 CloseHandle(hStdinCompPort);
569 hStdinCompPort = INVALID_HANDLE_VALUE;
573 * Shutdown the socket library.
580 *--------------------------------------------------------------
582 * Win32FreeDescriptor --
584 * Free I/O descriptor entry in fdTable.
587 * Frees I/O descriptor entry in fdTable.
592 *--------------------------------------------------------------
594 static void Win32FreeDescriptor(int fd)
596 /* Catch it if fd is a bogus value */
597 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
598 ASSERT(fdTable[fd].type != FD_UNUSED);
600 switch (fdTable[fd].type) {
603 /* Free file path string */
604 ASSERT(fdTable[fd].path != NULL);
605 free(fdTable[fd].path);
606 fdTable[fd].path = NULL;
610 * Break through to generic fdTable free-descriptor code
615 ASSERT(fdTable[fd].path == NULL);
616 fdTable[fd].type = FD_UNUSED;
617 fdTable[fd].path = NULL;
618 fdTable[fd].Errno = NO_ERROR;
619 fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL;
620 if (fdTable[fd].hMapMutex != NULL) {
621 CloseHandle(fdTable[fd].hMapMutex);
622 fdTable[fd].hMapMutex = NULL;
627 static short getPort(const char * bindPath)
630 char * p = strchr(bindPath, ':');
646 * OS_CreateLocalIpcFd --
648 * This procedure is responsible for creating the listener pipe
649 * on Windows NT for local process communication. It will create a
650 * named pipe and return a file descriptor to it to the caller.
653 * Listener pipe created. This call returns either a valid
654 * pseudo file descriptor or -1 on error.
657 * Listener pipe and IPC address are stored in the FCGI info
659 * 'errno' will set on errors (-1 is returned).
661 *----------------------------------------------------------------------
663 int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
666 short port = getPort(bindPath);
667 HANDLE mutex = CreateMutex(NULL, FALSE, NULL);
668 char * mutexEnvString;
675 if (! SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE))
680 // This is a nail for listening to more than one port..
681 // This should really be handled by the caller.
683 mutexEnvString = malloc(strlen(MUTEX_VARNAME) + 7);
684 sprintf(mutexEnvString, MUTEX_VARNAME "=%d", (int) mutex);
685 putenv(mutexEnvString);
687 // There's nothing to be gained (at the moment) by a shutdown Event
689 if (port && *bindPath != ':' && strncmp(bindPath, LOCALHOST, strlen(LOCALHOST)))
691 fprintf(stderr, "To start a service on a TCP port can not "
692 "specify a host name.\n"
693 "You should either use \"localhost:<port>\" or "
694 " just use \":<port>.\"\n");
698 listenType = (port) ? FD_SOCKET_SYNC : FD_PIPE_ASYNC;
703 struct sockaddr_in sockAddr;
704 int sockLen = sizeof(sockAddr);
706 memset(&sockAddr, 0, sizeof(sockAddr));
707 sockAddr.sin_family = AF_INET;
708 sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
709 sockAddr.sin_port = htons(port);
711 listenSock = socket(AF_INET, SOCK_STREAM, 0);
712 if (listenSock == INVALID_SOCKET)
717 if (! bind(listenSock, (struct sockaddr *) &sockAddr, sockLen)
718 || ! listen(listenSock, backlog))
723 pseudoFd = Win32NewDescriptor(listenType, listenSock, -1);
727 closesocket(listenSock);
731 hListen = (HANDLE) listenSock;
735 HANDLE hListenPipe = INVALID_HANDLE_VALUE;
736 char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
743 strcpy(pipePath, bindPathPrefix);
744 strcat(pipePath, bindPath);
746 hListenPipe = CreateNamedPipe(pipePath,
747 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
748 PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
749 PIPE_UNLIMITED_INSTANCES,
750 4096, 4096, 0, NULL);
754 if (hListenPipe == INVALID_HANDLE_VALUE)
759 if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE))
764 pseudoFd = Win32NewDescriptor(listenType, (int) hListenPipe, -1);
768 CloseHandle(hListenPipe);
772 hListen = (HANDLE) hListenPipe;
779 *----------------------------------------------------------------------
783 * Create the pipe pathname connect to the remote application if
787 * -1 if fail or a valid handle if connection succeeds.
790 * Remote connection established.
792 *----------------------------------------------------------------------
794 int OS_FcgiConnect(char *bindPath)
796 short port = getPort(bindPath);
803 struct sockaddr_in sockAddr;
804 int sockLen = sizeof(sockAddr);
807 if (*bindPath != ':')
809 char * p = strchr(bindPath, ':');
810 int len = p - bindPath + 1;
813 strncpy(host, bindPath, len);
817 hp = gethostbyname(host ? host : LOCALHOST);
826 fprintf(stderr, "Unknown host: %s\n", bindPath);
830 memset(&sockAddr, 0, sizeof(sockAddr));
831 sockAddr.sin_family = AF_INET;
832 memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length);
833 sockAddr.sin_port = htons(port);
835 sock = socket(AF_INET, SOCK_STREAM, 0);
836 if (sock == INVALID_SOCKET)
841 if (! connect(sock, (struct sockaddr *) &sockAddr, sockLen))
847 pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, sock, -1);
856 char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
864 strcpy(pipePath, bindPathPrefix);
865 strcat(pipePath, bindPath);
867 hPipe = CreateFile(pipePath,
868 GENERIC_WRITE | GENERIC_READ,
869 FILE_SHARE_READ | FILE_SHARE_WRITE,
872 FILE_FLAG_OVERLAPPED,
877 if( hPipe == INVALID_HANDLE_VALUE)
882 pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int) hPipe, -1);
891 * Set stdin equal to our pseudo FD and create the I/O completion
892 * port to be used for async I/O.
894 if (! CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1))
896 Win32FreeDescriptor(pseudoFd);
906 *--------------------------------------------------------------
910 * Pass through to the appropriate NT read function.
913 * Returns number of byes read. Mimics unix read:.
914 * n bytes read, 0 or -1 failure: errno contains actual error
919 *--------------------------------------------------------------
921 int OS_Read(int fd, char * buf, size_t len)
927 * Catch any bogus fd values
929 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
931 switch (fdTable[fd].type) {
938 * ReadFile returns: TRUE success, FALSE failure
940 if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead,
942 fdTable[fd].Errno = GetLastError();
948 case FD_SOCKET_ASYNC:
949 /* winsock recv returns n bytes recv'ed, SOCKET_ERROR failure */
951 * XXX: Test this with ReadFile. If it works, remove this code
952 * to simplify the routine.
954 if ((ret = recv(fdTable[fd].fid.sock, buf, len, 0)) ==
956 fdTable[fd].Errno = WSAGetLastError();
966 *--------------------------------------------------------------
970 * Perform a synchronous OS write.
973 * Returns number of bytes written. Mimics unix write:
974 * n bytes written, 0 or -1 failure (??? couldn't find man page).
979 *--------------------------------------------------------------
981 int OS_Write(int fd, char * buf, size_t len)
987 * Catch any bogus fd values
989 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
990 ASSERT((fdTable[fd].type > FD_UNUSED) &&
991 (fdTable[fd].type <= FD_PIPE_ASYNC));
993 switch (fdTable[fd].type) {
1000 * WriteFile returns: TRUE success, FALSE failure
1002 if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len,
1003 &bytesWritten, NULL)) {
1004 fdTable[fd].Errno = GetLastError();
1007 return bytesWritten;
1008 case FD_SOCKET_SYNC:
1009 case FD_SOCKET_ASYNC:
1010 /* winsock send returns n bytes written, SOCKET_ERROR failure */
1012 * XXX: Test this with WriteFile. If it works, remove this code
1013 * to simplify the routine.
1015 if ((ret = send(fdTable[fd].fid.sock, buf, len, 0)) ==
1017 fdTable[fd].Errno = WSAGetLastError();
1027 *----------------------------------------------------------------------
1031 * Spawns a new server listener process, and stores the information
1032 * relating to the child in the supplied record. A wait handler is
1033 * registered on the child's completion. This involves creating
1034 * a process on NT and preparing a command line with the required
1035 * state (currently a -childproc flag and the server socket to use
1036 * for accepting connections).
1039 * 0 if success, -1 if error.
1042 * Child process spawned.
1044 *----------------------------------------------------------------------
1046 int OS_SpawnChild(char *execPath, int listenFd)
1048 STARTUPINFO StartupInfo;
1049 PROCESS_INFORMATION pInfo;
1052 memset((void *)&StartupInfo, 0, sizeof(STARTUPINFO));
1053 StartupInfo.cb = sizeof (STARTUPINFO);
1054 StartupInfo.lpReserved = NULL;
1055 StartupInfo.lpReserved2 = NULL;
1056 StartupInfo.cbReserved2 = 0;
1057 StartupInfo.lpDesktop = NULL;
1060 * FastCGI on NT will set the listener pipe HANDLE in the stdin of
1061 * the new process. The fact that there is a stdin and NULL handles
1062 * for stdout and stderr tells the FastCGI process that this is a
1063 * FastCGI process and not a CGI process.
1065 StartupInfo.dwFlags = STARTF_USESTDHANDLES;
1067 * XXX: Do I have to dup the handle before spawning the process or is
1068 * it sufficient to use the handle as it's reference counted
1071 StartupInfo.hStdInput = fdTable[listenFd].fid.fileHandle;
1072 StartupInfo.hStdOutput = INVALID_HANDLE_VALUE;
1073 StartupInfo.hStdError = INVALID_HANDLE_VALUE;
1076 * Make the listener socket inheritable.
1078 success = SetHandleInformation(StartupInfo.hStdInput, HANDLE_FLAG_INHERIT,
1085 * XXX: Might want to apply some specific security attributes to the
1088 success = CreateProcess(execPath, /* LPCSTR address of module name */
1089 NULL, /* LPCSTR address of command line */
1090 NULL, /* Process security attributes */
1091 NULL, /* Thread security attributes */
1092 TRUE, /* Inheritable Handes inherited. */
1093 0, /* DWORD creation flags */
1094 NULL, /* Use parent environment block */
1095 NULL, /* Address of current directory name */
1096 &StartupInfo, /* Address of STARTUPINFO */
1097 &pInfo); /* Address of PROCESS_INFORMATION */
1106 *--------------------------------------------------------------
1108 * OS_AsyncReadStdin --
1110 * This initiates an asynchronous read on the standard
1111 * input handle. This handle is not guaranteed to be
1112 * capable of performing asynchronous I/O so we send a
1113 * message to the StdinThread to do the synchronous read.
1116 * -1 if error, 0 otherwise.
1119 * Asynchronous message is queued to the StdinThread and an
1120 * overlapped structure is allocated/initialized.
1122 *--------------------------------------------------------------
1124 int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr,
1125 ClientData clientData)
1127 POVERLAPPED_REQUEST pOv;
1129 ASSERT(fdTable[STDIN_FILENO].type != FD_UNUSED);
1131 pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1133 memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1134 pOv->clientData1 = (ClientData)buf;
1135 pOv->instance = fdTable[STDIN_FILENO].instance;
1136 pOv->procPtr = procPtr;
1137 pOv->clientData = clientData;
1139 PostQueuedCompletionStatus(hStdinCompPort, len, STDIN_FILENO,
1145 *--------------------------------------------------------------
1149 * This initiates an asynchronous read on the file
1150 * handle which may be a socket or named pipe.
1152 * We also must save the ProcPtr and ClientData, so later
1153 * when the io completes, we know who to call.
1155 * We don't look at any results here (the ReadFile may
1156 * return data if it is cached) but do all completion
1157 * processing in OS_Select when we get the io completion
1158 * port done notifications. Then we call the callback.
1161 * -1 if error, 0 otherwise.
1164 * Asynchronous I/O operation is queued for completion.
1166 *--------------------------------------------------------------
1168 int OS_AsyncRead(int fd, int offset, void *buf, int len,
1169 OS_AsyncProc procPtr, ClientData clientData)
1172 POVERLAPPED_REQUEST pOv;
1175 * Catch any bogus fd values
1177 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1179 * Confirm that this is an async fd
1181 ASSERT(fdTable[fd].type != FD_UNUSED);
1182 ASSERT(fdTable[fd].type != FD_FILE_SYNC);
1183 ASSERT(fdTable[fd].type != FD_PIPE_SYNC);
1184 ASSERT(fdTable[fd].type != FD_SOCKET_SYNC);
1186 pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1188 memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1190 * Only file offsets should be non-zero, but make sure.
1192 if (fdTable[fd].type == FD_FILE_ASYNC)
1193 if (fdTable[fd].offset >= 0)
1194 pOv->overlapped.Offset = fdTable[fd].offset;
1196 pOv->overlapped.Offset = offset;
1197 pOv->instance = fdTable[fd].instance;
1198 pOv->procPtr = procPtr;
1199 pOv->clientData = clientData;
1202 * ReadFile returns: TRUE success, FALSE failure
1204 if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead,
1205 (LPOVERLAPPED)pOv)) {
1206 fdTable[fd].Errno = GetLastError();
1207 if(fdTable[fd].Errno == ERROR_NO_DATA ||
1208 fdTable[fd].Errno == ERROR_PIPE_NOT_CONNECTED) {
1209 PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1212 if(fdTable[fd].Errno != ERROR_IO_PENDING) {
1213 PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1216 fdTable[fd].Errno = 0;
1222 *--------------------------------------------------------------
1226 * This initiates an asynchronous write on the "fake" file
1227 * descriptor (which may be a file, socket, or named pipe).
1228 * We also must save the ProcPtr and ClientData, so later
1229 * when the io completes, we know who to call.
1231 * We don't look at any results here (the WriteFile generally
1232 * completes immediately) but do all completion processing
1233 * in OS_DoIo when we get the io completion port done
1234 * notifications. Then we call the callback.
1237 * -1 if error, 0 otherwise.
1240 * Asynchronous I/O operation is queued for completion.
1242 *--------------------------------------------------------------
1244 int OS_AsyncWrite(int fd, int offset, void *buf, int len,
1245 OS_AsyncProc procPtr, ClientData clientData)
1248 POVERLAPPED_REQUEST pOv;
1251 * Catch any bogus fd values
1253 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1255 * Confirm that this is an async fd
1257 ASSERT(fdTable[fd].type != FD_UNUSED);
1258 ASSERT(fdTable[fd].type != FD_FILE_SYNC);
1259 ASSERT(fdTable[fd].type != FD_PIPE_SYNC);
1260 ASSERT(fdTable[fd].type != FD_SOCKET_SYNC);
1262 pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1264 memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1266 * Only file offsets should be non-zero, but make sure.
1268 if (fdTable[fd].type == FD_FILE_ASYNC)
1270 * Only file opened via OS_AsyncWrite with
1271 * O_APPEND will have an offset != -1.
1273 if (fdTable[fd].offset >= 0)
1275 * If the descriptor has a memory mapped file
1276 * handle, take the offsets from there.
1278 if (fdTable[fd].hMapMutex != NULL) {
1280 * Wait infinitely; this *should* not cause problems.
1282 WaitForSingleObject(fdTable[fd].hMapMutex, INFINITE);
1285 * Retrieve the shared offset values.
1287 pOv->overlapped.OffsetHigh = *(fdTable[fd].offsetHighPtr);
1288 pOv->overlapped.Offset = *(fdTable[fd].offsetLowPtr);
1291 * Update the shared offset values for the next write
1293 *(fdTable[fd].offsetHighPtr) += 0; /* XXX How do I handle overflow */
1294 *(fdTable[fd].offsetLowPtr) += len;
1296 ReleaseMutex(fdTable[fd].hMapMutex);
1298 pOv->overlapped.Offset = fdTable[fd].offset;
1300 pOv->overlapped.Offset = offset;
1301 pOv->instance = fdTable[fd].instance;
1302 pOv->procPtr = procPtr;
1303 pOv->clientData = clientData;
1306 * WriteFile returns: TRUE success, FALSE failure
1308 if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten,
1309 (LPOVERLAPPED)pOv)) {
1310 fdTable[fd].Errno = GetLastError();
1311 if(fdTable[fd].Errno != ERROR_IO_PENDING) {
1312 PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1315 fdTable[fd].Errno = 0;
1317 if (fdTable[fd].offset >= 0)
1318 fdTable[fd].offset += len;
1323 *--------------------------------------------------------------
1327 * Closes the descriptor with routine appropriate for
1328 * descriptor's type.
1331 * Socket or file is closed. Return values mimic Unix close:
1332 * 0 success, -1 failure
1335 * Entry in fdTable is marked as free.
1337 *--------------------------------------------------------------
1339 int OS_Close(int fd)
1344 * Catch it if fd is a bogus value
1346 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1347 ASSERT(fdTable[fd].type != FD_UNUSED);
1349 switch (fdTable[fd].type) {
1356 case FD_SOCKET_SYNC:
1357 case FD_SOCKET_ASYNC:
1359 * Closing a socket that has an async read outstanding causes a
1360 * tcp reset and possible data loss. The shutdown call seems to
1363 shutdown(fdTable[fd].fid.sock, 2);
1365 * closesocket returns: 0 success, SOCKET_ERROR failure
1367 if (closesocket(fdTable[fd].fid.sock) == SOCKET_ERROR)
1371 return -1; /* fake failure */
1374 Win32FreeDescriptor(fd);
1379 *--------------------------------------------------------------
1383 * Cancel outstanding asynchronous reads and prevent subsequent
1384 * reads from completing.
1387 * Socket or file is shutdown. Return values mimic Unix shutdown:
1388 * 0 success, -1 failure
1390 *--------------------------------------------------------------
1392 int OS_CloseRead(int fd)
1397 * Catch it if fd is a bogus value
1399 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1400 ASSERT(fdTable[fd].type == FD_SOCKET_ASYNC
1401 || fdTable[fd].type == FD_SOCKET_SYNC);
1403 if (shutdown(fdTable[fd].fid.sock,0) == SOCKET_ERROR)
1409 *--------------------------------------------------------------
1413 * This function was formerly OS_Select. It's purpose is
1414 * to pull I/O completion events off the queue and dispatch
1415 * them to the appropriate place.
1421 * Handlers are called.
1423 *--------------------------------------------------------------
1425 int OS_DoIo(struct timeval *tmo)
1429 POVERLAPPED_REQUEST pOv;
1436 * We can loop in here, but not too long, as wait handlers
1438 * For cgi stdin, apparently select returns when io completion
1439 * ports don't, so don't wait the full timeout.
1442 ms = (tmo->tv_sec*1000 + tmo->tv_usec/1000) / 2;
1446 ms_last = tb.time*1000 + tb.millitm;
1448 if(tmo && (ms = tmo->tv_sec*1000 + tmo->tv_usec/1000)> 100)
1450 if (!GetQueuedCompletionStatus(hIoCompPort, &bytes, &fd,
1451 (LPOVERLAPPED *)&pOv, ms) && !pOv) {
1452 err = WSAGetLastError();
1453 return 0; /* timeout */
1456 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1457 /* call callback if descriptor still valid */
1459 if(pOv->instance == fdTable[fd].instance)
1460 (*pOv->procPtr)(pOv->clientData, bytes);
1464 ms -= (tb.time*1000 + tb.millitm - ms_last);
1465 ms_last = tb.time*1000 + tb.millitm;
1471 static int CALLBACK isAddrOK(LPWSABUF lpCallerId,
1478 DWORD dwCallbackData)
1480 const char *okAddrs = (char *) dwCallbackData;
1481 struct sockaddr *sockaddr = (struct sockaddr *) lpCallerId->buf;
1483 if (okAddrs == NULL || sockaddr->sa_family != AF_INET)
1489 static const char *token = " ,;:\t";
1490 struct sockaddr_in * inet_sockaddr = (struct sockaddr_in *) sockaddr;
1491 char *ipaddr = inet_ntoa(inet_sockaddr->sin_addr);
1492 char *p = strstr(okAddrs, ipaddr);
1498 else if (p == okAddrs)
1500 p += strlen(ipaddr);
1501 return (strchr(token, *p) != NULL);
1503 else if (strchr(token, *--p))
1505 p += strlen(ipaddr) + 1;
1506 return (strchr(token, *p) != NULL);
1516 *----------------------------------------------------------------------
1520 * Accepts a new FastCGI connection. This routine knows whether
1521 * we're dealing with TCP based sockets or NT Named Pipes for IPC.
1524 * -1 if the operation fails, otherwise this is a valid IPC fd.
1527 * New IPC connection is accepted.
1529 *----------------------------------------------------------------------
1531 int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
1533 /* XXX This is broken for listen_sock & fail_on_intr */
1538 if (shutdownPending)
1543 // The mutex is to keep other processes (and threads, when supported)
1544 // from going into the accept cycle. The accept cycle needs to
1545 // periodically break out to check the state of the shutdown flag
1546 // and there's no point to having more than one thread do that.
1548 if (acceptMutex != INVALID_HANDLE_VALUE)
1550 if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED)
1556 if (shutdownPending)
1558 if (acceptMutex != INVALID_HANDLE_VALUE)
1560 ReleaseMutex(acceptMutex);
1565 if (listenType == FD_PIPE_SYNC)
1567 pConnected = ConnectNamedPipe(hListen, &listenOverlapped)
1569 : (GetLastError() == ERROR_PIPE_CONNECTED);
1573 while (WaitForSingleObject(listenOverlapped.hEvent, 1000) == WAIT_TIMEOUT)
1575 if (shutdownPending)
1577 if (acceptMutex != INVALID_HANDLE_VALUE)
1579 ReleaseMutex(acceptMutex);
1587 if (acceptMutex != INVALID_HANDLE_VALUE)
1589 ReleaseMutex(acceptMutex);
1592 ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1);
1595 DisconnectNamedPipe(hListen);
1598 else if (listenType == FD_SOCKET_SYNC)
1600 struct sockaddr sockaddr;
1601 int sockaddrLen = sizeof(sockaddr);
1603 const struct timeval timeout = {1, 0};
1606 FD_SET((unsigned int) hListen, &readfds);
1608 while (select(0, &readfds, NULL, NULL, &timeout) == 0)
1610 if (shutdownPending)
1616 hSock = (webServerAddrs == NULL)
1617 ? accept((SOCKET) hListen,
1620 : WSAAccept((unsigned int) hListen,
1624 (DWORD) webServerAddrs);
1626 if (acceptMutex != INVALID_HANDLE_VALUE)
1628 ReleaseMutex(acceptMutex);
1636 ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1);
1651 *----------------------------------------------------------------------
1655 * OS IPC routine to close an IPC connection.
1661 * IPC connection is closed.
1663 *----------------------------------------------------------------------
1665 int OS_IpcClose(int ipcFd)
1671 * Catch it if fd is a bogus value
1673 ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX));
1674 ASSERT(fdTable[ipcFd].type != FD_UNUSED);
1676 switch(listenType) {
1680 * Make sure that the client (ie. a Web Server in this case) has
1681 * read all data from the pipe before we disconnect.
1683 if(!FlushFileBuffers(fdTable[ipcFd].fid.fileHandle))
1685 if(DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) {
1693 case FD_SOCKET_SYNC:
1706 *----------------------------------------------------------------------
1710 * Determines whether this process is a FastCGI process or not.
1713 * Returns 1 if FastCGI, 0 if not.
1718 *----------------------------------------------------------------------
1720 int OS_IsFcgi(int sock)
1722 /* XXX This is broken for sock */
1723 if(listenType == FD_UNUSED) {
1731 *----------------------------------------------------------------------
1735 * Sets selected flag bits in an open file descriptor. Currently
1736 * this is only to put a SOCKET into non-blocking mode.
1738 *----------------------------------------------------------------------
1740 void OS_SetFlags(int fd, int flags)
1742 unsigned long pLong = 1L;
1745 if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) {
1746 if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) ==
1748 exit(WSAGetLastError());
1750 if (!CreateIoCompletionPort((HANDLE)fdTable[fd].fid.sock,
1751 hIoCompPort, fd, 1)) {
1752 err = GetLastError();
1756 fdTable[fd].type = FD_SOCKET_ASYNC;