diff options
author | SVN Migration <svn@php.net> | 2003-02-27 17:43:39 +0000 |
---|---|---|
committer | SVN Migration <svn@php.net> | 2003-02-27 17:43:39 +0000 |
commit | 078bcec0997ad0e07b720c43cc9e6d0e046a75ab (patch) | |
tree | 36cb0f6be2ef078fe3374de8c087b93ecf82f812 /sapi/cgi/libfcgi/os_win32.c | |
parent | fd61f69077f6156ca71dde60ecfd9ed9765a02db (diff) | |
download | php-git-PHP-5.tar.gz |
This commit was manufactured by cvs2svn to create branch 'PHP_5'.PHP-5
Diffstat (limited to 'sapi/cgi/libfcgi/os_win32.c')
-rw-r--r-- | sapi/cgi/libfcgi/os_win32.c | 2067 |
1 files changed, 0 insertions, 2067 deletions
diff --git a/sapi/cgi/libfcgi/os_win32.c b/sapi/cgi/libfcgi/os_win32.c deleted file mode 100644 index 723ef81060..0000000000 --- a/sapi/cgi/libfcgi/os_win32.c +++ /dev/null @@ -1,2067 +0,0 @@ -/* - * os_win32.c -- - * - * - * Copyright (c) 1995 Open Market, Inc. - * All rights reserved. - * - * This file contains proprietary and confidential information and - * remains the unpublished property of Open Market, Inc. Use, - * disclosure, or reproduction is prohibited except as permitted by - * express written license agreement with Open Market, Inc. - * - * Bill Snapper - * snapper@openmarket.com - * - * (Special thanks to Karen and Bill. They made my job much easier and - * significantly more enjoyable.) - */ -#ifndef lint -static const char rcsid[] = "$Id$"; -#endif /* not lint */ - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <winsock2.h> -#include <stdlib.h> -#include <assert.h> -#include <stdio.h> -#include <sys/timeb.h> - -#define DLLAPI __declspec(dllexport) - -#include "fcgimisc.h" -#include "fcgios.h" - -#define WIN32_OPEN_MAX 128 /* XXX: Small hack */ - -/* - * millisecs to wait for a client connection before checking the - * shutdown flag (then go back to waiting for a connection, etc). - */ -#define ACCEPT_TIMEOUT 1000 - -#define LOCALHOST "localhost" - -static HANDLE hIoCompPort = INVALID_HANDLE_VALUE; -static HANDLE hStdinCompPort = INVALID_HANDLE_VALUE; -static HANDLE hStdinThread = INVALID_HANDLE_VALUE; - -static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, - INVALID_HANDLE_VALUE}; - -static HANDLE acceptMutex = INVALID_HANDLE_VALUE; - -static BOOLEAN shutdownPending = FALSE; -static BOOLEAN shutdownNow = FALSE; - -static BOOLEAN bImpersonate = FALSE; -/* - * An enumeration of the file types - * supported by the FD_TABLE structure. - * - * XXX: Not all currently supported. This allows for future - * functionality. - */ -typedef enum { - FD_UNUSED, - FD_FILE_SYNC, - FD_FILE_ASYNC, - FD_SOCKET_SYNC, - FD_SOCKET_ASYNC, - FD_PIPE_SYNC, - FD_PIPE_ASYNC -} FILE_TYPE; - -typedef union { - HANDLE fileHandle; - SOCKET sock; - unsigned int value; -} DESCRIPTOR; - -/* - * Structure used to map file handle and socket handle - * values into values that can be used to create unix-like - * select bitmaps, read/write for both sockets/files. - */ -struct FD_TABLE { - DESCRIPTOR fid; - FILE_TYPE type; - char *path; - DWORD Errno; - unsigned long instance; - int status; - int offset; /* only valid for async file writes */ - LPDWORD offsetHighPtr; /* pointers to offset high and low words */ - LPDWORD offsetLowPtr; /* only valid for async file writes (logs) */ - HANDLE hMapMutex; /* mutex handle for multi-proc offset update */ - LPVOID ovList; /* List of associated OVERLAPPED_REQUESTs */ -}; - -/* - * XXX Note there is no dyanmic sizing of this table, so if the - * number of open file descriptors exceeds WIN32_OPEN_MAX the - * app will blow up. - */ -static struct FD_TABLE fdTable[WIN32_OPEN_MAX]; - -static CRITICAL_SECTION fdTableCritical; - -struct OVERLAPPED_REQUEST { - OVERLAPPED overlapped; - unsigned long instance; /* file instance (won't match after a close) */ - OS_AsyncProc procPtr; /* callback routine */ - ClientData clientData; /* callback argument */ - ClientData clientData1; /* additional clientData */ -}; -typedef struct OVERLAPPED_REQUEST *POVERLAPPED_REQUEST; - -static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\"; - -static FILE_TYPE listenType = FD_UNUSED; - -// XXX This should be a DESCRIPTOR -static HANDLE hListen = INVALID_HANDLE_VALUE; - -static OVERLAPPED listenOverlapped; -static BOOLEAN libInitialized = FALSE; - -/* - *-------------------------------------------------------------- - * - * Win32NewDescriptor -- - * - * Set up for I/O descriptor masquerading. - * - * Results: - * Returns "fake id" which masquerades as a UNIX-style "small - * non-negative integer" file/socket descriptor. - * Win32_* routine below will "do the right thing" based on the - * descriptor's actual type. -1 indicates failure. - * - * Side effects: - * Entry in fdTable is reserved to represent the socket/file. - * - *-------------------------------------------------------------- - */ -static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd) -{ - int index = -1; - - EnterCriticalSection(&fdTableCritical); - - /* - * If desiredFd is set, try to get this entry (this is used for - * mapping stdio handles). Otherwise try to get the fd entry. - * If this is not available, find a the first empty slot. . - */ - if (desiredFd >= 0 && desiredFd < WIN32_OPEN_MAX) - { - if (fdTable[desiredFd].type == FD_UNUSED) - { - index = desiredFd; - } - } - else if (fd > 0) - { - if (fd < WIN32_OPEN_MAX && fdTable[fd].type == FD_UNUSED) - { - index = fd; - } - else - { - int i; - - for (i = 1; i < WIN32_OPEN_MAX; ++i) - { - if (fdTable[i].type == FD_UNUSED) - { - index = i; - break; - } - } - } - } - - if (index != -1) - { - fdTable[index].fid.value = fd; - fdTable[index].type = type; - fdTable[index].path = NULL; - fdTable[index].Errno = NO_ERROR; - fdTable[index].status = 0; - fdTable[index].offset = -1; - fdTable[index].offsetHighPtr = fdTable[index].offsetLowPtr = NULL; - fdTable[index].hMapMutex = NULL; - fdTable[index].ovList = NULL; - } - - LeaveCriticalSection(&fdTableCritical); - return index; -} - -/* - *-------------------------------------------------------------- - * - * StdinThread-- - * - * This thread performs I/O on stadard input. It is needed - * because you can't guarantee that all applications will - * create standard input with sufficient access to perform - * asynchronous I/O. Since we don't want to block the app - * reading from stdin we make it look like it's using I/O - * completion ports to perform async I/O. - * - * Results: - * Data is read from stdin and posted to the io completion - * port. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ -static void StdinThread(LPDWORD startup){ - - int doIo = TRUE; - unsigned long fd; - unsigned long bytesRead; - POVERLAPPED_REQUEST pOv; - - // Touch the arg to prevent warning - startup = NULL; - - while(doIo) { - /* - * Block until a request to read from stdin comes in or a - * request to terminate the thread arrives (fd = -1). - */ - if (!GetQueuedCompletionStatus(hStdinCompPort, &bytesRead, &fd, - (LPOVERLAPPED *)&pOv, (DWORD)-1) && !pOv) { - doIo = 0; - break; - } - - ASSERT((fd == STDIN_FILENO) || (fd == -1)); - if(fd == -1) { - doIo = 0; - break; - } - ASSERT(pOv->clientData1 != NULL); - - if(ReadFile(stdioHandles[STDIN_FILENO], pOv->clientData1, bytesRead, - &bytesRead, NULL)) { - PostQueuedCompletionStatus(hIoCompPort, bytesRead, - STDIN_FILENO, (LPOVERLAPPED)pOv); - } else { - doIo = 0; - break; - } - } - - ExitThread(0); -} - -void OS_ShutdownPending(void) -{ - shutdownPending = TRUE; -} - -/* XXX Need a shutdown now event */ -static DWORD WINAPI ShutdownRequestThread(LPVOID arg) -{ - HANDLE shutdownEvent = (HANDLE) arg; - WaitForSingleObject(shutdownEvent, INFINITE); - shutdownPending = TRUE; - // Before an accept() is entered the shutdownPending flag is checked. - // If set, OS_Accept() will return -1. If not, it waits - // on a connection request for one second, checks the flag, & repeats. - // Only one process/thread is allowed to do this at time by - // wrapping the accept() with mutex. - return 0; -} - -int OS_SetImpersonate(void) -{ - char *os_name = NULL; - os_name = getenv("OS"); - if (os_name && stricmp(os_name, "Windows_NT") == 0) { - bImpersonate = TRUE; - return 1; - } - return 0; -} - -/* - *-------------------------------------------------------------- - * - * OS_LibInit -- - * - * Set up the OS library for use. - * - * Results: - * Returns 0 if success, -1 if not. - * - * Side effects: - * Sockets initialized, pseudo file descriptors setup, etc. - * - *-------------------------------------------------------------- - */ -int OS_LibInit(int stdioFds[3]) -{ - WORD wVersion; - WSADATA wsaData; - int err; - int fakeFd; - DWORD threadId; - char *cLenPtr = NULL; - char *val = NULL; - - if(libInitialized) - return 0; - - InitializeCriticalSection(&fdTableCritical); - - /* - * Initialize windows sockets library. - */ - wVersion = MAKEWORD(2,0); - err = WSAStartup( wVersion, &wsaData ); - if (err) { - fprintf(stderr, "Error starting Windows Sockets. Error: %d", - WSAGetLastError()); - //exit(111); - return -1; - } - - /* - * Create the I/O completion port to be used for our I/O queue. - */ - if (hIoCompPort == INVALID_HANDLE_VALUE) { - hIoCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, - 0, 1); - if(hIoCompPort == INVALID_HANDLE_VALUE) { - printf("<H2>OS_LibInit Failed CreateIoCompletionPort! ERROR: %d</H2>\r\n\r\n", - GetLastError()); - return -1; - } - } - - /* - * If a shutdown event is in the env, save it (I don't see any to - * remove it from the environment out from under the application). - * Spawn a thread to wait on the shutdown request. - */ - val = getenv(SHUTDOWN_EVENT_NAME); - if (val != NULL) - { - HANDLE shutdownEvent = (HANDLE) atoi(val); - - if (! CreateThread(NULL, 0, ShutdownRequestThread, - shutdownEvent, 0, NULL)) - { - return -1; - } - } - - /* - * If an accept mutex is in the env, save it and remove it. - */ - val = getenv(MUTEX_VARNAME); - if (val != NULL) - { - acceptMutex = (HANDLE) atoi(val); - } - - - /* - * Determine if this library is being used to listen for FastCGI - * connections. This is communicated by STDIN containing a - * valid handle to a listener object. In this case, both the - * "stdout" and "stderr" handles will be INVALID (ie. closed) by - * the starting process. - * - * The trick is determining if this is a pipe or a socket... - * - * XXX: Add the async accept test to determine socket or handle to a - * pipe!!! - */ - if((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) && - (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) && - (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE) ) - { - DWORD pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT; - HANDLE oldStdIn = GetStdHandle(STD_INPUT_HANDLE); - - // Move the handle to a "low" number - if (! DuplicateHandle(GetCurrentProcess(), oldStdIn, - GetCurrentProcess(), &hListen, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - return -1; - } - - if (! SetStdHandle(STD_INPUT_HANDLE, hListen)) - { - return -1; - } - - CloseHandle(oldStdIn); - - /* - * Set the pipe handle state so that it operates in wait mode. - * - * NOTE: The listenFd is not mapped to a pseudo file descriptor - * as all work done on it is contained to the OS library. - * - * XXX: Initial assumption is that SetNamedPipeHandleState will - * fail if this is an IP socket... - */ - if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL)) - { - listenType = FD_PIPE_SYNC; - listenOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - } - else - { - listenType = FD_SOCKET_SYNC; - } - } - - /* - * If there are no stdioFds passed in, we're done. - */ - if(stdioFds == NULL) { - libInitialized = 1; - return 0; - } - - /* - * Setup standard input asynchronous I/O. There is actually a separate - * thread spawned for this purpose. The reason for this is that some - * web servers use anonymous pipes for the connection between itself - * and a CGI application. Anonymous pipes can't perform asynchronous - * I/O or use I/O completion ports. Therefore in order to present a - * consistent I/O dispatch model to an application we emulate I/O - * completion port behavior by having the standard input thread posting - * messages to the hIoCompPort which look like a complete overlapped - * I/O structure. This keeps the event dispatching simple from the - * application perspective. - */ - stdioHandles[STDIN_FILENO] = GetStdHandle(STD_INPUT_HANDLE); - - if(!SetHandleInformation(stdioHandles[STDIN_FILENO], - HANDLE_FLAG_INHERIT, 0)) { -/* - * XXX: Causes error when run from command line. Check KB - err = GetLastError(); - DebugBreak(); - exit(99); - */ - return -1; - } - - if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC, - (int)stdioHandles[STDIN_FILENO], - STDIN_FILENO)) == -1) { - return -1; - } else { - /* - * Set stdin equal to our pseudo FD and create the I/O completion - * port to be used for async I/O. - */ - stdioFds[STDIN_FILENO] = fakeFd; - } - - /* - * Create the I/O completion port to be used for communicating with - * the thread doing I/O on standard in. This port will carry read - * and possibly thread termination requests to the StdinThread. - */ - if (hStdinCompPort == INVALID_HANDLE_VALUE) { - hStdinCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, - 0, 1); - if(hStdinCompPort == INVALID_HANDLE_VALUE) { - printf("<H2>OS_LibInit Failed CreateIoCompletionPort: STDIN! ERROR: %d</H2>\r\n\r\n", - GetLastError()); - return -1; - } - } - - /* - * Create the thread that will read stdin if the CONTENT_LENGTH - * is non-zero. - */ - if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL && - atoi(cLenPtr) > 0) { - hStdinThread = CreateThread(NULL, 8192, - (LPTHREAD_START_ROUTINE)&StdinThread, - NULL, 0, &threadId); - if (hStdinThread == NULL) { - printf("<H2>OS_LibInit Failed to create STDIN thread! ERROR: %d</H2>\r\n\r\n", - GetLastError()); - return -1; - } - } - - /* - * STDOUT will be used synchronously. - * - * XXX: May want to convert this so that it could be used for OVERLAPPED - * I/O later. If so, model it after the Stdin I/O as stdout is - * also incapable of async I/O on some servers. - */ - stdioHandles[STDOUT_FILENO] = GetStdHandle(STD_OUTPUT_HANDLE); - if(!SetHandleInformation(stdioHandles[STDOUT_FILENO], - HANDLE_FLAG_INHERIT, FALSE)) { - //exit(99); - return -1; - } - - if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC, - (int)stdioHandles[STDOUT_FILENO], - STDOUT_FILENO)) == -1) { - return -1; - } else { - /* - * Set stdout equal to our pseudo FD - */ - stdioFds[STDOUT_FILENO] = fakeFd; - } - - stdioHandles[STDERR_FILENO] = GetStdHandle(STD_ERROR_HANDLE); - if(!SetHandleInformation(stdioHandles[STDERR_FILENO], - HANDLE_FLAG_INHERIT, FALSE)) { - //exit(99); - return -1; - } - if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC, - (int)stdioHandles[STDERR_FILENO], - STDERR_FILENO)) == -1) { - return -1; - } else { - /* - * Set stderr equal to our pseudo FD - */ - stdioFds[STDERR_FILENO] = fakeFd; - } - - return 0; -} - -/* - *-------------------------------------------------------------- - * - * OS_LibShutdown -- - * - * Shutdown the OS library. - * - * Results: - * None. - * - * Side effects: - * Memory freed, handles closed. - * - *-------------------------------------------------------------- - */ -void OS_LibShutdown() -{ - - if (hIoCompPort != INVALID_HANDLE_VALUE) - { - CloseHandle(hIoCompPort); - hIoCompPort = INVALID_HANDLE_VALUE; - } - - if (hStdinCompPort != INVALID_HANDLE_VALUE) - { - CloseHandle(hStdinCompPort); - hStdinCompPort = INVALID_HANDLE_VALUE; - } - - if (acceptMutex != INVALID_HANDLE_VALUE) - { - ReleaseMutex(acceptMutex); - CloseHandle(acceptMutex); - } - - /* we only want to do this if we're not a web server */ - if (stdioHandles[0] != INVALID_HANDLE_VALUE) { - DisconnectNamedPipe(hListen); - CancelIo(hListen); - if (bImpersonate) RevertToSelf(); - } - - DeleteCriticalSection(&fdTableCritical); - WSACleanup(); -} - -/* - *-------------------------------------------------------------- - * - * Win32FreeDescriptor -- - * - * Free I/O descriptor entry in fdTable. - * - * Results: - * Frees I/O descriptor entry in fdTable. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ -static void Win32FreeDescriptor(int fd) -{ - /* Catch it if fd is a bogus value */ - ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); - - EnterCriticalSection(&fdTableCritical); - - if (fdTable[fd].type != FD_UNUSED) - { - switch (fdTable[fd].type) - { - case FD_FILE_SYNC: - case FD_FILE_ASYNC: - - /* Free file path string */ - ASSERT(fdTable[fd].path != NULL); - - free(fdTable[fd].path); - fdTable[fd].path = NULL; - break; - case FD_PIPE_ASYNC: - break; - default: - break; - } - - ASSERT(fdTable[fd].path == NULL); - - fdTable[fd].type = FD_UNUSED; - fdTable[fd].path = NULL; - fdTable[fd].Errno = NO_ERROR; - fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL; - - if (fdTable[fd].hMapMutex != NULL) - { - CloseHandle(fdTable[fd].hMapMutex); - fdTable[fd].hMapMutex = NULL; - } - } - - LeaveCriticalSection(&fdTableCritical); - - return; -} - -static short getPort(const char * bindPath) -{ - short port = 0; - char * p = strchr(bindPath, ':'); - - if (p && *++p) - { - char buf[6]; - - strncpy(buf, p, 6); - buf[5] = '\0'; - - port = (short) atoi(buf); - } - - return port; -} - -/** -This function builds a Dacl which grants the creator of the objects -FILE_ALL_ACCESS and Everyone FILE_GENERIC_READ and FILE_GENERIC_WRITE -access to the object. - -This Dacl allows for higher security than a NULL Dacl, which is common for -named-pipes, as this only grants the creator/owner write access to the -security descriptor, and grants Everyone the ability to "use" the named-pipe. -This scenario prevents a malevolent user from disrupting service by preventing -arbitrary access manipulation. -**/ -BOOL -BuildNamedPipeAcl( - PACL pAcl, - PDWORD cbAclSize - ) -{ - DWORD dwAclSize; - - SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY; - SID_IDENTIFIER_AUTHORITY siaCreator = SECURITY_CREATOR_SID_AUTHORITY; - - BYTE BufEveryoneSid[32]; - BYTE BufOwnerSid[32]; - - PSID pEveryoneSid = (PSID)BufEveryoneSid; - PSID pOwnerSid = (PSID)BufOwnerSid; - - // - // compute size of acl - // - dwAclSize = sizeof(ACL) + - 2 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) + - GetSidLengthRequired( 1 ) + // well-known Everyone Sid - GetSidLengthRequired( 1 ) ; // well-known Creator Owner Sid - - if(*cbAclSize < dwAclSize) { - *cbAclSize = dwAclSize; - return FALSE; - } - - *cbAclSize = dwAclSize; - - // - // intialize well known sids - // - - if(!InitializeSid(pEveryoneSid, &siaWorld, 1)) return FALSE; - *GetSidSubAuthority(pEveryoneSid, 0) = SECURITY_WORLD_RID; - - if(!InitializeSid(pOwnerSid, &siaCreator, 1)) return FALSE; - *GetSidSubAuthority(pOwnerSid, 0) = SECURITY_CREATOR_OWNER_RID; - - if(!InitializeAcl(pAcl, dwAclSize, ACL_REVISION)) - return FALSE; - - // - // - if(!AddAccessAllowedAce( - pAcl, - ACL_REVISION, - FILE_GENERIC_READ | FILE_GENERIC_WRITE, - pEveryoneSid - )) - return FALSE; - - // - // - return AddAccessAllowedAce( - pAcl, - ACL_REVISION, - FILE_ALL_ACCESS, - pOwnerSid - ); -} - - -/* - * OS_CreateLocalIpcFd -- - * - * This procedure is responsible for creating the listener pipe - * on Windows NT for local process communication. It will create a - * named pipe and return a file descriptor to it to the caller. - * - * Results: - * Listener pipe created. This call returns either a valid - * pseudo file descriptor or -1 on error. - * - * Side effects: - * Listener pipe and IPC address are stored in the FCGI info - * structure. - * 'errno' will set on errors (-1 is returned). - * - *---------------------------------------------------------------------- - */ -int OS_CreateLocalIpcFd(const char *bindPath, int backlog, int bCreateMutex) -{ - int pseudoFd = -1; - short port = getPort(bindPath); - HANDLE mutex = INVALID_HANDLE_VALUE; - char mutexEnvString[100]; - - if (bCreateMutex) { - mutex = CreateMutex(NULL, FALSE, NULL); - if (! SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE)) - { - CloseHandle(mutex); - return -3; - } - // This is a nail for listening to more than one port.. - // This should really be handled by the caller. - _snprintf(mutexEnvString, sizeof(mutexEnvString)-1, MUTEX_VARNAME "=%d", (int) mutex); - putenv(mutexEnvString); - } - - // There's nothing to be gained (at the moment) by a shutdown Event - - if (port && *bindPath != ':' && strncmp(bindPath, LOCALHOST, strlen(LOCALHOST))) - { - fprintf(stderr, "To start a service on a TCP port can not " - "specify a host name.\n" - "You should either use \"localhost:<port>\" or " - " just use \":<port>.\"\n"); - //exit(1); - if (bCreateMutex) CloseHandle(mutexEnvString); - return -1; - } - - listenType = (port) ? FD_SOCKET_SYNC : FD_PIPE_ASYNC; - - if (port) - { - SOCKET listenSock; - struct sockaddr_in sockAddr; - int sockLen = sizeof(sockAddr); - - memset(&sockAddr, 0, sizeof(sockAddr)); - sockAddr.sin_family = AF_INET; - sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); - sockAddr.sin_port = htons(port); - - listenSock = socket(AF_INET, SOCK_STREAM, 0); - if (listenSock == INVALID_SOCKET) - { - if (bCreateMutex)CloseHandle(mutexEnvString); - return -4; - } - - if (bind(listenSock, (struct sockaddr *) &sockAddr, sockLen) ) - { - if (bCreateMutex)CloseHandle(mutexEnvString); - return -12; - } - - if (listen(listenSock, backlog)) - { - if (bCreateMutex)CloseHandle(mutexEnvString); - return -5; - } - - pseudoFd = Win32NewDescriptor(listenType, listenSock, -1); - - if (pseudoFd == -1) - { - if (bCreateMutex)CloseHandle(mutexEnvString); - closesocket(listenSock); - return -6; - } - - hListen = (HANDLE) listenSock; - } - else - { - SECURITY_ATTRIBUTES sa; - SECURITY_DESCRIPTOR sd; - BYTE AclBuf[ 64 ]; - DWORD cbAclSize = 64; - PACL pAcl = (PACL)AclBuf; - - HANDLE hListenPipe = INVALID_HANDLE_VALUE; - char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1); - - if (! pipePath) - { - if (bCreateMutex)CloseHandle(mutexEnvString); - return -7; - } - - strcpy(pipePath, bindPathPrefix); - strcat(pipePath, bindPath); - - if (bImpersonate) { - // get the security attributes for Everybody to connect - // we do this so that multithreaded servers that run - // threads under secured users can access pipes created - // by a system level thread (for instance, IIS) - // - // suppress errors regarding startup directory, etc - // - SetErrorMode(SEM_FAILCRITICALERRORS); - - if(!BuildNamedPipeAcl(pAcl, &cbAclSize)) { - fprintf(stderr, "BuildNamedPipeAcl"); - return -100; - } - - if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { - fprintf(stderr, "InitializeSecurityDescriptor"); - return -100; - } - - if(!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { - fprintf(stderr, "SetSecurityDescriptorDacl"); - return -100; - } - - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = &sd; // default Dacl of caller - sa.bInheritHandle = TRUE; - - } - - hListenPipe = CreateNamedPipe(pipePath, - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE, - PIPE_UNLIMITED_INSTANCES, - 4096, 4096, 0, bImpersonate?&sa:NULL); - - free(pipePath); - - if (hListenPipe == INVALID_HANDLE_VALUE) - { - if (bCreateMutex)CloseHandle(mutexEnvString); - return -8; - } - - if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE)) - { - if (bCreateMutex)CloseHandle(mutexEnvString); - return -9; - } - - pseudoFd = Win32NewDescriptor(listenType, (int) hListenPipe, -1); - - if (pseudoFd == -1) - { - if (bCreateMutex)CloseHandle(mutexEnvString); - CloseHandle(hListenPipe); - return -10; - } - - hListen = (HANDLE) hListenPipe; - } - - return pseudoFd; -} - -/* - *---------------------------------------------------------------------- - * - * OS_FcgiConnect -- - * - * Create the pipe pathname connect to the remote application if - * possible. - * - * Results: - * -1 if fail or a valid handle if connection succeeds. - * - * Side effects: - * Remote connection established. - * - *---------------------------------------------------------------------- - */ -int OS_FcgiConnect(char *bindPath) -{ - short port = getPort(bindPath); - int pseudoFd = -1; - unsigned int flags = FILE_FLAG_OVERLAPPED; - if (port) - { - struct hostent *hp; - char *host = NULL; - struct sockaddr_in sockAddr; - int sockLen = sizeof(sockAddr); - SOCKET sock; - - if (*bindPath != ':') - { - char * p = strchr(bindPath, ':'); - if (p) { - int len = p - bindPath + 1; - - host = (char *)malloc(len); - if (!host) { - fprintf(stderr, "Unable to allocate memory\n"); - return -1; - } - strncpy(host, bindPath, len); - host[len-1] = '\0'; - } - } - - hp = gethostbyname(host ? host : LOCALHOST); - - if (host) - { - free(host); - } - - if (hp == NULL) - { - fprintf(stderr, "Unknown host: %s\n", bindPath); - return -1; - } - - memset(&sockAddr, 0, sizeof(sockAddr)); - sockAddr.sin_family = AF_INET; - memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length); - sockAddr.sin_port = htons(port); - - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) - { - return -1; - } - - if (connect(sock, (struct sockaddr *) &sockAddr, sockLen) == SOCKET_ERROR) - { - closesocket(sock); - return -1; - } - - pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, sock, -1); - if (pseudoFd == -1) - { - closesocket(sock); - return -1; - } - } - else - { - char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1); - HANDLE hPipe; - - if (! pipePath) - { - return -1; - } - - strcpy(pipePath, bindPathPrefix); - strcat(pipePath, bindPath); - - if (bImpersonate) { - flags |= SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION; - } - - hPipe = CreateFile(pipePath, - GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - flags, - NULL); - - free(pipePath); - - if( hPipe == INVALID_HANDLE_VALUE || hPipe == 0) - { - return -1; - } - - pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int) hPipe, -1); - - if (pseudoFd == -1) - { - CloseHandle(hPipe); - return -1; - } - - /* - * Set stdin equal to our pseudo FD and create the I/O completion - * port to be used for async I/O. - */ - if (! CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1)) - { - Win32FreeDescriptor(pseudoFd); - CloseHandle(hPipe); - return -1; - } - } - - return pseudoFd; -} - -/* - *-------------------------------------------------------------- - * - * OS_Read -- - * - * Pass through to the appropriate NT read function. - * - * Results: - * Returns number of byes read. Mimics unix read:. - * n bytes read, 0 or -1 failure: errno contains actual error - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ -int OS_Read(int fd, char * buf, size_t len) -{ - DWORD bytesRead; - int ret = -1; - - ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); - - if (shutdownNow) return -1; - - switch (fdTable[fd].type) - { - case FD_FILE_SYNC: - case FD_FILE_ASYNC: - case FD_PIPE_SYNC: - case FD_PIPE_ASYNC: - - if (ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, NULL)) - { - ret = bytesRead; - } - else - { - fdTable[fd].Errno = GetLastError(); - ret = -1; - } - - break; - - case FD_SOCKET_SYNC: - case FD_SOCKET_ASYNC: - - ret = recv(fdTable[fd].fid.sock, buf, len, 0); - if (ret == SOCKET_ERROR) - { - fdTable[fd].Errno = WSAGetLastError(); - ret = -1; - } - - break; - - default: - - ASSERT(0); - } - - return ret; -} - -/* - *-------------------------------------------------------------- - * - * OS_Write -- - * - * Perform a synchronous OS write. - * - * Results: - * Returns number of bytes written. Mimics unix write: - * n bytes written, 0 or -1 failure (??? couldn't find man page). - * - * Side effects: - * none. - * - *-------------------------------------------------------------- - */ -int OS_Write(int fd, char * buf, size_t len) -{ - DWORD bytesWritten; - int ret = -1; - - ASSERT(fd >= 0 && fd < WIN32_OPEN_MAX); - - if (shutdownNow) return -1; - - switch (fdTable[fd].type) - { - case FD_FILE_SYNC: - case FD_FILE_ASYNC: - case FD_PIPE_SYNC: - case FD_PIPE_ASYNC: - - if (WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten, NULL)) - { - ret = bytesWritten; - } - else - { - fdTable[fd].Errno = GetLastError(); - } - - break; - - case FD_SOCKET_SYNC: - case FD_SOCKET_ASYNC: - - ret = send(fdTable[fd].fid.sock, buf, len, 0); - if (ret == SOCKET_ERROR) - { - fdTable[fd].Errno = WSAGetLastError(); - ret = -1; - } - - break; - - default: - - ASSERT(0); - } - - return ret; -} - -/* - *---------------------------------------------------------------------- - * - * OS_SpawnChild -- - * - * Spawns a new server listener process, and stores the information - * relating to the child in the supplied record. A wait handler is - * registered on the child's completion. This involves creating - * a process on NT and preparing a command line with the required - * state (currently a -childproc flag and the server socket to use - * for accepting connections). - * - * Results: - * 0 if success, -1 if error. - * - * Side effects: - * Child process spawned. - * - *---------------------------------------------------------------------- - */ -int OS_SpawnChild(char *execPath, int listenFd, PROCESS_INFORMATION *pInfo, char *env) -{ - STARTUPINFO StartupInfo; - BOOL success; - - memset((void *)&StartupInfo, 0, sizeof(STARTUPINFO)); - StartupInfo.cb = sizeof (STARTUPINFO); - StartupInfo.lpReserved = NULL; - StartupInfo.lpReserved2 = NULL; - StartupInfo.cbReserved2 = 0; - StartupInfo.lpDesktop = NULL; - StartupInfo.wShowWindow = SW_HIDE; - /* - * FastCGI on NT will set the listener pipe HANDLE in the stdin of - * the new process. The fact that there is a stdin and NULL handles - * for stdout and stderr tells the FastCGI process that this is a - * FastCGI process and not a CGI process. - */ - StartupInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; - /* - * XXX: Do I have to dup the handle before spawning the process or is - * it sufficient to use the handle as it's reference counted - * by NT anyway? - */ - StartupInfo.hStdInput = fdTable[listenFd].fid.fileHandle; - StartupInfo.hStdOutput = INVALID_HANDLE_VALUE; - StartupInfo.hStdError = INVALID_HANDLE_VALUE; - - /* - * Make the listener socket inheritable. - */ - success = SetHandleInformation(StartupInfo.hStdInput, HANDLE_FLAG_INHERIT, - TRUE); - if(!success) { - //exit(99); - return -1; - } - - /* - * XXX: Might want to apply some specific security attributes to the - * processes. - */ - success = CreateProcess(execPath, /* LPCSTR address of module name */ - NULL, /* LPCSTR address of command line */ - NULL, /* Process security attributes */ - NULL, /* Thread security attributes */ - TRUE, /* Inheritable Handes inherited. */ - 0, /* DWORD creation flags */ - env, /* Use parent environment block */ - NULL, /* Address of current directory name */ - &StartupInfo, /* Address of STARTUPINFO */ - pInfo); /* Address of PROCESS_INFORMATION */ - if(success) { - return 0; - } else { - return -1; - } -} - -/* - *-------------------------------------------------------------- - * - * OS_AsyncReadStdin -- - * - * This initiates an asynchronous read on the standard - * input handle. This handle is not guaranteed to be - * capable of performing asynchronous I/O so we send a - * message to the StdinThread to do the synchronous read. - * - * Results: - * -1 if error, 0 otherwise. - * - * Side effects: - * Asynchronous message is queued to the StdinThread and an - * overlapped structure is allocated/initialized. - * - *-------------------------------------------------------------- - */ -int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, - ClientData clientData) -{ - POVERLAPPED_REQUEST pOv; - - ASSERT(fdTable[STDIN_FILENO].type != FD_UNUSED); - - pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST)); - ASSERT(pOv); - memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST)); - pOv->clientData1 = (ClientData)buf; - pOv->instance = fdTable[STDIN_FILENO].instance; - pOv->procPtr = procPtr; - pOv->clientData = clientData; - - PostQueuedCompletionStatus(hStdinCompPort, len, STDIN_FILENO, - (LPOVERLAPPED)pOv); - return 0; -} - -/* - *-------------------------------------------------------------- - * - * OS_AsyncRead -- - * - * This initiates an asynchronous read on the file - * handle which may be a socket or named pipe. - * - * We also must save the ProcPtr and ClientData, so later - * when the io completes, we know who to call. - * - * We don't look at any results here (the ReadFile may - * return data if it is cached) but do all completion - * processing in OS_Select when we get the io completion - * port done notifications. Then we call the callback. - * - * Results: - * -1 if error, 0 otherwise. - * - * Side effects: - * Asynchronous I/O operation is queued for completion. - * - *-------------------------------------------------------------- - */ -int OS_AsyncRead(int fd, int offset, void *buf, int len, - OS_AsyncProc procPtr, ClientData clientData) -{ - DWORD bytesRead; - POVERLAPPED_REQUEST pOv; - - /* - * Catch any bogus fd values - */ - ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); - /* - * Confirm that this is an async fd - */ - ASSERT(fdTable[fd].type != FD_UNUSED); - ASSERT(fdTable[fd].type != FD_FILE_SYNC); - ASSERT(fdTable[fd].type != FD_PIPE_SYNC); - ASSERT(fdTable[fd].type != FD_SOCKET_SYNC); - - pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST)); - ASSERT(pOv); - memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST)); - /* - * Only file offsets should be non-zero, but make sure. - */ - if (fdTable[fd].type == FD_FILE_ASYNC) - if (fdTable[fd].offset >= 0) - pOv->overlapped.Offset = fdTable[fd].offset; - else - pOv->overlapped.Offset = offset; - pOv->instance = fdTable[fd].instance; - pOv->procPtr = procPtr; - pOv->clientData = clientData; - bytesRead = fd; - /* - * ReadFile returns: TRUE success, FALSE failure - */ - if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, - (LPOVERLAPPED)pOv)) { - fdTable[fd].Errno = GetLastError(); - if(fdTable[fd].Errno == ERROR_NO_DATA || - fdTable[fd].Errno == ERROR_PIPE_NOT_CONNECTED) { - PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv); - return 0; - } - if(fdTable[fd].Errno != ERROR_IO_PENDING) { - PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv); - return -1; - } - fdTable[fd].Errno = 0; - } - return 0; -} - -/* - *-------------------------------------------------------------- - * - * OS_AsyncWrite -- - * - * This initiates an asynchronous write on the "fake" file - * descriptor (which may be a file, socket, or named pipe). - * We also must save the ProcPtr and ClientData, so later - * when the io completes, we know who to call. - * - * We don't look at any results here (the WriteFile generally - * completes immediately) but do all completion processing - * in OS_DoIo when we get the io completion port done - * notifications. Then we call the callback. - * - * Results: - * -1 if error, 0 otherwise. - * - * Side effects: - * Asynchronous I/O operation is queued for completion. - * - *-------------------------------------------------------------- - */ -int OS_AsyncWrite(int fd, int offset, void *buf, int len, - OS_AsyncProc procPtr, ClientData clientData) -{ - DWORD bytesWritten; - POVERLAPPED_REQUEST pOv; - - /* - * Catch any bogus fd values - */ - ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); - /* - * Confirm that this is an async fd - */ - ASSERT(fdTable[fd].type != FD_UNUSED); - ASSERT(fdTable[fd].type != FD_FILE_SYNC); - ASSERT(fdTable[fd].type != FD_PIPE_SYNC); - ASSERT(fdTable[fd].type != FD_SOCKET_SYNC); - - pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST)); - ASSERT(pOv); - memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST)); - /* - * Only file offsets should be non-zero, but make sure. - */ - if (fdTable[fd].type == FD_FILE_ASYNC) - /* - * Only file opened via OS_AsyncWrite with - * O_APPEND will have an offset != -1. - */ - if (fdTable[fd].offset >= 0) - /* - * If the descriptor has a memory mapped file - * handle, take the offsets from there. - */ - if (fdTable[fd].hMapMutex != NULL) { - /* - * Wait infinitely; this *should* not cause problems. - */ - WaitForSingleObject(fdTable[fd].hMapMutex, INFINITE); - - /* - * Retrieve the shared offset values. - */ - pOv->overlapped.OffsetHigh = *(fdTable[fd].offsetHighPtr); - pOv->overlapped.Offset = *(fdTable[fd].offsetLowPtr); - - /* - * Update the shared offset values for the next write - */ - *(fdTable[fd].offsetHighPtr) += 0; /* XXX How do I handle overflow */ - *(fdTable[fd].offsetLowPtr) += len; - - ReleaseMutex(fdTable[fd].hMapMutex); - } else - pOv->overlapped.Offset = fdTable[fd].offset; - else - pOv->overlapped.Offset = offset; - pOv->instance = fdTable[fd].instance; - pOv->procPtr = procPtr; - pOv->clientData = clientData; - bytesWritten = fd; - /* - * WriteFile returns: TRUE success, FALSE failure - */ - if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten, - (LPOVERLAPPED)pOv)) { - fdTable[fd].Errno = GetLastError(); - if(fdTable[fd].Errno != ERROR_IO_PENDING) { - PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv); - return -1; - } - fdTable[fd].Errno = 0; - } - if (fdTable[fd].offset >= 0) - fdTable[fd].offset += len; - return 0; -} - -/* - *-------------------------------------------------------------- - * - * OS_Close -- - * - * Closes the descriptor with routine appropriate for - * descriptor's type. - * - * Results: - * Socket or file is closed. Return values mimic Unix close: - * 0 success, -1 failure - * - * Side effects: - * Entry in fdTable is marked as free. - * - *-------------------------------------------------------------- - */ -int OS_Close(int fd) -{ - int ret = 0; - - /* - * Catch it if fd is a bogus value - */ - ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); - ASSERT(fdTable[fd].type != FD_UNUSED); - - switch (fdTable[fd].type) { - case FD_PIPE_SYNC: - case FD_PIPE_ASYNC: - case FD_FILE_SYNC: - case FD_FILE_ASYNC: - /* - * CloseHandle returns: TRUE success, 0 failure - */ - /* - XXX don't close here, fcgi apps fail if we do so - need to examine resource leaks if any might exist - if (CloseHandle(fdTable[fd].fid.fileHandle) == FALSE) - ret = -1; - */ - break; - case FD_SOCKET_SYNC: - case FD_SOCKET_ASYNC: - /* - * Closing a socket that has an async read outstanding causes a - * tcp reset and possible data loss. The shutdown call seems to - * prevent this. - */ - - /* shutdown(fdTable[fd].fid.sock, SD_BOTH); */ - - { - char buf[16]; - int r; - - shutdown(fdTable[fd].fid.sock,SD_SEND); - - do - { - r = recv(fdTable[fd].fid.sock,buf,16,0); - } while (r > 0); - } - /* - * closesocket returns: 0 success, SOCKET_ERROR failure - */ - if (closesocket(fdTable[fd].fid.sock) == SOCKET_ERROR) - ret = -1; - break; - default: - return -1; /* fake failure */ - } - - Win32FreeDescriptor(fd); - return ret; -} - -/* - *-------------------------------------------------------------- - * - * OS_CloseRead -- - * - * Cancel outstanding asynchronous reads and prevent subsequent - * reads from completing. - * - * Results: - * Socket or file is shutdown. Return values mimic Unix shutdown: - * 0 success, -1 failure - * - *-------------------------------------------------------------- - */ -int OS_CloseRead(int fd) -{ - int ret = 0; - - /* - * Catch it if fd is a bogus value - */ - ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); - ASSERT(fdTable[fd].type == FD_SOCKET_ASYNC - || fdTable[fd].type == FD_SOCKET_SYNC); - - if (shutdown(fdTable[fd].fid.sock,SD_RECEIVE) == SOCKET_ERROR) - ret = -1; - return ret; -} - -/* - *-------------------------------------------------------------- - * - * OS_DoIo -- - * - * This function was formerly OS_Select. It's purpose is - * to pull I/O completion events off the queue and dispatch - * them to the appropriate place. - * - * Results: - * Returns 0. - * - * Side effects: - * Handlers are called. - * - *-------------------------------------------------------------- - */ -int OS_DoIo(struct timeval *tmo) -{ - unsigned long fd; - unsigned long bytes; - POVERLAPPED_REQUEST pOv; - struct timeb tb; - int ms; - int ms_last; - int err; - - /* XXX - * We can loop in here, but not too long, as wait handlers - * must run. - * For cgi stdin, apparently select returns when io completion - * ports don't, so don't wait the full timeout. - */ - if(tmo) - ms = (tmo->tv_sec*1000 + tmo->tv_usec/1000) / 2; - else - ms = 1000; - ftime(&tb); - ms_last = tb.time*1000 + tb.millitm; - while (ms >= 0) { - if(tmo && (ms = tmo->tv_sec*1000 + tmo->tv_usec/1000)> 100) - ms = 100; - if (!GetQueuedCompletionStatus(hIoCompPort, &bytes, &fd, - (LPOVERLAPPED *)&pOv, ms) && !pOv) { - err = WSAGetLastError(); - return 0; /* timeout */ - } - - ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); - /* call callback if descriptor still valid */ - ASSERT(pOv); - if(pOv->instance == fdTable[fd].instance) - (*pOv->procPtr)(pOv->clientData, bytes); - free(pOv); - - ftime(&tb); - ms -= (tb.time*1000 + tb.millitm - ms_last); - ms_last = tb.time*1000 + tb.millitm; - } - return 0; -} - -static int isAddrOK(struct sockaddr_in * inet_sockaddr, const char * okAddrs) -{ - static const char *token = " ,;:\t"; - char *ipaddr; - char *p; - - if (okAddrs == NULL) return TRUE; - - ipaddr = inet_ntoa(inet_sockaddr->sin_addr); - p = strstr(okAddrs, ipaddr); - - if (p == NULL) return FALSE; - - if (p == okAddrs) - { - p += strlen(ipaddr); - return (strchr(token, *p) != NULL); - } - - if (strchr(token, *--p) != NULL) - { - p += strlen(ipaddr) + 1; - return (strchr(token, *p) != NULL); - } - - return FALSE; -} - -#ifndef NO_WSAACEPT -static int CALLBACK isAddrOKCallback(LPWSABUF lpCallerId, - LPWSABUF dc0, - LPQOS dc1, - LPQOS dc2, - LPWSABUF dc3, - LPWSABUF dc4, - GROUP *dc5, - DWORD data) -{ - struct sockaddr_in *sockaddr = (struct sockaddr_in *) lpCallerId->buf; - - // Touch the args to avoid warnings - dc0 = NULL; dc1 = NULL; dc2 = NULL; dc3 = NULL; dc4 = NULL; dc5 = NULL; - - if ((void *) data == NULL) return CF_ACCEPT; - - if (sockaddr->sin_family != AF_INET) return CF_ACCEPT; - - return isAddrOK(sockaddr, (const char *) data) ? CF_ACCEPT : CF_REJECT; -} -#endif - -static printLastError(const char * text) -{ - LPVOID buf; - - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - 0, - (LPTSTR) &buf, - 0, - NULL - ); - - fprintf(stderr, "%s: %s\n", text, (LPCTSTR) buf); - LocalFree(buf); -} - -static int acceptNamedPipe() -{ - int ipcFd = -1; - - if (! ConnectNamedPipe(hListen, &listenOverlapped)) - { - switch (GetLastError()) - { - case ERROR_PIPE_CONNECTED: - - // A client connected after CreateNamedPipe but - // before ConnectNamedPipe. Its a good connection. - - break; - - case ERROR_IO_PENDING: - - // Wait for a connection to complete. - - while (WaitForSingleObject(listenOverlapped.hEvent, - ACCEPT_TIMEOUT) == WAIT_TIMEOUT) - { - if (shutdownPending) - { - OS_LibShutdown(); - return -1; - } - } - - break; - - case ERROR_PIPE_LISTENING: - - // The pipe handle is in nonblocking mode. - - case ERROR_NO_DATA: - - // The previous client closed its handle (and we failed - // to call DisconnectNamedPipe) - - default: - - printLastError("unexpected ConnectNamedPipe() error"); - } - } - - // - // impersonate the client - // - if(bImpersonate && !ImpersonateNamedPipeClient(hListen)) { - DisconnectNamedPipe(hListen); - } else { - ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1); - if (ipcFd == -1) - { - DisconnectNamedPipe(hListen); - if (bImpersonate) RevertToSelf(); - } - } - - return ipcFd; -} - -static int acceptSocket(const char *webServerAddrs) -{ - SOCKET hSock; - int ipcFd = -1; - - for (;;) - { - struct sockaddr sockaddr; - int sockaddrLen = sizeof(sockaddr); - - for (;;) - { - const struct timeval timeout = {1, 0}; - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET((unsigned int) hListen, &readfds); - - if (select(0, &readfds, NULL, NULL, &timeout) == 0) - { - if (shutdownPending) - { - OS_LibShutdown(); - return -1; - } - } - else - { - break; - } - } - -#if NO_WSAACEPT - hSock = accept((SOCKET) hListen, &sockaddr, &sockaddrLen); - - if (hSock == INVALID_SOCKET) - { - break; - } - - if (isAddrOK((struct sockaddr_in *) &sockaddr, webServerAddrs)) - { - break; - } - - closesocket(hSock); -#else - hSock = WSAAccept((unsigned int) hListen, - &sockaddr, - &sockaddrLen, - isAddrOKCallback, - (DWORD) webServerAddrs); - - if (hSock != INVALID_SOCKET) - { - break; - } - - if (WSAGetLastError() != WSAECONNREFUSED) - { - break; - } -#endif - } - - if (hSock == INVALID_SOCKET) - { - /* Use FormatMessage() */ - fprintf(stderr, "accept()/WSAAccept() failed: %d", WSAGetLastError()); - return -1; - } - - ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1); - if (ipcFd == -1) - { - closesocket(hSock); - } - - return ipcFd; -} - -/* - *---------------------------------------------------------------------- - * - * OS_Accept -- - * - * Accepts a new FastCGI connection. This routine knows whether - * we're dealing with TCP based sockets or NT Named Pipes for IPC. - * - * fail_on_intr is ignored in the Win lib. - * - * Results: - * -1 if the operation fails, otherwise this is a valid IPC fd. - * - *---------------------------------------------------------------------- - */ -int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs) -{ - int ipcFd = -1; - - // Touch args to prevent warnings - listen_sock = 0; fail_on_intr = 0; - - // @todo Muliple listen sockets and sockets other than 0 are not - // supported due to the use of globals. - - if (shutdownPending) - { - OS_LibShutdown(); - return -1; - } - - // The mutex is to keep other processes (and threads, when supported) - // from going into the accept cycle. The accept cycle needs to - // periodically break out to check the state of the shutdown flag - // and there's no point to having more than one thread do that. - - if (acceptMutex != INVALID_HANDLE_VALUE) - { - DWORD ret; - while ((ret = WaitForSingleObject(acceptMutex, ACCEPT_TIMEOUT)) == WAIT_TIMEOUT) - { - if (shutdownPending) break; - } - if (ret == WAIT_FAILED) { - printLastError("WaitForSingleObject() failed"); - return -1; - } - } - - if (shutdownPending) - { - OS_LibShutdown(); - } - else if (listenType == FD_PIPE_SYNC) - { - ipcFd = acceptNamedPipe(); - } - else if (listenType == FD_SOCKET_SYNC) - { - ipcFd = acceptSocket(webServerAddrs); - } - else - { - fprintf(stderr, "unknown listenType (%d)\n", listenType); - } - - if (acceptMutex != INVALID_HANDLE_VALUE) - { - ReleaseMutex(acceptMutex); - } - - return ipcFd; -} - -/* - *---------------------------------------------------------------------- - * - * OS_IpcClose - * - * OS IPC routine to close an IPC connection. - * - * Results: - * - * - * Side effects: - * IPC connection is closed. - * - *---------------------------------------------------------------------- - */ -int OS_IpcClose(int ipcFd) -{ - if (ipcFd == -1) - return 0; - - /* - * Catch it if fd is a bogus value - */ - ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX)); - ASSERT(fdTable[ipcFd].type != FD_UNUSED); - - switch(listenType) { - - case FD_PIPE_SYNC: - /* - * Make sure that the client (ie. a Web Server in this case) has - * read all data from the pipe before we disconnect. - */ - if(!FlushFileBuffers(fdTable[ipcFd].fid.fileHandle)) - return -1; - if(DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) { - OS_Close(ipcFd); - if (bImpersonate) RevertToSelf(); - return 0; - } else { - return -1; - } - break; - - case FD_SOCKET_SYNC: - OS_Close(ipcFd); - return 0; - break; - - case FD_UNUSED: - default: - //exit(106); - return -1; - break; - } - return -1; -} - -/* - *---------------------------------------------------------------------- - * - * OS_IsFcgi -- - * - * Determines whether this process is a FastCGI process or not. - * - * Results: - * Returns 1 if FastCGI, 0 if not. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -int OS_IsFcgi(int sock) -{ - // Touch args to prevent warnings - sock = 0; - - /* XXX This is broken for sock */ - - return (listenType != FD_UNUSED); -} - -/* - *---------------------------------------------------------------------- - * - * OS_SetFlags -- - * - * Sets selected flag bits in an open file descriptor. Currently - * this is only to put a SOCKET into non-blocking mode. - * - *---------------------------------------------------------------------- - */ -void OS_SetFlags(int fd, int flags) -{ - unsigned long pLong = 1L; - - if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) { - if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) == - SOCKET_ERROR) { - //exit(WSAGetLastError()); - SetLastError(WSAGetLastError()); - return; - } - if (!CreateIoCompletionPort((HANDLE)fdTable[fd].fid.sock, - hIoCompPort, fd, 1)) { - //err = GetLastError(); - //exit(err); - return; - } - - fdTable[fd].type = FD_SOCKET_ASYNC; - } - return; -} - |