diff options
Diffstat (limited to 'server/mpm/winnt')
-rw-r--r-- | server/mpm/winnt/child.c | 105 | ||||
-rw-r--r-- | server/mpm/winnt/mpm_winnt.c | 2 | ||||
-rw-r--r-- | server/mpm/winnt/mpm_winnt.h | 2 |
3 files changed, 86 insertions, 23 deletions
diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index 7983851a..c9168b08 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -45,7 +45,22 @@ #ifdef __MINGW32__ #include <mswsock.h> -#endif + +#ifndef WSAID_ACCEPTEX +#define WSAID_ACCEPTEX \ + {0xb5367df1, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +typedef BOOL (WINAPI *LPFN_ACCEPTEX)(SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED); +#endif /* WSAID_ACCEPTEX */ + +#ifndef WSAID_GETACCEPTEXSOCKADDRS +#define WSAID_GETACCEPTEXSOCKADDRS \ + {0xb5367df2, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +typedef VOID (WINAPI *LPFN_GETACCEPTEXSOCKADDRS)(PVOID, DWORD, DWORD, DWORD, + struct sockaddr **, LPINT, + struct sockaddr **, LPINT); +#endif /* WSAID_GETACCEPTEXSOCKADDRS */ + +#endif /* __MINGW32__ */ /* * The Windows MPM uses a queue of completion contexts that it passes @@ -281,6 +296,10 @@ static unsigned int __stdcall winnt_accept(void *lr_) winnt_conn_ctx_t *context = NULL; DWORD BytesRead; SOCKET nlsd; + LPFN_ACCEPTEX lpfnAcceptEx = NULL; + LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockaddrs = NULL; + GUID GuidAcceptEx = WSAID_ACCEPTEX; + GUID GuidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS; core_server_config *core_sconf; const char *accf_name; int rv; @@ -296,7 +315,15 @@ static unsigned int __stdcall winnt_accept(void *lr_) core_sconf = ap_get_core_module_config(ap_server_conf->module_config); accf_name = apr_table_get(core_sconf->accf_map, lr->protocol); - if (strcmp(accf_name, "data") == 0) + if (!accf_name) { + accf = 0; + accf_name = "none"; + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, + APLOGNO(02531) "winnt_accept: Listen protocol '%s' has " + "no known accept filter. Using 'none' instead", + lr->protocol); + } + else if (strcmp(accf_name, "data") == 0) accf = 2; else if (strcmp(accf_name, "connect") == 0) accf = 1; @@ -325,6 +352,24 @@ static unsigned int __stdcall winnt_accept(void *lr_) if (accf > 0) /* 'data' or 'connect' */ { + if (WSAIoctl(nlsd, SIO_GET_EXTENSION_FUNCTION_POINTER, + &GuidAcceptEx, sizeof GuidAcceptEx, + &lpfnAcceptEx, sizeof lpfnAcceptEx, + &BytesRead, NULL, NULL) == SOCKET_ERROR) { + ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), + ap_server_conf, APLOGNO(02322) + "winnt_accept: failed to retrieve AcceptEx, try 'AcceptFilter none'"); + return 1; + } + if (WSAIoctl(nlsd, SIO_GET_EXTENSION_FUNCTION_POINTER, + &GuidGetAcceptExSockaddrs, sizeof GuidGetAcceptExSockaddrs, + &lpfnGetAcceptExSockaddrs, sizeof lpfnGetAcceptExSockaddrs, + &BytesRead, NULL, NULL) == SOCKET_ERROR) { + ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), + ap_server_conf, APLOGNO(02323) + "winnt_accept: failed to retrieve GetAcceptExSockaddrs, try 'AcceptFilter none'"); + return 1; + } /* first, high priority event is an already accepted connection */ events[1] = exit_event; events[2] = max_requests_per_child_event; @@ -421,9 +466,9 @@ reinit: /* target of data or connect upon too many AcceptEx failures */ /* AcceptEx on the completion context. The completion context will be * signaled when a connection is accepted. */ - if (!AcceptEx(nlsd, context->accept_socket, buf, len, - PADDED_ADDR_SIZE, PADDED_ADDR_SIZE, &BytesRead, - &context->overlapped)) { + if (!lpfnAcceptEx(nlsd, context->accept_socket, buf, len, + PADDED_ADDR_SIZE, PADDED_ADDR_SIZE, &BytesRead, + &context->overlapped)) { rv = apr_get_netos_error(); if ((rv == APR_FROM_OS_ERROR(WSAECONNRESET)) || (rv == APR_FROM_OS_ERROR(WSAEACCES))) { @@ -540,9 +585,9 @@ reinit: /* target of data or connect upon too many AcceptEx failures */ /* Get the local & remote address * TODO; error check */ - GetAcceptExSockaddrs(buf, len, PADDED_ADDR_SIZE, PADDED_ADDR_SIZE, - &context->sa_server, &context->sa_server_len, - &context->sa_client, &context->sa_client_len); + lpfnGetAcceptExSockaddrs(buf, len, PADDED_ADDR_SIZE, PADDED_ADDR_SIZE, + &context->sa_server, &context->sa_server_len, + &context->sa_client, &context->sa_client_len); /* For 'data', craft a bucket for our data result * and pass to worker_main as context->overlapped.Pointer @@ -801,12 +846,12 @@ static DWORD __stdcall worker_main(void *thread_num_val) context->sock, thread_num, sbh, context->ba); - if (!c) - { + if (!c) { /* ap_run_create_connection closes the socket on failure */ context->accept_socket = INVALID_SOCKET; - if (e) + if (e) { apr_bucket_free(e); + } continue; } @@ -824,17 +869,14 @@ static DWORD __stdcall worker_main(void *thread_num_val) c->aborted = 1; } - if (e && c->aborted) - { + if (e && c->aborted) { apr_bucket_free(e); } - else - { + else { ap_set_module_config(c->conn_config, &mpm_winnt_module, context); } - if (!c->aborted) - { + if (!c->aborted) { ap_run_process_connection(c); apr_socket_opt_get(context->sock, APR_SO_DISCONNECTED, @@ -908,12 +950,12 @@ static void create_listener_thread(void) } -void child_main(apr_pool_t *pconf) +void child_main(apr_pool_t *pconf, DWORD parent_pid) { apr_status_t status; apr_hash_t *ht; ap_listen_rec *lr; - HANDLE child_events[2]; + HANDLE child_events[3]; HANDLE *child_handles; int listener_started = 0; int threads_created = 0; @@ -923,6 +965,7 @@ void child_main(apr_pool_t *pconf) DWORD tid; int rv; int i; + int num_events; apr_pool_create(&pchild, pconf); apr_pool_tag(pchild, "pchild"); @@ -940,6 +983,16 @@ void child_main(apr_pool_t *pconf) child_events[0] = exit_event; child_events[1] = max_requests_per_child_event; + if (parent_pid != my_pid) { + child_events[2] = OpenProcess(SYNCHRONIZE, FALSE, parent_pid); + num_events = 3; + } + else { + /* presumably -DONE_PROCESS */ + child_events[2] = NULL; + num_events = 2; + } + /* * Wait until we have permission to start accepting connections. * start_mutex is used to ensure that only one child ever @@ -1056,10 +1109,10 @@ void child_main(apr_pool_t *pconf) */ while (1) { #if !APR_HAS_OTHER_CHILD - rv = WaitForMultipleObjects(2, (HANDLE *)child_events, FALSE, INFINITE); + rv = WaitForMultipleObjects(num_events, (HANDLE *)child_events, FALSE, INFINITE); cld = rv - WAIT_OBJECT_0; #else - rv = WaitForMultipleObjects(2, (HANDLE *)child_events, FALSE, 1000); + rv = WaitForMultipleObjects(num_events, (HANDLE *)child_events, FALSE, 1000); cld = rv - WAIT_OBJECT_0; if (rv == WAIT_TIMEOUT) { apr_proc_other_child_refresh_all(APR_OC_REASON_RUNNING); @@ -1080,6 +1133,13 @@ void child_main(apr_pool_t *pconf) "ending."); break; } + else if (cld == 2) { + /* The parent is dead. Shutdown the child process. */ + ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, APLOGNO(02538) + "Child: Parent process exited abruptly. Child process " + "is ending"); + break; + } else { /* MaxConnectionsPerChild event set by the worker threads. * Signal the parent to restart @@ -1245,6 +1305,9 @@ void child_main(apr_pool_t *pconf) apr_pool_destroy(pchild); CloseHandle(exit_event); + if (child_events[2] != NULL) { + CloseHandle(child_events[2]); + } } #endif /* def WIN32 */ diff --git a/server/mpm/winnt/mpm_winnt.c b/server/mpm/winnt/mpm_winnt.c index 4e3b23ce..957af639 100644 --- a/server/mpm/winnt/mpm_winnt.c +++ b/server/mpm/winnt/mpm_winnt.c @@ -1708,7 +1708,7 @@ static int winnt_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s ) ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf, APLOGNO(00453) "Child process is running"); - child_main(pconf); + child_main(pconf, parent_pid); ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf, APLOGNO(00454) "Child process is exiting"); diff --git a/server/mpm/winnt/mpm_winnt.h b/server/mpm/winnt/mpm_winnt.h index 7452f9fb..8fb595b4 100644 --- a/server/mpm/winnt/mpm_winnt.h +++ b/server/mpm/winnt/mpm_winnt.h @@ -90,7 +90,7 @@ AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type); void hold_console_open_on_error(void); /* From child.c: */ -void child_main(apr_pool_t *pconf); +void child_main(apr_pool_t *pconf, DWORD parent_pid); apr_status_t winnt_insert_network_bucket(conn_rec *c, apr_bucket_brigade *bb, apr_socket_t *socket); |