Check unix domain socket functionality
[catagits/fcgi2.git] / libfcgi / os_win32.c
index 4c3cbb1..cb3550f 100755 (executable)
@@ -1,23 +1,19 @@
 /*
  * 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.)
+ *
+ * Copyright (c) 1996 Open Market, Inc.
+ *
+ * See the file "LICENSE" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  */
 #ifndef lint
-static const char rcsid[] = "$Id: os_win32.c,v 1.29 2002/02/24 15:07:03 robs Exp $";
+static const char rcsid[] = "$Id: os_win32.c,v 1.35 2004/01/31 17:47:07 robs Exp $";
 #endif /* not lint */
 
 #define WIN32_LEAN_AND_MEAN 
@@ -28,6 +24,7 @@ static const char rcsid[] = "$Id: os_win32.c,v 1.29 2002/02/24 15:07:03 robs Exp
 #include <stdio.h>
 #include <sys/timeb.h>
 #include <process.h>
+#include <signal.h>
 
 #define DLLAPI  __declspec(dllexport)
 
@@ -223,8 +220,8 @@ static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd)
  *
  *--------------------------------------------------------------
  */
-static void StdinThread(LPDWORD startup){
-
+static void StdinThread(void * startup) 
+{
     int doIo = TRUE;
     unsigned long fd;
     unsigned long bytesRead;
@@ -269,26 +266,30 @@ void OS_ShutdownPending(void)
     shutdownPending = TRUE;
 }
 
-/* XXX Need a shutdown now event */
 static void ShutdownRequestThread(void * arg)
 {
     HANDLE shutdownEvent = (HANDLE) arg;
     
-    if (WaitForSingleObject(shutdownEvent, INFINITE) == WAIT_FAILED)
-    {
-        // Assuming it will happen again, all we can do is exit the thread
-    }
-    else
+    WaitForSingleObject(shutdownEvent, INFINITE);
+
+    shutdownPending = TRUE;
+
+    // emulate the unix behaviour
+    raise(SIGTERM);
+
+    if (listenType == FD_PIPE_SYNC)
     {
-        // "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.
+        // 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.
 }
 
 /*
@@ -1351,7 +1352,7 @@ int OS_AsyncWrite(int fd, int offset, void *buf, int len,
  *
  *--------------------------------------------------------------
  */
-int OS_Close(int fd)
+int OS_Close(int fd, int shutdown_ok)
 {
     int ret = 0;
 
@@ -1366,24 +1367,53 @@ int OS_Close(int fd)
        case FD_PIPE_ASYNC:
        case FD_FILE_SYNC:
        case FD_FILE_ASYNC:
-           break;
+           
+        break;
 
-        case FD_SOCKET_SYNC:
+    case FD_SOCKET_SYNC:
        case FD_SOCKET_ASYNC:
-           /*
-            * Closing a socket that has an async read outstanding causes a
-            * tcp reset and possible data loss.  The shutdown call seems to
-            * prevent this.
-            */
-           shutdown(fdTable[fd].fid.sock, 2);
-           /*
-            * closesocket returns: 0 success, SOCKET_ERROR failure
-            */
-           if (closesocket(fdTable[fd].fid.sock) == SOCKET_ERROR)
-               ret = -1;
-           break;
+
+        /*
+         * shutdown() the send side and then read() from client until EOF
+         * or a timeout expires.  This is done to minimize the potential
+         * that a TCP RST will be sent by our TCP stack in response to 
+         * receipt of additional data from the client.  The RST would
+         * cause the client to discard potentially useful response data.
+         */
+
+        if (shutdown_ok)
+        {
+            if (shutdown(fdTable[fd].fid.sock, SD_SEND) == 0)
+            {
+                struct timeval tv;
+                fd_set rfds;
+                int sock = fdTable[fd].fid.sock;
+                int rv;
+                char trash[1024];
+   
+                FD_ZERO(&rfds);
+
+                do 
+                {
+#pragma warning( disable : 4127 ) 
+                   FD_SET((unsigned) sock, &rfds);
+#pragma warning( default : 4127 )
+                    
+                   tv.tv_sec = 2;
+                   tv.tv_usec = 0;
+                   rv = select(sock + 1, &rfds, NULL, NULL, &tv);
+                }
+                while (rv > 0 && recv(sock, trash, sizeof(trash), 0) > 0);
+            }
+        }
+        
+        closesocket(fdTable[fd].fid.sock);
+
+        break;
+
        default:
-           return -1;          /* fake failure */
+
+           ret = -1;           /* fake failure */
     }
 
     Win32FreeDescriptor(fd);
@@ -1533,7 +1563,7 @@ static int CALLBACK isAddrOKCallback(LPWSABUF  lpCallerId,
 }
 #endif
 
-static printLastError(const char * text)
+static void printLastError(const char * text)
 {
     LPVOID buf;
 
@@ -1767,10 +1797,9 @@ int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
  *
  *----------------------------------------------------------------------
  */
-int OS_IpcClose(int ipcFd)
+int OS_IpcClose(int ipcFd, int shutdown)
 {
-    if (ipcFd == -1)
-        return 0;
+    if (ipcFd == -1) return 0;
 
     /*
      * Catch it if fd is a bogus value
@@ -1778,33 +1807,32 @@ int OS_IpcClose(int ipcFd)
     ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX));
     ASSERT(fdTable[ipcFd].type != FD_UNUSED);
 
-    switch(listenType) {
-
+    switch (listenType) 
+    {
     case FD_PIPE_SYNC:
-       /*
-        * Make sure that the client (ie. a Web Server in this case) has
-        * read all data from the pipe before we disconnect.
-        */
-       if(!FlushFileBuffers(fdTable[ipcFd].fid.fileHandle))
-           return -1;
-       if(DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) {
-           OS_Close(ipcFd);
-           return 0;
-       } else {
-           return -1;
-       }
-       break;
+           /*
+            * Make sure that the client (ie. a Web Server in this case) has
+            * read all data from the pipe before we disconnect.
+            */
+           if (! FlushFileBuffers(fdTable[ipcFd].fid.fileHandle)) return -1;
+
+           if (! DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) return -1;
+
+        /* fall through */
 
     case FD_SOCKET_SYNC:
-       OS_Close(ipcFd);
-        return 0;
-       break;
+
+           OS_Close(ipcFd, shutdown);
+           break;
 
     case FD_UNUSED:
     default:
-       exit(106);
-       break;
+
+           exit(106);
+           break;
     }
+
+    return 0; 
 }
 
 /*