]> granicus.if.org Git - apache/blobdiff - server/mpm_unix.c
promote
[apache] / server / mpm_unix.c
index 2dd43558bb1f508966eb8a65666321b92cdf7d3f..1a7f9359c73b51e0a7dbe178f15114f0464baf7c 100644 (file)
@@ -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 */