From 0c1274ca1d6bb033299d2401424b8474b8ffb9d7 Mon Sep 17 00:00:00 2001 From: "Allan K. Edwards" Date: Tue, 4 Mar 2003 22:15:51 +0000 Subject: [PATCH] Added the WindowsSocketsWorkaroud directive for Windows NT/2000/XP 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 | 5 ++++ server/mpm/winnt/child.c | 46 +++++++++++++++++++++++++++--------- server/mpm/winnt/mpm_winnt.c | 22 +++++++++++++++++ server/mpm/winnt/mpm_winnt.h | 1 + 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index 56e910562b..267b7d0cd8 100644 --- 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] diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index 5ca5f7ca4f..95cabeed02 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -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); } diff --git a/server/mpm/winnt/mpm_winnt.c b/server/mpm/winnt/mpm_winnt.c index 0ce69fb663..f82c36dbb8 100644 --- a/server/mpm/winnt/mpm_winnt.c +++ b/server/mpm/winnt/mpm_winnt.c @@ -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 } }; diff --git a/server/mpm/winnt/mpm_winnt.h b/server/mpm/winnt/mpm_winnt.h index 5046553dd9..79d72c8b01 100644 --- a/server/mpm/winnt/mpm_winnt.h +++ b/server/mpm/winnt/mpm_winnt.h @@ -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); -- 2.40.0