⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_win32.c

📁 FastCGI,语言无关的、可伸缩架构的CGI开放扩展
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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 lintstatic const char rcsid[] = "$Id: os_win32.c,v 1.33 2002/03/05 18:15:15 robs Exp $";#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>#include <process.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 MUTEX_VARNAME "_FCGI_MUTEX_"#define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_"#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};// This is a nail for listening to more than one port..static HANDLE acceptMutex = INVALID_HANDLE_VALUE;static BOOLEAN shutdownPending = FALSE;static BOOLEAN shutdownNow = 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 DESCRIPTORstatic HANDLE hListen = INVALID_HANDLE_VALUE;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(void * 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;}static void ShutdownRequestThread(void * arg){    HANDLE shutdownEvent = (HANDLE) arg;        WaitForSingleObject(shutdownEvent, INFINITE);    shutdownPending = TRUE;    if (listenType == FD_PIPE_SYNC)    {        // Its a hassle to get ConnectNamedPipe to return early,        // so just wack the whole process - yes, this will toast        // any requests in progress, but at least its a clean         // shutdown (its better than TerminateProcess())        exit(0);    }           // FD_SOCKET_SYNC: When in Accept(), select() is used to poll    // the shutdownPending flag - yeah this isn't pretty either    // but its only one process doing it if an Accept mutex is used.    // This at least buys no toasted requests.}/* *-------------------------------------------------------------- * * 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;    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);    }    /*     * 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 (_beginthread(ShutdownRequestThread, 0, shutdownEvent) == -1)        {            return -1;        }    }    if (acceptMutex == INVALID_HANDLE_VALUE)    {        /* If an accept mutex is in the env, use 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;        }         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); */    }    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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -