]> granicus.if.org Git - apache/commitdiff
Added the WindowsSocketsWorkaroud directive for Windows NT/2000/XP
authorAllan K. Edwards <ake@apache.org>
Tue, 4 Mar 2003 22:15:51 +0000 (22:15 +0000)
committerAllan K. Edwards <ake@apache.org>
Tue, 4 Mar 2003 22:15:51 +0000 (22:15 +0000)
to work around problems with certain VPN and Firewall products that
have buggy AcceptEx implementations

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@98890 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
server/mpm/winnt/child.c
server/mpm/winnt/mpm_winnt.c
server/mpm/winnt/mpm_winnt.h

diff --git a/CHANGES b/CHANGES
index 56e910562b25ae7f7c2ccdfbcb7c598f636bf197..267b7d0cd8ee06c3720f8e0143394d1cbe083b13 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,11 @@ Changes with Apache 2.1.0-dev
 
   [Remove entries to the current 2.0 section below, when backported]
 
+  *) Added the WindowsSocketsWorkaroud directive for Windows NT/2000/XP
+     to work around problems with certain VPN and Firewall products that 
+     have buggy AcceptEx implementations.
+     [Allan Edwards w/ suggestions from Bill Stoddard & Bill Rowe]
+
   *) Unescape the supplied wildcard pattern in mod_autoindex. Otherwise
      the pattern will not always match as desired. PR 12596.
      [AndrĂ© Malo]
index 5ca5f7ca4f046a6f80c119533e880fa14085f566..95cabeed02a71fdc6eee9393aa22851ff6e3da87 100644 (file)
@@ -498,7 +498,7 @@ static void winnt_accept(void *lr_)
     PCOMP_CONTEXT context = NULL;
     DWORD BytesRead;
     SOCKET nlsd;
-    int rv;
+    int rv, err_count = 0;
 
     apr_os_sock_get(&nlsd, lr->sd);
 
@@ -538,15 +538,38 @@ static void winnt_accept(void *lr_)
             rv = apr_get_netos_error();
             if ((rv == APR_FROM_OS_ERROR(WSAEINVAL)) ||
                 (rv == APR_FROM_OS_ERROR(WSAENOTSOCK))) {
-                /* Hack alert. Occasionally, TransmitFile will not recycle the 
-                 * accept socket (usually when the client disconnects early). 
-                 * Get a new socket and try the call again.
+                /* Hack alert, we can get here because: 
+                 * 1) Occasionally, TransmitFile will not recycle the accept socket 
+                 *    (usually when the client disconnects early). 
+                 * 2) There is VPN or Firewall software installed with buggy AcceptEx implementation
+                 * 3) The webserver is using a dynamic address and it has changed
                  */
+                Sleep(0);
+                if (++err_count > 1000) { 
+                    apr_int32_t disconnected;
+
+                    /* abitrary socket call to test if the Listening socket is still valid */
+                    apr_status_t listen_rv =  apr_socket_opt_get(lr->sd, APR_SO_DISCONNECTED, &disconnected);
+
+                    if (listen_rv == APR_SUCCESS) {
+                        ap_log_error(APLOG_MARK,APLOG_ERR, listen_rv, ap_server_conf,
+                                     "AcceptEx error: If this occurs constantly and NO requests are being served "
+                                     "try using the WindowsSocketsWorkaround directive set to 'on'.");
+                        err_count = 0;
+                    }
+                    else {
+                        ap_log_error(APLOG_MARK,APLOG_ERR, listen_rv, ap_server_conf,
+                                     "The Listening socket is no longer valid. Dynamic address changed?");
+                        break;
+                    }
+                }
+
                 closesocket(context->accept_socket);
                 context->accept_socket = INVALID_SOCKET;
                 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf,
-                       "winnt_accept: AcceptEx failed due to early client "
-                       "disconnect. Reallocate the accept socket and try again.");
+                       "winnt_accept: AcceptEx failed, either early client disconnect, "
+                       "dynamic address renewal, or incompatible VPN or Firewall software.");
+          
                 continue;
             }
             else if ((rv != APR_FROM_OS_ERROR(ERROR_IO_PENDING)) &&
@@ -558,6 +581,7 @@ static void winnt_accept(void *lr_)
                 Sleep(100);
                 continue;
             }
+            err_count = 0;  
 
             /* Wait for pending i/o. 
              * Wake up once per second to check for shutdown .
@@ -701,7 +725,7 @@ static void worker_main(long thread_num)
         ap_update_child_status_from_indexes(0, thread_num, SERVER_READY, NULL);
 
         /* Grab a connection off the network */
-        if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+        if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS || windows_sockets_workaround == 1) {
             context = win9x_get_connection(context);
         }
         else {
@@ -769,7 +793,7 @@ static void cleanup_thread(HANDLE *handles, int *thread_cnt, int thread_to_clean
 static void create_listener_thread()
 {
     int tid;
-    if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+    if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS || windows_sockets_workaround == 1) {
         _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE) win9x_accept,
                        NULL, 0, &tid);
     } else {
@@ -840,7 +864,7 @@ void child_main(apr_pool_t *pconf)
      * Create the worker thread dispatch IOCompletionPort
      * on Windows NT/2000
      */
-    if (osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) {
+    if (osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS && windows_sockets_workaround != 1) {
         /* Create the worker thread dispatch IOCP */
         ThreadDispatchIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
                                                     NULL,
@@ -1007,7 +1031,7 @@ void child_main(apr_pool_t *pconf)
     }
 
     /* Shutdown the worker threads */
-    if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+    if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS || windows_sockets_workaround == 1) {
         for (i = 0; i < threads_created; i++) {
             add_job(INVALID_SOCKET);
         }
@@ -1065,7 +1089,7 @@ void child_main(apr_pool_t *pconf)
 
     CloseHandle(allowed_globals.jobsemaphore);
     apr_thread_mutex_destroy(allowed_globals.jobmutex);
-    if (osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) {
+    if (osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS && windows_sockets_workaround != 1) {
        apr_thread_mutex_destroy(qlock);
         CloseHandle(qwait_event);
     }
index 0ce69fb6637c1ae47adea8c4a897e1b0d7d632c6..f82c36dbb81166317ec7662f5ec0b912579c7bdd 100644 (file)
@@ -102,6 +102,7 @@ OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */
 static DWORD parent_pid;
 DWORD my_pid;
 
+int windows_sockets_workaround = 0;
 int ap_threads_per_child = 0;
 static int thread_limit = DEFAULT_THREAD_LIMIT;
 static int first_thread_limit = 0;
@@ -217,6 +218,24 @@ static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *ar
     }
     return NULL;
 }
+static const char *set_sockets_workaround (cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    windows_sockets_workaround = 0;
+    if (!strcasecmp(arg, "on")) {
+        windows_sockets_workaround = 1;
+    }
+    else if (strcasecmp(arg, "off")) {
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
+                         "WARNING: setting WindowsSocketsWorkaround to off");
+    }
+    return NULL;
+}
+
 
 static const command_rec winnt_cmds[] = {
 LISTEN_COMMANDS,
@@ -224,6 +243,9 @@ AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF,
   "Number of threads each child creates" ),
 AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF,
   "Maximum worker threads in a server for this run of Apache"),
+AP_INIT_TAKE1("WindowsSocketsWorkaround", set_sockets_workaround, NULL, RSRC_CONF,
+  "Set \"on\" to work around buggy Winsock provider implementations of certain VPN or Firewall software"),
+
 { NULL }
 };
 
index 5046553dd9e662e9a08868cc6df1a5862ca29046..79d72c8b01e528e81cab2028c9d50f21791300ee 100644 (file)
@@ -101,6 +101,7 @@ void mpm_nt_eventlog_stderr_flush(void);
 
 /* From winnt.c: */
 
+extern int windows_sockets_workaround;
 extern OSVERSIONINFO osver;
 extern void clean_child_exit(int);