PCOMP_CONTEXT context = NULL;
DWORD BytesRead;
SOCKET nlsd;
- int rv;
+ int rv, err_count = 0;
apr_os_sock_get(&nlsd, lr->sd);
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)) &&
Sleep(100);
continue;
}
+ err_count = 0;
/* Wait for pending i/o.
* Wake up once per second to check for shutdown .
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 {
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 {
* 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,
}
/* 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);
}
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);
}
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;
}
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,
"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 }
};