httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Allan Edwards <a...@us.ibm.com>
Subject Re: PR 15282 AcceptEx problem
Date Mon, 03 Mar 2003 22:58:01 GMT
William A. Rowe, Jr. wrote:
>>Just to summarize, there are three conditions we need to consider:
>>1) we hit the TransmitFile recycle bug many times in a row
>>2) we have encountered an incompatible firewall or VPN
>>3) the IP address has changed
> 
> 
> You seem to have the failcases easily reproduced.  Would you tack in
> some quick code that simply uses getsockopt(foo) (any option you like)
> to see if simply getting socket options for a now-broken listen socket
> will fail?  

Actually I have not been able to reproduce the AcceptEx error
for 3), however I think the following will address all three
cases and introduces the WindowsSocketsWorkaround directive:

Index: mpm/winnt/child.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/winnt/child.c,v
retrieving revision 1.13
diff -u -d -b -r1.13 child.c
--- mpm/winnt/child.c	28 Feb 2003 14:02:42 -0000	1.13
+++ mpm/winnt/child.c	3 Mar 2003 22:31:15 -0000
@@ -498,7 +498,7 @@
      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 @@
              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 @@
                  Sleep(100);
                  continue;
              }
+            err_count = 0;

              /* Wait for pending i/o.
               * Wake up once per second to check for shutdown .
@@ -701,7 +725,7 @@
          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 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 @@
       * 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 @@
      }

      /* 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 @@

      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: mpm/winnt/mpm_winnt.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/winnt/mpm_winnt.c,v
retrieving revision 1.298
diff -u -d -b -r1.298 mpm_winnt.c
--- mpm/winnt/mpm_winnt.c	3 Feb 2003 17:53:25 -0000	1.298
+++ mpm/winnt/mpm_winnt.c	3 Mar 2003 22:31:15 -0000
@@ -102,6 +102,7 @@
  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 @@
      }
      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 @@
    "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,
+  "Work around the buggy Winsock provider implementations of certain VPN or Firewall software"),
+
  { NULL }
  };

Index: mpm/winnt/mpm_winnt.h
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/winnt/mpm_winnt.h,v
retrieving revision 1.41
diff -u -d -b -r1.41 mpm_winnt.h
--- mpm/winnt/mpm_winnt.h	3 Feb 2003 17:53:25 -0000	1.41
+++ mpm/winnt/mpm_winnt.h	3 Mar 2003 22:31:15 -0000
@@ -101,6 +101,7 @@

  /* From winnt.c: */

+extern int windows_sockets_workaround;
  extern OSVERSIONINFO osver;
  extern void clean_child_exit(int);

I'll also put some doc together for the new directive.
....Allan

Mime
View raw message