Fix includes.
[catagits/fcgi2.git] / libfcgi / os_win32.c
index 082fe84..0fa5795 100755 (executable)
@@ -1,4 +1,4 @@
-/* 
+/*
  * os_win32.c --
  *
  *
@@ -6,9 +6,9 @@
  *  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. 
+ *  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.)
  */
-#ifdef _WIN32
-#define DLLAPI  __declspec(dllexport)
-#endif
-
 #ifndef lint
-static const char rcsid[] = "$Id: os_win32.c,v 1.1 1997/09/16 15:36:33 stanleyg Exp $";
+static const char rcsid[] = "$Id: os_win32.c,v 1.15 2001/06/19 17:11:39 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>
+
+#define DLLAPI  __declspec(dllexport)
 #include "fcgios.h"
+#include "fcgimisc.h"
+
+#define WIN32_OPEN_MAX 128 /* XXX: Small hack */
 
 /*
- * io.c will instantiate globals; all other
- * modules access these variables as externs.
+ * millisecs to wait for a client connection before checking the 
+ * shutdown flag (then go back to waiting for a connection, etc).
  */
-#ifndef EXTRN
-#define EXTRN extern
-#endif
-
-#include <assert.h>
-#include <sys/timeb.h>
+#define ACCEPT_TIMEOUT 1000
 
-#define WIN32_OPEN_MAX 32 /* XXX: Small hack */
-
-#define ASSERT assert
+#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;
@@ -50,12 +51,11 @@ static HANDLE hStdinThread = INVALID_HANDLE_VALUE;
 static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
                                 INVALID_HANDLE_VALUE};
 
-static HANDLE hPipeMutex = INVALID_HANDLE_VALUE;;
-static char pipeMutexEnv[80] = "";
+static HANDLE acceptMutex = INVALID_HANDLE_VALUE;
 
-#define MUTEX_VARNAME "_FCGI_MUTEX_"
+static BOOLEAN shutdownPending = FALSE;
 
-/* 
+/*
  * An enumeration of the file types
  * supported by the FD_TABLE structure.
  *
@@ -78,7 +78,7 @@ typedef union {
     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.
@@ -97,10 +97,15 @@ struct FD_TABLE {
     LPVOID  ovList;            /* List of associated OVERLAPPED_REQUESTs */
 };
 
-typedef struct FD_TABLE *PFD_TABLE;
-
+/* 
+ * 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) */
@@ -112,13 +117,14 @@ typedef struct OVERLAPPED_REQUEST *POVERLAPPED_REQUEST;
 
 static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\";
 
-static int isFastCGI = FALSE;
-static int isCGI = FALSE;
-static int listenType = FD_UNUSED;
+static enum FILE_TYPE listenType = FD_UNUSED;
+
+// XXX This should be a DESCRIPTOR
 static HANDLE hListen = INVALID_HANDLE_VALUE;
-static int libInitialized = 0;
 
-\f
+static OVERLAPPED listenOverlapped;
+static BOOLEAN libInitialized = FALSE;
+
 /*
  *--------------------------------------------------------------
  *
@@ -139,64 +145,60 @@ static int libInitialized = 0;
  */
 static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd)
 {
-    int index;
-
-    /*
-     * If the "desiredFd" is not -1, try to get this entry for our
-     * pseudo file descriptor.  If this is not available, return -1
-     * as the caller wanted to get this mapping.  This is typically
-     * only used for mapping stdio handles.
-     */
-    if ((desiredFd >= 0) &&
-       (desiredFd < WIN32_OPEN_MAX)) {
-
-        if(fdTable[desiredFd].type == FD_UNUSED) {
-           index = desiredFd;
-           goto found_entry;
-        } else {
-           return -1;
-       }
+    int index = -1;
 
-    }
+    EnterCriticalSection(&fdTableCritical);
 
     /*
-     * Next see if the entry that matches "fd" is available.
+     * 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 ((fd > 0) &&
-       (fd < WIN32_OPEN_MAX) && (fdTable[fd].type == FD_UNUSED)) {
-       index = fd;
-       goto found_entry;
+    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;
+                }
+            }
+        }
     }
-
-    /*
-     * Scan entries for one we can use. Start at 1 (0 fake id fails
-     * in some cases). -K*
-     */
-    for (index = 1; index < WIN32_OPEN_MAX; index++)
-       if (fdTable[index].type == FD_UNUSED)
-           break;
-
-    /* If no table entries are available, return error. */
-    if (index == WIN32_OPEN_MAX) {
-       SetLastError(WSAEMFILE);
-       DebugBreak();
-       return -1;
+    
+    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;
     }
 
-found_entry:
-    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;
 }
-\f
+
 /*
  *--------------------------------------------------------------
  *
@@ -206,7 +208,7 @@ found_entry:
  *      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 
+ *      reading from stdin we make it look like it's using I/O
  *      completion ports to perform async I/O.
  *
  * Results:
@@ -224,7 +226,7 @@ static void StdinThread(LPDWORD startup){
     int fd;
     int bytesRead;
     POVERLAPPED_REQUEST pOv;
-    
+
     while(doIo) {
         /*
          * Block until a request to read from stdin comes in or a
@@ -235,7 +237,7 @@ static void StdinThread(LPDWORD startup){
             doIo = 0;
             break;
         }
-       
+
        ASSERT((fd == STDIN_FILENO) || (fd == -1));
         if(fd == -1) {
             doIo = 0;
@@ -245,7 +247,7 @@ static void StdinThread(LPDWORD startup){
 
         if(ReadFile(stdioHandles[STDIN_FILENO], pOv->clientData1, bytesRead,
                     &bytesRead, NULL)) {
-            PostQueuedCompletionStatus(hIoCompPort, bytesRead, 
+            PostQueuedCompletionStatus(hIoCompPort, bytesRead,
                                        STDIN_FILENO, (LPOVERLAPPED)pOv);
         } else {
             doIo = 0;
@@ -256,7 +258,29 @@ static void StdinThread(LPDWORD startup){
     ExitThread(0);
 }
 
-\f
+static DWORD WINAPI ShutdownRequestThread(LPVOID arg)
+{
+    HANDLE shutdownEvent = (HANDLE) arg;
+    
+    if (WaitForSingleObject(shutdownEvent, INFINITE) == WAIT_FAILED)
+    {
+        // Assuming it will happen again, all we can do is exit the thread
+        return -1;
+    }
+    else
+    {
+        // "Simple reads and writes to properly-aligned 32-bit variables are atomic"
+        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;
+    }
+}
+
 /*
  *--------------------------------------------------------------
  *
@@ -278,18 +302,19 @@ int OS_LibInit(int stdioFds[3])
     WSADATA wsaData;
     int err;
     int fakeFd;
-    DWORD pipeMode;
     DWORD threadId;
     char *cLenPtr = NULL;
-    char *mutexPtr = NULL;
-    
+    char *val = NULL;
+        
     if(libInitialized)
         return 0;
 
+    InitializeCriticalSection(&fdTableCritical);   
+        
     /*
      * Initialize windows sockets library.
      */
-    wVersion = MAKEWORD(1,1);
+    wVersion = MAKEWORD(2,0);
     err = WSAStartup( wVersion, &wsaData );
     if (err) {
         fprintf(stderr, "Error starting Windows Sockets.  Error: %d",
@@ -311,6 +336,35 @@ int OS_LibInit(int stdioFds[3])
     }
 
     /*
+     * 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);
+
+        putenv(SHUTDOWN_EVENT_NAME"=");
+
+        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
@@ -324,10 +378,25 @@ int OS_LibInit(int stdioFds[3])
      */
     if((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
        (GetStdHandle(STD_ERROR_HANDLE)  == INVALID_HANDLE_VALUE) &&
-       (GetStdHandle(STD_INPUT_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;
+        }
 
-        hListen = GetStdHandle(STD_INPUT_HANDLE);
-        isFastCGI = TRUE;
+        CloseHandle(oldStdIn);
 
        /*
         * Set the pipe handle state so that it operates in wait mode.
@@ -338,20 +407,13 @@ int OS_LibInit(int stdioFds[3])
         * XXX: Initial assumption is that SetNamedPipeHandleState will
         *      fail if this is an IP socket...
         */
-        pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT;
-        if(SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL)) {
+        if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL)) 
+        {
             listenType = FD_PIPE_SYNC;
-            /*
-             * Lookup the mutex.  If one is found, save it and 
-             * remove it from the env table if it's not already
-             * been done.
-             */
-            mutexPtr = getenv(MUTEX_VARNAME);
-            if(mutexPtr != NULL) {
-                hPipeMutex = (HANDLE)atoi(mutexPtr);
-                putenv(MUTEX_VARNAME"=");
-            }
-        } else {
+            listenOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+        } 
+        else 
+        {
             listenType = FD_SOCKET_SYNC;
         }
     }
@@ -363,7 +425,7 @@ int OS_LibInit(int stdioFds[3])
         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
@@ -415,7 +477,7 @@ int OS_LibInit(int stdioFds[3])
        }
     }
 
-    /* 
+    /*
      * Create the thread that will read stdin if the CONTENT_LENGTH
      * is non-zero.
      */
@@ -476,7 +538,6 @@ int OS_LibInit(int stdioFds[3])
     return 0;
 }
 
-\f
 /*
  *--------------------------------------------------------------
  *
@@ -495,24 +556,31 @@ int OS_LibInit(int stdioFds[3])
 void OS_LibShutdown()
 {
 
-    if(hIoCompPort != INVALID_HANDLE_VALUE) {
+    if (hIoCompPort != INVALID_HANDLE_VALUE) 
+    {
         CloseHandle(hIoCompPort);
-       hIoCompPort = INVALID_HANDLE_VALUE;
+        hIoCompPort = INVALID_HANDLE_VALUE;
     }
 
-    if(hStdinCompPort != INVALID_HANDLE_VALUE) {
+    if (hStdinCompPort != INVALID_HANDLE_VALUE) 
+    {
         CloseHandle(hStdinCompPort);
-       hStdinCompPort = INVALID_HANDLE_VALUE;
+        hStdinCompPort = INVALID_HANDLE_VALUE;
     }
 
-    /*
-     * Shutdown the socket library.
-     */
+    if (acceptMutex != INVALID_HANDLE_VALUE) 
+    {
+        ReleaseMutex(acceptMutex);
+    }
+
+    DisconnectNamedPipe(hListen);
+
+    CancelIo(hListen);
+
+
     WSACleanup();
-    return;
 }
 
-\f
 /*
  *--------------------------------------------------------------
  *
@@ -532,36 +600,63 @@ static void Win32FreeDescriptor(int fd)
 {
     /* 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_FILE_SYNC:
-       case FD_FILE_ASYNC:
-           /* Free file path string */
-           ASSERT(fdTable[fd].path != NULL);
-           free(fdTable[fd].path);
-           fdTable[fd].path = NULL;
-           break;
-       default:
-           /*
-            * Break through to generic fdTable free-descriptor code
-            */
-           break;
+    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;
+
+           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;
+        }
     }
-    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;
 }
 
-\f
+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 = atoi(buf);
+    }
+    return port;
+}
+
 /*
  * OS_CreateLocalIpcFd --
  *
@@ -580,130 +675,121 @@ static void Win32FreeDescriptor(int fd)
  *
  *----------------------------------------------------------------------
  */
-int OS_CreateLocalIpcFd(char *bindPath)
+int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
 {
-    int retFd = -1;
-    SECURITY_ATTRIBUTES     sa;
-    HANDLE hListenPipe = INVALID_HANDLE_VALUE;
-    char *localPath;
-    SOCKET listenSock;
-    int bpLen;
-    int servLen;
-    struct  sockaddr_in        sockAddr;
-    char    host[1024];
-    short   port;
-    int            tcp = FALSE;
-    int flag = 1;
-    char    *tp;
-    
-    strcpy(host, bindPath);
-    if((tp = strchr(host, ':')) != 0) {
-       *tp++ = 0;
-       if((port = atoi(tp)) == 0) {
-           *--tp = ':';
-        } else {
-           tcp = TRUE;
-        }
+    int pseudoFd = -1;
+    short port = getPort(bindPath);
+    HANDLE mutex = CreateMutex(NULL, FALSE, NULL);
+    char * mutexEnvString;
+
+    if (mutex == NULL)
+    {
+        return -1;
     }
-    if(tcp && (*host && strcmp(host, "localhost") != 0)) {
-       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 (! SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE))
+    {
+        return -1;
     }
 
-    if(tcp) {
-       listenSock = socket(AF_INET, SOCK_STREAM, 0);
-        if(listenSock == SOCKET_ERROR) {
-           return -1;
-       }
-       /*
-        * Bind the listening socket.
-        */
-       memset((char *) &sockAddr, 0, sizeof(sockAddr));
-       sockAddr.sin_family = AF_INET;
-       sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
-       sockAddr.sin_port = htons(port);
-       servLen = sizeof(sockAddr);
-
-       if(bind(listenSock, (struct sockaddr *) &sockAddr, servLen) < 0
-          || listen(listenSock, 5) < 0) {
-           perror("bind/listen");
-           exit(errno);
-       }
+    // This is a nail for listening to more than one port..
+    // This should really be handled by the caller.
 
-       retFd = Win32NewDescriptor(FD_SOCKET_SYNC, (int)listenSock, -1);
-       return retFd;
-    }
+    mutexEnvString = malloc(strlen(MUTEX_VARNAME) + 7);
+    sprintf(mutexEnvString, MUTEX_VARNAME "=%d", (int) mutex);
+    putenv(mutexEnvString);
 
-  
-    /*
-     * Initialize the SECURITY_ATTRIUBTES structure.
-     */
-    sa.nLength = sizeof(sa);
-    sa.lpSecurityDescriptor = NULL;
-    sa.bInheritHandle = TRUE;       /* This will be inherited by the
-                                     * FastCGI process
-                                     */
+    // There's nothing to be gained (at the moment) by a shutdown Event    
 
-    /*
-     * Create a mutex to be used to synchronize access to accepting a
-     * connection on a named pipe.  We don't want to own this at creation
-     * time but would rather let the first process that goes for it
-     * be able to acquire it.
-     */
-    hPipeMutex = CreateMutex(NULL, FALSE, NULL);
-    if(hPipeMutex == NULL) {
-        return -1;
-    }
-    if(!SetHandleInformation(hPipeMutex, HANDLE_FLAG_INHERIT,
-                                 TRUE)) {
-        return -1;
+    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);
     }
-    sprintf(pipeMutexEnv, "%s=%d", MUTEX_VARNAME, (int)hPipeMutex);
-    putenv(pipeMutexEnv);
 
-    /*
-     * Create a unique name to be used for the socket bind path.
-     * Make sure that this name is unique and that there's no process
-     * bound to it.
-     *
-     * Named Pipe Pathname: \\.\pipe\FastCGI\OM_WS.pid.N
-     * Where: N is the pipe instance on the machine.
-     *
-     */
-    bpLen = (int)strlen(bindPathPrefix);
-    bpLen += strlen(bindPath);
-    localPath = malloc(bpLen+2);
-    strcpy(localPath, bindPathPrefix);
-    strcat(localPath, bindPath);
+    listenType = (port) ? FD_SOCKET_SYNC : FD_PIPE_ASYNC;
     
-    /*
-     * Create and setup the named pipe to be used by the fcgi server.
-     */
-    hListenPipe = CreateNamedPipe(localPath, /* name of pipe */
-                   PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
-                   PIPE_TYPE_BYTE | PIPE_WAIT |
-                   PIPE_READMODE_BYTE,         /* pipe IO type */
-                   PIPE_UNLIMITED_INSTANCES,   /* number of instances */
-                   4096,                       /* size of outbuf (0 == allocate as necessary) */
-                   4096,                               /* size of inbuf */
-                   0, /*1000,*/                /* default time-out value */
-                   &sa);                       /* security attributes */
-    free(localPath);
-    /*
-     * Can't create an instance of the pipe, fail...
-     */
-    if (hListenPipe == INVALID_HANDLE_VALUE) {
-       return -1;
+    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 -1;
+           }
+
+           if (! bind(listenSock, (struct sockaddr *) &sockAddr, sockLen)
+               || ! listen(listenSock, backlog)) 
+        {
+               return -1;
+           }
+
+        pseudoFd = Win32NewDescriptor(listenType, listenSock, -1);
+        
+        if (pseudoFd == -1) 
+        {
+            closesocket(listenSock);
+            return -1;
+        }
+
+        hListen = (HANDLE) listenSock;        
+    }
+    else
+    {
+        HANDLE hListenPipe = INVALID_HANDLE_VALUE;
+        char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
+        
+        if (! pipePath) 
+        {
+            return -1;
+        }
+
+        strcpy(pipePath, bindPathPrefix);
+        strcat(pipePath, bindPath);
+
+        hListenPipe = CreateNamedPipe(pipePath,
+                       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                       PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
+                       PIPE_UNLIMITED_INSTANCES,
+                       4096, 4096, 0, NULL);
+        
+        free(pipePath);
+
+        if (hListenPipe == INVALID_HANDLE_VALUE)
+        {
+            return -1;
+        }
+
+        if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE))
+        {
+            return -1;
+        }
+
+        pseudoFd = Win32NewDescriptor(listenType, (int) hListenPipe, -1);
+        
+        if (pseudoFd == -1) 
+        {
+            CloseHandle(hListenPipe);
+            return -1;
+        }
+
+        hListen = (HANDLE) hListenPipe;
     }
 
-    retFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)hListenPipe, -1);
-    return retFd;
+    return pseudoFd;
 }
 
-\f
 /*
  *----------------------------------------------------------------------
  *
@@ -722,101 +808,115 @@ int OS_CreateLocalIpcFd(char *bindPath)
  */
 int OS_FcgiConnect(char *bindPath)
 {
-    char *pipePath = NULL;
-    HANDLE hPipe;
-    int pseudoFd, err;
-
-    struct  sockaddr_in        sockAddr;
-    int servLen, resultSock;
-    int connectStatus;
-    char    *tp;
-    char    host[1024];
-    short   port;
-    int            tcp = FALSE;
-
-    strcpy(host, bindPath);
-    if((tp = strchr(host, ':')) != 0) {
-       *tp++ = 0;
-       if((port = atoi(tp)) == 0) {
-           *--tp = ':';
-        } else {
-           tcp = TRUE;
-        }
-    }
-    if(tcp == TRUE) {
-       struct  hostent *hp;
-       if((hp = gethostbyname((*host ? host : "localhost"))) == NULL) {
-           fprintf(stderr, "Unknown host: %s\n", bindPath);
-           exit(1000);
-       }
-       sockAddr.sin_family = AF_INET;
-       memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length);
-       sockAddr.sin_port = htons(port);
-       servLen = sizeof(sockAddr);
-       resultSock = socket(AF_INET, SOCK_STREAM, 0);
-
-       assert(resultSock >= 0);
-       connectStatus = connect(resultSock, (struct sockaddr *)
-                               &sockAddr, servLen);
-       if(connectStatus < 0) {
-           /*
-            * Most likely (errno == ENOENT || errno == ECONNREFUSED)
-            * and no FCGI application server is running.
-            */
-           closesocket(resultSock);
-           return -1;
-       }
-       pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, resultSock, -1);
-       if(pseudoFd == -1) {
-           closesocket(resultSock);
-       }
-       return pseudoFd;
-    }
+    short port = getPort(bindPath);
+    int pseudoFd = -1;
     
-    /*
-     * Not a TCP connection, create and connect to a named pipe.
-     */
-    pipePath = malloc((size_t)(strlen(bindPathPrefix) + strlen(bindPath) + 2));
-    if(pipePath == NULL) {
-        return -1;
-    }
-    strcpy(pipePath, bindPathPrefix);
-    strcat(pipePath, bindPath);
-
-    hPipe = CreateFile (pipePath, 
-                       /* Generic access, read/write. */
-                       GENERIC_WRITE | GENERIC_READ,
-                       /* Share both read and write. */
-                       FILE_SHARE_READ | FILE_SHARE_WRITE ,
-                       NULL,                  /* No security.*/
-                       OPEN_EXISTING,         /* Fail if not existing. */
-                       FILE_FLAG_OVERLAPPED,  /* Use overlap. */
-                       NULL);                 /* No template. */
-
-    free(pipePath);
-    if(hPipe == INVALID_HANDLE_VALUE) {
-        return -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;
+        }
 
-    if ((pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int)hPipe, -1)) == -1) {
-        CloseHandle(hPipe);
-        return -1;
-    } else {
+        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)) {
-           err = GetLastError();
-           Win32FreeDescriptor(pseudoFd);
-           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;
+
+    return pseudoFd;    
 }
-     
-\f
+
 /*
  *--------------------------------------------------------------
  *
@@ -836,47 +936,48 @@ int OS_FcgiConnect(char *bindPath)
 int OS_Read(int fd, char * buf, size_t len)
 {
     DWORD bytesRead;
-    int ret;
+    int ret = -1;
 
-    /*
-     * Catch any bogus fd values
-     */
     ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
 
-    switch (fdTable[fd].type) {
+    switch (fdTable[fd].type) 
+    {
        case FD_FILE_SYNC:
        case FD_FILE_ASYNC:
        case FD_PIPE_SYNC:
        case FD_PIPE_ASYNC:
-           bytesRead = fd;
-           /*
-            * ReadFile returns: TRUE success, FALSE failure
-            */
-           if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead,
-               NULL)) {
-               fdTable[fd].Errno = GetLastError();
-               return -1;
+
+           if (ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, NULL)) 
+        {
+            ret = bytesRead;
+        }
+        else
+        {
+                   fdTable[fd].Errno = GetLastError();
            }
-           return bytesRead;
+
+        break;
 
        case FD_SOCKET_SYNC:
        case FD_SOCKET_ASYNC:
-           /* winsock recv returns n bytes recv'ed, SOCKET_ERROR failure */
-           /*
-            * XXX: Test this with ReadFile.  If it works, remove this code
-            *      to simplify the routine.
-            */
-           if ((ret = recv(fdTable[fd].fid.sock, buf, len, 0)) ==
-               SOCKET_ERROR) {
-               fdTable[fd].Errno = WSAGetLastError();
-               return -1;
+
+        ret = recv(fdTable[fd].fid.sock, buf, len, 0);
+           if (ret == SOCKET_ERROR) 
+        {
+                   fdTable[fd].Errno = WSAGetLastError();
+                   ret = -1;
            }
-           return ret;
-       default:
-               return -1;
+
+        break;
+        
+    default:
+
+        ASSERT(0);
     }
+
+    return ret;
 }
-\f
+
 /*
  *--------------------------------------------------------------
  *
@@ -896,49 +997,48 @@ int OS_Read(int fd, char * buf, size_t len)
 int OS_Write(int fd, char * buf, size_t len)
 {
     DWORD bytesWritten;
-    int ret;
+    int ret = -1;
 
-    /*
-     * Catch any bogus fd values
-     */
-    ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
-    ASSERT((fdTable[fd].type > FD_UNUSED) &&
-          (fdTable[fd].type <= FD_PIPE_ASYNC));
+    ASSERT(fd >= 0 && fd < WIN32_OPEN_MAX);
 
-    switch (fdTable[fd].type) {
+    switch (fdTable[fd].type) 
+    {
        case FD_FILE_SYNC:
        case FD_FILE_ASYNC:
        case FD_PIPE_SYNC:
        case FD_PIPE_ASYNC:
-           bytesWritten = fd;
-           /*
-            * WriteFile returns: TRUE success, FALSE failure
-            */
-           if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len,
-               &bytesWritten, NULL)) {
-               fdTable[fd].Errno = GetLastError();
-               return -1;
+
+        if (WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten, NULL)) 
+        {
+            ret = bytesWritten;
+        }
+        else
+        {
+                   fdTable[fd].Errno = GetLastError();
            }
-           return bytesWritten;
+
+        break;
+
        case FD_SOCKET_SYNC:
        case FD_SOCKET_ASYNC:
-           /* winsock send returns n bytes written, SOCKET_ERROR failure */
-           /*
-            * XXX: Test this with WriteFile.  If it works, remove this code
-            *      to simplify the routine.
-            */
-           if ((ret = send(fdTable[fd].fid.sock, buf, len, 0)) ==
-               SOCKET_ERROR) {
-               fdTable[fd].Errno = WSAGetLastError();
-               return -1;
+
+        ret = send(fdTable[fd].fid.sock, buf, len, 0);
+        if (ret == SOCKET_ERROR) 
+        {
+                   fdTable[fd].Errno = WSAGetLastError();
+                   ret = -1;
            }
-           return ret;
-       default:
-           return -1;
+
+        break;
+
+    default:
+
+        ASSERT(0);
     }
+
+    return ret;
 }
 
-\f
 /*
  *----------------------------------------------------------------------
  *
@@ -987,7 +1087,7 @@ int OS_SpawnChild(char *execPath, int listenFd)
     StartupInfo.hStdInput  = fdTable[listenFd].fid.fileHandle;
     StartupInfo.hStdOutput = INVALID_HANDLE_VALUE;
     StartupInfo.hStdError  = INVALID_HANDLE_VALUE;
-    
+
     /*
      * Make the listener socket inheritable.
      */
@@ -1003,7 +1103,7 @@ int OS_SpawnChild(char *execPath, int listenFd)
      */
     success = CreateProcess(execPath,  /* LPCSTR address of module name */
                        NULL,           /* LPCSTR address of command line */
-                       NULL,           /* Process security attributes */ 
+                       NULL,           /* Process security attributes */
                        NULL,           /* Thread security attributes */
                        TRUE,           /* Inheritable Handes inherited. */
                        0,              /* DWORD creation flags  */
@@ -1018,7 +1118,6 @@ int OS_SpawnChild(char *execPath, int listenFd)
     }
 }
 
-\f
 /*
  *--------------------------------------------------------------
  *
@@ -1026,7 +1125,7 @@ int OS_SpawnChild(char *execPath, int listenFd)
  *
  *     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 
+ *      capable of performing asynchronous I/O so we send a
  *      message to the StdinThread to do the synchronous read.
  *
  * Results:
@@ -1038,7 +1137,7 @@ int OS_SpawnChild(char *execPath, int listenFd)
  *
  *--------------------------------------------------------------
  */
-int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, 
+int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr,
                       ClientData clientData)
 {
     POVERLAPPED_REQUEST pOv;
@@ -1058,7 +1157,6 @@ int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr,
     return 0;
 }
 
-\f
 /*
  *--------------------------------------------------------------
  *
@@ -1135,7 +1233,7 @@ int OS_AsyncRead(int fd, int offset, void *buf, int len,
     }
     return 0;
 }
-\f
+
 /*
  *--------------------------------------------------------------
  *
@@ -1159,7 +1257,7 @@ int OS_AsyncRead(int fd, int offset, void *buf, int len,
  *
  *--------------------------------------------------------------
  */
-int OS_AsyncWrite(int fd, int offset, void *buf, int len, 
+int OS_AsyncWrite(int fd, int offset, void *buf, int len,
                  OS_AsyncProc procPtr, ClientData clientData)
 {
     DWORD bytesWritten;
@@ -1184,35 +1282,35 @@ int OS_AsyncWrite(int fd, int offset, void *buf, int len,
      * 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 
+           } else
                pOv->overlapped.Offset = fdTable[fd].offset;
        else
            pOv->overlapped.Offset = offset;
@@ -1237,7 +1335,6 @@ int OS_AsyncWrite(int fd, int offset, void *buf, int len,
     return 0;
 }
 
-\f
 /*
  *--------------------------------------------------------------
  *
@@ -1270,13 +1367,9 @@ int OS_Close(int fd)
        case FD_PIPE_ASYNC:
        case FD_FILE_SYNC:
        case FD_FILE_ASYNC:
-           /*
-            * CloseHandle returns: TRUE success, 0 failure
-            */
-           if (CloseHandle(fdTable[fd].fid.fileHandle) == FALSE)
-               ret = -1;
            break;
-       case FD_SOCKET_SYNC:
+
+        case FD_SOCKET_SYNC:
        case FD_SOCKET_ASYNC:
            /*
             * Closing a socket that has an async read outstanding causes a
@@ -1297,7 +1390,7 @@ int OS_Close(int fd)
     Win32FreeDescriptor(fd);
     return ret;
 }
-\f
+
 /*
  *--------------------------------------------------------------
  *
@@ -1327,7 +1420,7 @@ int OS_CloseRead(int fd)
        ret = -1;
     return ret;
 }
-\f
+
 /*
  *--------------------------------------------------------------
  *
@@ -1354,7 +1447,7 @@ int OS_DoIo(struct timeval *tmo)
     int ms;
     int ms_last;
     int err;
-    
+
     /* XXX
      * We can loop in here, but not too long, as wait handlers
      * must run.
@@ -1375,7 +1468,7 @@ int OS_DoIo(struct timeval *tmo)
            err = WSAGetLastError();
            return 0; /* timeout */
         }
-       
+
        ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
        /* call callback if descriptor still valid */
        ASSERT(pOv);
@@ -1390,129 +1483,246 @@ int OS_DoIo(struct timeval *tmo)
     return 0;
 }
 
-\f
+
+static int CALLBACK isAddrOK(LPWSABUF  lpCallerId,
+                             LPWSABUF  dc0,
+                             LPQOS     dc1,
+                             LPQOS     dc2,
+                             LPWSABUF  dc3,
+                             LPWSABUF  dc4,
+                             GROUP     *dc5,
+                             DWORD     dwCallbackData)
+{
+    const char *okAddrs = (char *) dwCallbackData;
+    struct sockaddr *sockaddr = (struct sockaddr *) lpCallerId->buf;
+
+    if (okAddrs == NULL || sockaddr->sa_family != AF_INET)
+    {
+        return TRUE;
+    }
+    else
+    {
+        static const char *token = " ,;:\t";
+        struct sockaddr_in * inet_sockaddr = (struct sockaddr_in *) sockaddr;
+        char *ipaddr = inet_ntoa(inet_sockaddr->sin_addr);
+        char *p = strstr(okAddrs, ipaddr);
+
+        if (p == NULL)
+        {
+            return FALSE;
+        }
+        else if (p == okAddrs)
+        {
+            p += strlen(ipaddr);
+            return (strchr(token, *p) != NULL);
+        }
+        else if (strchr(token, *--p))
+        {
+            p += strlen(ipaddr) + 1;
+            return (strchr(token, *p) != NULL);
+        }
+        else
+        {
+            return FALSE;
+        }
+    }
+}
+
+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");
+        }
+    }
+
+    ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1);
+       if (ipcFd == -1) 
+    {
+        DisconnectNamedPipe(hListen);
+    }
+
+    return ipcFd;
+}
+
+static int acceptSocket(const char *webServerAddrs)
+{
+    struct sockaddr sockaddr;
+    int sockaddrLen = sizeof(sockaddr);
+    fd_set readfds;
+    const struct timeval timeout = {1, 0};
+    SOCKET hSock;
+    int ipcFd = -1;
+    FD_ZERO(&readfds);
+    FD_SET((unsigned int) hListen, &readfds);
+    
+    while (select(0, &readfds, NULL, NULL, &timeout) == 0)
+    {
+        if (shutdownPending) 
+        {
+            OS_LibShutdown();
+            return -1;
+        }
+    }
+    
+    hSock = (webServerAddrs == NULL)
+        ? accept((SOCKET) hListen, 
+                          &sockaddr, 
+                          &sockaddrLen)
+        : WSAAccept((unsigned int) hListen,                    
+                                   &sockaddr,  
+                                   &sockaddrLen,               
+                                   isAddrOK,  
+                           (DWORD) webServerAddrs);
+    
+
+    if (hSock == INVALID_SOCKET) 
+    {
+        // Can I 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_FcgiIpcAccept --
+ * OS_Accept --
  *
- *     Accepts a new FastCGI connection.  This routine knows whether
- *      we're dealing with TCP based sockets or NT Named Pipes for IPC.
+ *  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.
  *
- * Side effects:
- *      New IPC connection is accepted.
- *
  *----------------------------------------------------------------------
  */
-int OS_FcgiIpcAccept(char *serverHostList)
+int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
 {
-    struct sockaddr_in sa;
-    int isNewConnection;
     int ipcFd = -1;
-    BOOL pConnected;
-    HANDLE hDup;
-    SOCKET hSock;
-    int clilen = sizeof(sa);
-    DWORD waitForStatus;
-    
-    switch(listenType) {
 
-    case FD_PIPE_SYNC:
-        waitForStatus = WaitForSingleObject(hPipeMutex,INFINITE);
-        switch(waitForStatus) {
-        case WAIT_OBJECT_0:
-        case WAIT_ABANDONED:
-            break;
+    // @todo Muliple listen sockets and sockets other than 0 are not
+    // supported due to the use of globals.
+    if (listen_sock != (int) hListen)
+    {
+        fprintf(stderr, "illegal listen_sock value (%d) for OS_Accept()\n", listen_sock);
+        return -1;
+    }
 
-        case WAIT_FAILED:
-        default:
-            return -1;
-        }
+    if (shutdownPending) 
+    {
+        OS_LibShutdown();
+        return -1;
+    }
 
-        /*
-         * We have the mutex, go for the connection.
-         */
-       pConnected = ConnectNamedPipe(hListen, NULL) ?
-                             TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
-                                   
-        ReleaseMutex(hPipeMutex);
-           if(pConnected) {
-               /*
-                * Success...
-                */
-               if (!DuplicateHandle(GetCurrentProcess(), hListen,
-                                GetCurrentProcess(), &hDup, 0,
-                                TRUE,          /* allow inheritance */
-                                DUPLICATE_SAME_ACCESS)) {
-                   return -1;
-               }
-               ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)hDup, -1);
-               if(ipcFd == -1) {
-                DisconnectNamedPipe(hListen);
-                CloseHandle(hDup);
-            }
-            return ipcFd;
-        } else {
+    // 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) 
+    {
+        if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED) 
+        {
+            printLastError("WaitForSingleObject() failed");
             return -1;
+        }
     }
-       break;
-
-    case FD_SOCKET_SYNC:
-       hSock = accept((int)hListen, (struct sockaddr *) &sa, &clilen);
-       if(hSock == -1) {
-           return -1;
-       } else if (sa.sin_family != AF_INET) { /* What are we? */
-           closesocket(hSock);
-           hSock = (SOCKET)-1;
-           return -1;
-       } else {
-           char        *tp1, *tp2;
-           int match = 0;
-           if (serverHostList == NULL) 
-               isNewConnection = TRUE;
-           else {
-               tp1 = (char *) malloc(strlen(serverHostList)+1);
-            ASSERT(tp1 != NULL);
-               strcpy(tp1, serverHostList);
-               while(tp1) {
-                   if ((tp2 = strchr(tp1, ',')) != NULL)
-                       *tp2++ = 0;
-                       
-                   if (inet_addr(tp1) == sa.sin_addr.s_addr) {
-                       match = 1;
-                       break;
-                   }
-                   tp1 = tp2;
-               }
-               free(tp1);
-               if (match)
-                   isNewConnection = TRUE;
-               else {
-                   closesocket(hSock);
-                   hSock = (SOCKET)-1;
-                   return -1;
-               }
-           }
-       }
-
-       ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1);
-       if(ipcFd == -1) {
-           closesocket(hSock);
-       }
-       return ipcFd;
-       break;
-
-    case FD_UNUSED:
-      default:
-        exit(101);
-       break;
-       
+    
+    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;
 }
-\f
+
 /*
  *----------------------------------------------------------------------
  *
@@ -1530,6 +1740,8 @@ int OS_FcgiIpcAccept(char *serverHostList)
  */
 int OS_IpcClose(int ipcFd)
 {
+    if (ipcFd == -1)
+        return 0;
 
     /*
      * Catch it if fd is a bogus value
@@ -1556,6 +1768,7 @@ int OS_IpcClose(int ipcFd)
 
     case FD_SOCKET_SYNC:
        OS_Close(ipcFd);
+        return 0;
        break;
 
     case FD_UNUSED:
@@ -1563,10 +1776,8 @@ int OS_IpcClose(int ipcFd)
        exit(106);
        break;
     }
-
 }
 
-\f
 /*
  *----------------------------------------------------------------------
  *
@@ -1582,18 +1793,14 @@ int OS_IpcClose(int ipcFd)
  *
  *----------------------------------------------------------------------
  */
-int OS_IsFcgi()
+int OS_IsFcgi(int sock)
 {
-    if(listenType == FD_UNUSED) {
-        isCGI = TRUE;
-        return 0;
-    } else {
-        isCGI = FALSE;
-        return 1;
-    }
+    // This is still broken.  There is not currently a way to differentiate
+    // a CGI from a FCGI pipe (try the Unix method).
+    
+    return (fdTable[sock].type != FD_UNUSED);
 }
 
-\f
 /*
  *----------------------------------------------------------------------
  *
@@ -1606,10 +1813,10 @@ int OS_IsFcgi()
  */
 void OS_SetFlags(int fd, int flags)
 {
-    long int pLong = 1L;
+    unsigned long pLong = 1L;
     int err;
-    
-    if(fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) {
+
+    if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) {
         if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) ==
            SOCKET_ERROR) {
            exit(WSAGetLastError());