Exemple #1
0
static int acceptNamedPipe()
{
    int ipcFd = -1;

#ifdef DEBUG_CGI
	
	FILE *dbg = fopen("c:\\libcgi1.log", "w");
	int i=0;
#endif
#ifdef DEBUG_CGI
	fprintf(dbg,"%d\n",hListen);
	fclose(dbg);		
#endif
	
    if (! ConnectNamedPipe(hListen, NULL))
    {
        switch (GetLastError())
        {
            case ERROR_PIPE_CONNECTED:

                // A client connected after CreateNamedPipe but
                // before ConnectNamedPipe. Its a good connection.

                break;
        
            case ERROR_IO_PENDING:

                // The NamedPipe was opened with an Overlapped structure
                // and there is a pending io operation.  mod_fastcgi 
                // did this in 2.2.12 (fcgi_pm.c v1.52).

            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");
        }
    }

    ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1);
	if (ipcFd == -1) 
    {
        DisconnectNamedPipe(hListen);
    }

    return ipcFd;
}
Exemple #2
0
static int acceptNamedPipe()
{
    int ipcFd = -1;

    if (! ConnectNamedPipe(hListen, NULL))
    {
        switch (GetLastError())
        {
            case ERROR_PIPE_CONNECTED:

                // A client connected after CreateNamedPipe but
                // before ConnectNamedPipe. Its a good connection.

                break;
        
            case ERROR_IO_PENDING:

                // The NamedPipe was opened with an Overlapped structure
                // and there is a pending io operation.  mod_fastcgi 
                // did this in 2.2.12 (fcgi_pm.c v1.52).

            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");
        }
    }

    ASSERT(INT_MIN <= (intptr_t)hListen && (intptr_t)hListen <= INT_MAX);
    ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)(intptr_t)hListen, -1);
	if (ipcFd == -1) 
    {
        DisconnectNamedPipe(hListen);
    }

    return ipcFd;
}
Exemple #3
0
/*
 *----------------------------------------------------------------------
 *
 * 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;
    
    if (port) 
    {
	    struct hostent *hp;
        char *host = NULL;
        struct sockaddr_in sockAddr;
        int sockLen = sizeof(sockAddr);
        SOCKET sock;
        
        if (*bindPath != ':')
        {
            char * p = strchr(bindPath, ':');
            int len = p - bindPath + 1;

            host = malloc(len);
            strncpy(host, bindPath, len);
            host[len] = '\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)) 
        {
	        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);

        hPipe = CreateFile(pipePath,
			    GENERIC_WRITE | GENERIC_READ,
			    FILE_SHARE_READ | FILE_SHARE_WRITE,
			    NULL,
			    OPEN_EXISTING,
			    FILE_FLAG_OVERLAPPED,
			    NULL);

        free(pipePath);

        if( hPipe == INVALID_HANDLE_VALUE) 
        {
            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;    
}
Exemple #4
0
/*
 * 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 pseudoFd = -1;
    short port = getPort(bindPath);

    if (acceptMutex == INVALID_HANDLE_VALUE)
    {
        acceptMutex = CreateMutex(NULL, FALSE, NULL);
        if (acceptMutex == NULL) return -2;
        if (! SetHandleInformation(acceptMutex, HANDLE_FLAG_INHERIT, TRUE)) return -3;
    }

    // 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);
    }

    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) 
        {
	        return -4;
	    }

	    if (bind(listenSock, (struct sockaddr *) &sockAddr, sockLen)  )
        {
	        return -12;
	    }

	    if (listen(listenSock, backlog)) 
        {
	        return -5;
	    }

        pseudoFd = Win32NewDescriptor(listenType, listenSock, -1);
        
        if (pseudoFd == -1) 
        {
            closesocket(listenSock);
            return -6;
        }

        hListen = (HANDLE) listenSock;        
    }
    else
    {
        HANDLE hListenPipe = INVALID_HANDLE_VALUE;
        char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
        
        if (! pipePath) 
        {
            return -7;
        }

        strcpy(pipePath, bindPathPrefix);
        strcat(pipePath, bindPath);

        hListenPipe = CreateNamedPipe(pipePath,
		        PIPE_ACCESS_DUPLEX,
		        PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
		        PIPE_UNLIMITED_INSTANCES,
		        4096, 4096, 0, NULL);
        
        free(pipePath);

        if (hListenPipe == INVALID_HANDLE_VALUE)
        {
            return -8;
        }

        if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE))
        {
            return -9;
        }

        pseudoFd = Win32NewDescriptor(listenType, (int) hListenPipe, -1);
        
        if (pseudoFd == -1) 
        {
            CloseHandle(hListenPipe);
            return -10;
        }

        hListen = (HANDLE) hListenPipe;
    }

    return pseudoFd;
}
Exemple #5
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;
    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
     * 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 = (HANDLE) _beginthread(StdinThread, 0, NULL);
	if (hStdinThread == (HANDLE) -1) {
	    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)) {
        DebugBreak();
	exit(99);
    }

    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)) {
        DebugBreak();
	exit(99);
    }
    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;
}
Exemple #6
0
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);

#pragma warning( disable : 4127 ) 
            FD_SET((unsigned int) hListen, &readfds);
#pragma warning( default : 4127 ) 

            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;
}