type changes, casts, and arg touching to prevent warnings.
[catagits/fcgi2.git] / libfcgi / os_win32.c
index 6414d67..ff53ad0 100755 (executable)
  *  significantly more enjoyable.)
  */
 #ifndef lint
-static const char rcsid[] = "$Id: os_win32.c,v 1.11 2001/03/27 14:03:21 robs Exp $";
+static const char rcsid[] = "$Id: os_win32.c,v 1.18 2001/06/20 17:02:09 robs Exp $";
 #endif /* not lint */
 
-#include "fcgi_config.h"
-
-#define DLLAPI  __declspec(dllexport)
-
+#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 <Winsock2.h>
-#include <Windows.h>
 
+#define DLLAPI  __declspec(dllexport)
 #include "fcgios.h"
-
-#define ASSERT assert
+#include "fcgimisc.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"
@@ -93,8 +97,6 @@ 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 
@@ -102,6 +104,8 @@ typedef struct FD_TABLE *PFD_TABLE;
  */
 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) */
@@ -141,66 +145,57 @@ static BOOLEAN libInitialized = FALSE;
  */
 static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd)
 {
-    int index;
+    int index = -1;
+
+    EnterCriticalSection(&fdTableCritical);
 
     /*
-     * 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 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) 
+        if (fdTable[desiredFd].type == FD_UNUSED) 
         {
-            return -1;
+            index = desiredFd;
         }
-           index = desiredFd;
        }
-    else
+    else if (fd > 0)
     {
-        // See if the entry that matches "fd" is available.
-
-        if (fd <= 0 || fd >= WIN32_OPEN_MAX)
-        {
-            return -1;
-        }
-
-        if (fdTable[fd].type == FD_UNUSED)
+        if (fd < WIN32_OPEN_MAX && fdTable[fd].type == FD_UNUSED)
         {
                index = fd;
         }
         else 
         {
-            // Find an entry we can use. 
-            // Start at 1 (0 fake id fails in some cases).
+            int i;
 
-            for (index = 1; index < WIN32_OPEN_MAX; index++)
+            for (i = 1; i < WIN32_OPEN_MAX; ++i)
             {
-                   if (fdTable[index].type == FD_UNUSED)
+                   if (fdTable[i].type == FD_UNUSED)
                 {
+                    index = i;
                     break;
                 }
             }
-
-            if (index == WIN32_OPEN_MAX) 
-            {
-                   SetLastError(WSAEMFILE);
-                   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;
+    }
 
-    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;
 }
 
@@ -228,10 +223,13 @@ static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd)
 static void StdinThread(LPDWORD startup){
 
     int doIo = TRUE;
-    int fd;
-    int bytesRead;
+    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
@@ -270,7 +268,7 @@ static DWORD WINAPI ShutdownRequestThread(LPVOID arg)
     if (WaitForSingleObject(shutdownEvent, INFINITE) == WAIT_FAILED)
     {
         // Assuming it will happen again, all we can do is exit the thread
-        return -1;
+        return 1;
     }
     else
     {
@@ -314,6 +312,8 @@ int OS_LibInit(int stdioFds[3])
     if(libInitialized)
         return 0;
 
+    InitializeCriticalSection(&fdTableCritical);   
+        
     /*
      * Initialize windows sockets library.
      */
@@ -559,21 +559,29 @@ 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;
 }
 
 /*
@@ -595,32 +603,42 @@ 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;
 }
 
@@ -636,7 +654,7 @@ static short getPort(const char * bindPath)
         strncpy(buf, p, 6);
         buf[5] = '\0';
 
-        port = atoi(buf);
+        port = (short) atoi(buf);
     }
  
     return port;
@@ -921,45 +939,46 @@ 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;
 }
 
 /*
@@ -981,46 +1000,46 @@ 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;
 }
 
 /*
@@ -1424,8 +1443,8 @@ int OS_CloseRead(int fd)
  */
 int OS_DoIo(struct timeval *tmo)
 {
-    int fd;
-    int bytes;
+    unsigned long fd;
+    unsigned long bytes;
     POVERLAPPED_REQUEST pOv;
     struct timeb tb;
     int ms;
@@ -1480,6 +1499,9 @@ static int CALLBACK isAddrOK(LPWSABUF  lpCallerId,
     const char *okAddrs = (char *) dwCallbackData;
     struct sockaddr *sockaddr = (struct sockaddr *) lpCallerId->buf;
 
+    // Touch the args to avoid warnings
+    dc0 = NULL; dc1 = NULL; dc2 = NULL; dc3 = NULL; dc4 = NULL; dc5 = NULL;
+
     if (okAddrs == NULL || sockaddr->sa_family != AF_INET)
     {
         return TRUE;
@@ -1511,32 +1533,158 @@ static int CALLBACK isAddrOK(LPWSABUF  lpCallerId,
         }
     }
 }
+
+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_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_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
 {
-    /* XXX This is broken for listen_sock & fail_on_intr */
     int ipcFd = -1;
-    BOOL pConnected;
-    SOCKET hSock;
+
+    // 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;
     }
 
@@ -1549,101 +1697,33 @@ int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
     {
         if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED) 
         {
+            printLastError("WaitForSingleObject() failed");
             return -1;
         }
     }
     
     if (shutdownPending) 
     {
-        if (acceptMutex != INVALID_HANDLE_VALUE) 
-        {
-            ReleaseMutex(acceptMutex);
-        }
-        return -1;
+        OS_LibShutdown();
     }
-    
-    if (listenType == FD_PIPE_SYNC) 
+    else if (listenType == FD_PIPE_SYNC) 
     {
-        pConnected = ConnectNamedPipe(hListen, &listenOverlapped) 
-            ? TRUE 
-            : (GetLastError() == ERROR_PIPE_CONNECTED);
-
-        if (! pConnected) 
-        {
-            while (WaitForSingleObject(listenOverlapped.hEvent, 1000) == WAIT_TIMEOUT) 
-            {
-                if (shutdownPending) 
-                {
-                    if (acceptMutex != INVALID_HANDLE_VALUE) 
-                    {
-                        ReleaseMutex(acceptMutex);
-                    }
-                    CancelIo(hListen);
-                    return -1;
-                }            
-            }
-        }
-        
-        if (acceptMutex != INVALID_HANDLE_VALUE) 
-        {
-            ReleaseMutex(acceptMutex);
-        }
-
-        ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1);
-           if (ipcFd == -1) 
-        {
-            DisconnectNamedPipe(hListen);
-        }
+        ipcFd = acceptNamedPipe();
     }
     else if (listenType == FD_SOCKET_SYNC)
     {
-        struct sockaddr sockaddr;
-        int sockaddrLen = sizeof(sockaddr);
-        fd_set readfds;
-        const struct timeval timeout = {1, 0};
-     
-        FD_ZERO(&readfds);
-        FD_SET((unsigned int) hListen, &readfds);
-        
-        while (select(0, &readfds, NULL, NULL, &timeout) == 0)
-        {
-            if (shutdownPending) 
-            {
-                return -1;
-            }
-        }
-        
-        hSock = (webServerAddrs == NULL)
-            ? accept((SOCKET) hListen, 
-                              &sockaddr, 
-                              &sockaddrLen)
-            : WSAAccept((unsigned int) hListen,                    
-                                       &sockaddr,  
-                                       &sockaddrLen,               
-                                       isAddrOK,  
-                               (DWORD) webServerAddrs);
-        
-        if (acceptMutex != INVALID_HANDLE_VALUE) 
-        {
-            ReleaseMutex(acceptMutex);
-        }
-
-        if (hSock == -1) 
-        {
-            return -1;
-        }
-        
-        ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1);
-           if (ipcFd == -1) 
-        {
-               closesocket(hSock);
-           }
+        ipcFd = acceptSocket(webServerAddrs);
     }
     else
     {
-        ASSERT(0);
+        fprintf(stderr, "unknown listenType (%d)\n", listenType);
     }
            
+    if (acceptMutex != INVALID_HANDLE_VALUE) 
+    {
+        ReleaseMutex(acceptMutex);
+    }
+
     return ipcFd;
 }
 
@@ -1719,12 +1799,12 @@ int OS_IpcClose(int ipcFd)
  */
 int OS_IsFcgi(int sock)
 {
+    // Touch args to prevent warnings
+    sock = 0;
+
     /* XXX This is broken for sock */
-    if(listenType == FD_UNUSED) {
-        return FALSE;
-    } else {
-        return TRUE;
-    }
+
+       return (listenType != FD_UNUSED); 
 }
 
 /*