X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=server%2Fmpm_unix.c;h=1a7f9359c73b51e0a7dbe178f15114f0464baf7c;hb=c20d5efb4c6f4fca3713c98f98d475bb022523f9;hp=2dd43558bb1f508966eb8a65666321b92cdf7d3f;hpb=c9fd2623da21dc757571e93f8c14344946e59ec7;p=apache diff --git a/server/mpm_unix.c b/server/mpm_unix.c index 2dd43558bb..1a7f9359c7 100644 --- a/server/mpm_unix.c +++ b/server/mpm_unix.c @@ -73,9 +73,9 @@ typedef struct extra_process_t { static extra_process_t *extras; -void ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen) +AP_DECLARE(void) ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen) { - extra_process_t *p = (extra_process_t *)malloc(sizeof(extra_process_t)); + extra_process_t *p = (extra_process_t *)ap_malloc(sizeof(extra_process_t)); p->next = extras; p->pid = pid; @@ -83,7 +83,7 @@ void ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen) extras = p; } -int ap_unregister_extra_mpm_process(pid_t pid, ap_generation_t *gen) +AP_DECLARE(int) ap_unregister_extra_mpm_process(pid_t pid, ap_generation_t *old_gen) { extra_process_t *cur = extras; extra_process_t *prev = NULL; @@ -100,7 +100,7 @@ int ap_unregister_extra_mpm_process(pid_t pid, ap_generation_t *gen) else { extras = cur->next; } - *gen = cur->gen; + *old_gen = cur->gen; free(cur); return 1; /* found */ } @@ -120,7 +120,7 @@ static int reclaim_one_pid(pid_t pid, action_t action) /* Ensure pid sanity. */ if (pid < 1) { return 1; - } + } proc.pid = pid; waitret = apr_proc_wait(&proc, &status, &why, APR_NOWAIT); @@ -137,7 +137,7 @@ static int reclaim_one_pid(pid_t pid, action_t action) case SEND_SIGTERM: /* ok, now it's being annoying */ ap_log_error(APLOG_MARK, APLOG_WARNING, - 0, ap_server_conf, + 0, ap_server_conf, APLOGNO(00045) "child process %" APR_PID_T_FMT " still did not exit, " "sending a SIGTERM", @@ -147,7 +147,7 @@ static int reclaim_one_pid(pid_t pid, action_t action) case SEND_SIGKILL: ap_log_error(APLOG_MARK, APLOG_ERR, - 0, ap_server_conf, + 0, ap_server_conf, APLOGNO(00046) "child process %" APR_PID_T_FMT " still did not exit, " "sending a SIGKILL", @@ -162,7 +162,7 @@ static int reclaim_one_pid(pid_t pid, action_t action) * after the restart. */ ap_log_error(APLOG_MARK, APLOG_ERR, - 0, ap_server_conf, + 0, ap_server_conf, APLOGNO(00047) "could not make child process %" APR_PID_T_FMT " exit, " "attempting to continue anyway", @@ -173,8 +173,8 @@ static int reclaim_one_pid(pid_t pid, action_t action) return 0; } -void ap_reclaim_child_processes(int terminate, - ap_reclaim_callback_fn_t *mpm_callback) +AP_DECLARE(void) ap_reclaim_child_processes(int terminate, + ap_reclaim_callback_fn_t *mpm_callback) { apr_time_t waittime = 1024 * 16; int i; @@ -270,7 +270,7 @@ void ap_reclaim_child_processes(int terminate, action_table[cur_action].action != GIVEUP); } -void ap_relieve_child_processes(ap_reclaim_callback_fn_t *mpm_callback) +AP_DECLARE(void) ap_relieve_child_processes(ap_reclaim_callback_fn_t *mpm_callback) { int i; extra_process_t *cur_extra; @@ -313,7 +313,7 @@ void ap_relieve_child_processes(ap_reclaim_callback_fn_t *mpm_callback) * the pid is a member of the current process group; either using * apr_proc_wait(), where waitpid() guarantees to fail for non-child * processes; or by using getpgid() directly, if available. */ -apr_status_t ap_mpm_safe_kill(pid_t pid, int sig) +AP_DECLARE(apr_status_t) ap_mpm_safe_kill(pid_t pid, int sig) { #ifndef HAVE_GETPGID apr_proc_t proc; @@ -337,7 +337,7 @@ apr_status_t ap_mpm_safe_kill(pid_t pid, int sig) else if (rv != APR_CHILD_NOTDONE) { /* The child is already dead and reaped, or was a bogus pid - * log this either way. */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, ap_server_conf, + ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, ap_server_conf, APLOGNO(00048) "cannot send signal %d to pid %ld (non-child or " "already dead)", sig, (long)pid); return APR_EINVAL; @@ -350,25 +350,26 @@ apr_status_t ap_mpm_safe_kill(pid_t pid, int sig) return APR_EINVAL; } - pg = getpgid(pid); + pg = getpgid(pid); if (pg == -1) { /* Process already dead... */ return errno; } if (pg != getpgrp()) { - ap_log_error(APLOG_MARK, APLOG_ALERT, 0, ap_server_conf, + ap_log_error(APLOG_MARK, APLOG_ALERT, 0, ap_server_conf, APLOGNO(00049) "refusing to send signal %d to pid %ld outside " "process group", sig, (long)pid); return APR_EINVAL; } -#endif +#endif return kill(pid, sig) ? errno : APR_SUCCESS; } -int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status) +AP_DECLARE(int) ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, + int status) { int signum = status; const char *sigdesc; @@ -388,7 +389,7 @@ int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status) if (status == APEXIT_CHILDFATAL) { ap_log_error(APLOG_MARK, APLOG_ALERT, - 0, ap_server_conf, + 0, ap_server_conf, APLOGNO(00050) "Child %" APR_PID_T_FMT " returned a Fatal error... Apache is exiting!", pid->pid); @@ -411,7 +412,7 @@ int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status) default: if (APR_PROC_CHECK_CORE_DUMP(why)) { ap_log_error(APLOG_MARK, APLOG_NOTICE, - 0, ap_server_conf, + 0, ap_server_conf, APLOGNO(00051) "child pid %ld exit signal %s (%d), " "possible coredump in %s", (long)pid->pid, sigdesc, signum, @@ -419,7 +420,7 @@ int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status) } else { ap_log_error(APLOG_MARK, APLOG_NOTICE, - 0, ap_server_conf, + 0, ap_server_conf, APLOGNO(00052) "child pid %ld exit signal %s (%d)", (long)pid->pid, sigdesc, signum); } @@ -493,21 +494,122 @@ static apr_status_t pod_signal_internal(ap_pod_t *pod) rv = apr_file_write(pod->pod_out, &char_of_death, &one); if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00053) "write pipe_of_death"); } return rv; } -/* This function connects to the server, then immediately closes the connection. - * This permits the MPM to skip the poll when there is only one listening - * socket, because it provides a alternate way to unblock an accept() when - * the pod is used. - */ +AP_DECLARE(apr_status_t) ap_mpm_podx_open(apr_pool_t *p, ap_pod_t **pod) +{ + apr_status_t rv; + + *pod = apr_palloc(p, sizeof(**pod)); + rv = apr_file_pipe_create(&((*pod)->pod_in), &((*pod)->pod_out), p); + if (rv != APR_SUCCESS) { + return rv; + } + /* + apr_file_pipe_timeout_set((*pod)->pod_in, 0); + */ + (*pod)->p = p; + + /* close these before exec. */ + apr_file_inherit_unset((*pod)->pod_in); + apr_file_inherit_unset((*pod)->pod_out); + + return APR_SUCCESS; +} + +AP_DECLARE(int) ap_mpm_podx_check(ap_pod_t *pod) +{ + char c; + apr_os_file_t fd; + int rc; + + /* we need to surface EINTR so we'll have to grab the + * native file descriptor and do the OS read() ourselves + */ + apr_os_file_get(&fd, pod->pod_in); + rc = read(fd, &c, 1); + if (rc == 1) { + switch (c) { + case AP_MPM_PODX_RESTART_CHAR: + return AP_MPM_PODX_RESTART; + case AP_MPM_PODX_GRACEFUL_CHAR: + return AP_MPM_PODX_GRACEFUL; + } + } + return AP_MPM_PODX_NORESTART; +} + +AP_DECLARE(apr_status_t) ap_mpm_podx_close(ap_pod_t *pod) +{ + apr_status_t rv; + + rv = apr_file_close(pod->pod_out); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_file_close(pod->pod_in); + if (rv != APR_SUCCESS) { + return rv; + } + return rv; +} + +static apr_status_t podx_signal_internal(ap_pod_t *pod, + ap_podx_restart_t graceful) +{ + apr_status_t rv; + apr_size_t one = 1; + char char_of_death = ' '; + switch (graceful) { + case AP_MPM_PODX_RESTART: + char_of_death = AP_MPM_PODX_RESTART_CHAR; + break; + case AP_MPM_PODX_GRACEFUL: + char_of_death = AP_MPM_PODX_GRACEFUL_CHAR; + break; + case AP_MPM_PODX_NORESTART: + break; + } + + rv = apr_file_write(pod->pod_out, &char_of_death, &one); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(02404) + "write pipe_of_death"); + } + return rv; +} + +AP_DECLARE(apr_status_t) ap_mpm_podx_signal(ap_pod_t * pod, + ap_podx_restart_t graceful) +{ + return podx_signal_internal(pod, graceful); +} + +AP_DECLARE(void) ap_mpm_podx_killpg(ap_pod_t * pod, int num, + ap_podx_restart_t graceful) +{ + int i; + apr_status_t rv = APR_SUCCESS; + + for (i = 0; i < num && rv == APR_SUCCESS; i++) { + rv = podx_signal_internal(pod, graceful); + } +} + +/* This function connects to the server and sends enough data to + * ensure the child wakes up and processes a new connection. This + * permits the MPM to skip the poll when there is only one listening + * socket, because it provides a alternate way to unblock an accept() + * when the pod is used. */ static apr_status_t dummy_connection(ap_pod_t *pod) { - char *srequest; + const char *data; apr_status_t rv; apr_socket_t *sock; apr_pool_t *p; @@ -534,7 +636,7 @@ static apr_status_t dummy_connection(ap_pod_t *pod) rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p); if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00054) "get socket to connect to listener"); apr_pool_destroy(p); return rv; @@ -548,7 +650,7 @@ static apr_status_t dummy_connection(ap_pod_t *pod) */ rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00055) "set timeout on socket to connect to listener"); apr_socket_close(sock); apr_pool_destroy(p); @@ -567,28 +669,43 @@ static apr_status_t dummy_connection(ap_pod_t *pod) log_level = APLOG_DEBUG; } - ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, + ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, APLOGNO(00056) "connect to listener on %pI", lp->bind_addr); + apr_pool_destroy(p); + return rv; } - /* Create the request string. We include a User-Agent so that - * adminstrators can track down the cause of the odd-looking - * requests in their logs. - */ - srequest = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ", + if (lp->protocol && strcasecmp(lp->protocol, "https") == 0) { + /* Send a TLS 1.0 close_notify alert. This is perhaps the + * "least wrong" way to open and cleanly terminate an SSL + * connection. It should "work" without noisy error logs if + * the server actually expects SSLv3/TLSv1. With + * SSLv23_server_method() OpenSSL's SSL_accept() fails + * ungracefully on receipt of this message, since it requires + * an 11-byte ClientHello message and this is too short. */ + static const unsigned char tls10_close_notify[7] = { + '\x15', /* TLSPlainText.type = Alert (21) */ + '\x03', '\x01', /* TLSPlainText.version = {3, 1} */ + '\x00', '\x02', /* TLSPlainText.length = 2 */ + '\x01', /* Alert.level = warning (1) */ + '\x00' /* Alert.description = close_notify (0) */ + }; + data = (const char *)tls10_close_notify; + len = sizeof(tls10_close_notify); + } + else /* ... XXX other request types here? */ { + /* Create an HTTP request string. We include a User-Agent so + * that adminstrators can track down the cause of the + * odd-looking requests in their logs. A complete request is + * used since kernel-level filtering may require that much + * data before returning from accept(). */ + data = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ", ap_get_server_description(), " (internal dummy connection)\r\n\r\n", NULL); + len = strlen(data); + } - /* Since some operating systems support buffering of data or entire - * requests in the kernel, we send a simple request, to make sure - * the server pops out of a blocking accept(). - */ - /* XXX: This is HTTP specific. We should look at the Protocol for each - * listener, and send the correct type of request to trigger any Accept - * Filters. - */ - len = strlen(srequest); - apr_socket_send(sock, srequest, &len); + apr_socket_send(sock, data, &len); apr_socket_close(sock); apr_pool_destroy(p); @@ -625,7 +742,12 @@ void ap_mpm_pod_killpg(ap_pod_t *pod, int num) * readers stranded (a number of them could be tied up for * a while serving time-consuming requests) */ + /* Recall: we only worry about IDLE child processes here */ for (i = 0; i < num && rv == APR_SUCCESS; i++) { + if (ap_scoreboard_image->servers[i][0].status != SERVER_READY || + ap_scoreboard_image->servers[i][0].pid == 0) { + continue; + } rv = dummy_connection(pod); } } @@ -636,7 +758,7 @@ static const char *dash_k_arg_noarg = "noarg"; static int send_signal(pid_t pid, int sig) { if (kill(pid, sig) < 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, errno, NULL, + ap_log_error(APLOG_MARK, APLOG_STARTUP, errno, NULL, APLOGNO(00057) "sending signal to server"); return 1; } @@ -655,9 +777,9 @@ int ap_signal_server(int *exit_status, apr_pool_t *pconf) rv = ap_read_pid(pconf, ap_pid_fname, &otherpid); if (rv != APR_SUCCESS) { if (!APR_STATUS_IS_ENOENT(rv)) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, NULL, + ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, NULL, APLOGNO(00058) "Error retrieving pid file %s", ap_pid_fname); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00059) "Remove it before continuing if it is corrupted."); *exit_status = 1; return 1; @@ -777,8 +899,8 @@ void ap_mpm_rewrite_args(process_rec *process) process->argc = mpm_new_argv->nelts; process->argv = (const char * const *)mpm_new_argv->elts; - - if (NULL == dash_k_arg) { + + if (NULL == dash_k_arg) { dash_k_arg = dash_k_arg_noarg; } @@ -848,7 +970,7 @@ static void sig_coredump(int sig) */ if (getpid() == parent_pid) { ap_log_error(APLOG_MARK, APLOG_NOTICE, - 0, ap_server_conf, + 0, ap_server_conf, APLOGNO(00060) "seg fault or similar nasty error detected " "in the parent process"); /* XXX we can probably add some rudimentary cleanup code here, @@ -867,13 +989,14 @@ static void sig_coredump(int sig) */ } -apr_status_t ap_fatal_signal_child_setup(server_rec *s) +AP_DECLARE(apr_status_t) ap_fatal_signal_child_setup(server_rec *s) { my_pid = getpid(); return APR_SUCCESS; } -apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf) +AP_DECLARE(apr_status_t) ap_fatal_signal_setup(server_rec *s, + apr_pool_t *in_pconf) { #ifndef NO_USE_SIGACTION struct sigaction sa; @@ -890,26 +1013,26 @@ apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf) sa.sa_handler = sig_coredump; if (sigaction(SIGSEGV, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGSEGV)"); + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00061) "sigaction(SIGSEGV)"); #ifdef SIGBUS if (sigaction(SIGBUS, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGBUS)"); + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00062) "sigaction(SIGBUS)"); #endif #ifdef SIGABORT if (sigaction(SIGABORT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABORT)"); + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00063) "sigaction(SIGABORT)"); #endif #ifdef SIGABRT if (sigaction(SIGABRT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABRT)"); + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00064) "sigaction(SIGABRT)"); #endif #ifdef SIGILL if (sigaction(SIGILL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGILL)"); + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00065) "sigaction(SIGILL)"); #endif #ifdef SIGFPE if (sigaction(SIGFPE, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGFPE)"); + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00066) "sigaction(SIGFPE)"); #endif #else /* NO_USE_SIGACTION */