diff options
author | Arno Töll <arno@debian.org> | 2013-12-23 23:50:09 -1100 |
---|---|---|
committer | Arno Töll <arno@debian.org> | 2013-12-23 23:50:09 -1100 |
commit | 86d5cc79d9d6750da8771fdb0c9ab22c19b8ad45 (patch) | |
tree | 5037da70bf37c0ee93f0ea09f054bdfb278befe0 /server | |
parent | 4a336a5b117419c33c29eadd6409c69df78cd586 (diff) | |
download | apache2-86d5cc79d9d6750da8771fdb0c9ab22c19b8ad45.tar.gz |
Imported Upstream version 2.4.7upstream/2.4.7
Diffstat (limited to 'server')
-rw-r--r-- | server/Makefile.in | 3 | ||||
-rw-r--r-- | server/config.c | 32 | ||||
-rw-r--r-- | server/core.c | 1 | ||||
-rw-r--r-- | server/core_filters.c | 10 | ||||
-rw-r--r-- | server/log.c | 13 | ||||
-rw-r--r-- | server/mpm/config.m4 | 11 | ||||
-rw-r--r-- | server/mpm/event/config.m4 | 2 | ||||
-rw-r--r-- | server/mpm/event/config3.m4 | 2 | ||||
-rw-r--r-- | server/mpm/event/event.c | 177 | ||||
-rw-r--r-- | server/mpm/event/pod.c | 113 | ||||
-rw-r--r-- | server/mpm/event/pod.h | 59 | ||||
-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 | ||||
-rw-r--r-- | server/mpm/worker/config3.m4 | 2 | ||||
-rw-r--r-- | server/mpm/worker/pod.c | 113 | ||||
-rw-r--r-- | server/mpm/worker/pod.h | 58 | ||||
-rw-r--r-- | server/mpm/worker/worker.c | 45 | ||||
-rw-r--r-- | server/mpm_common.c | 2 | ||||
-rw-r--r-- | server/mpm_unix.c | 101 | ||||
-rw-r--r-- | server/scoreboard.c | 2 | ||||
-rw-r--r-- | server/util_fcgi.c | 287 | ||||
-rw-r--r-- | server/util_script.c | 14 | ||||
-rw-r--r-- | server/vhost.c | 16 |
24 files changed, 687 insertions, 485 deletions
diff --git a/server/Makefile.in b/server/Makefile.in index 19010759..9663eec7 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -7,7 +7,7 @@ SUBDIRS = mpm LTLIBRARY_NAME = libmain.la LTLIBRARY_SOURCES = \ - config.c log.c main.c vhost.c util.c \ + config.c log.c main.c vhost.c util.c util_fcgi.c \ util_script.c util_md5.c util_cfgtree.c util_ebcdic.c util_time.c \ connection.c listen.c util_mutex.c mpm_common.c mpm_unix.c \ util_charset.c util_cookies.c util_debug.c util_xml.c \ @@ -15,6 +15,7 @@ LTLIBRARY_SOURCES = \ scoreboard.c error_bucket.c protocol.c core.c request.c provider.c \ eoc_bucket.c eor_bucket.c core_filters.c \ util_expr_parse.c util_expr_scan.c util_expr_eval.c + LTLIBRARY_DEPENDENCIES = test_char.h TARGETS = delete-exports $(LTLIBRARY_NAME) $(CORE_IMPLIB_FILE) export_vars.h httpd.exp diff --git a/server/config.c b/server/config.c index c1aae172..265744e3 100644 --- a/server/config.c +++ b/server/config.c @@ -80,6 +80,7 @@ APR_HOOK_STRUCT( APR_HOOK_LINK(quick_handler) APR_HOOK_LINK(optional_fn_retrieve) APR_HOOK_LINK(test_config) + APR_HOOK_LINK(open_htaccess) ) AP_IMPLEMENT_HOOK_RUN_ALL(int, header_parser, @@ -171,6 +172,12 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(int, handler, (request_rec *r), AP_IMPLEMENT_HOOK_RUN_FIRST(int, quick_handler, (request_rec *r, int lookup), (r, lookup), DECLINED) +AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, open_htaccess, + (request_rec *r, const char *dir_name, const char *access_name, + ap_configfile_t **conffile, const char **full_name), + (r, dir_name, access_name, conffile, full_name), + AP_DECLINED) + /* hooks with no args are implemented last, after disabling APR hook probes */ #if defined(APR_HOOK_PROBES_ENABLED) #undef APR_HOOK_PROBES_ENABLED @@ -2073,14 +2080,23 @@ AP_DECLARE(int) ap_process_config_tree(server_rec *s, return OK; } +apr_status_t ap_open_htaccess(request_rec *r, const char *dir_name, + const char *access_name, + ap_configfile_t **conffile, + const char **full_name) +{ + *full_name = ap_make_full_path(r->pool, dir_name, access_name); + return ap_pcfg_openfile(conffile, r->pool, *full_name); +} + AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, request_rec *r, int override, int override_opts, apr_table_t *override_list, - const char *d, const char *access_name) + const char *d, const char *access_names) { ap_configfile_t *f = NULL; cmd_parms parms; - char *filename = NULL; + const char *filename; const struct htaccess_result *cache; struct htaccess_result *new; ap_conf_vector_t *dc = NULL; @@ -2104,15 +2120,11 @@ AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, parms.path = apr_pstrdup(r->pool, d); /* loop through the access names and find the first one */ - while (access_name[0]) { - /* AFAICT; there is no use of the actual 'filename' against - * any canonicalization, so we will simply take the given - * name, ignoring case sensitivity and aliases - */ - filename = ap_make_full_path(r->pool, d, - ap_getword_conf(r->pool, &access_name)); - status = ap_pcfg_openfile(&f, r->pool, filename); + while (access_names[0]) { + const char *access_name = ap_getword_conf(r->pool, &access_names); + filename = NULL; + status = ap_run_open_htaccess(r, d, access_name, &f, &filename); if (status == APR_SUCCESS) { const char *errmsg; ap_directive_t *temptree = NULL; diff --git a/server/core.c b/server/core.c index fb5e34a0..936bf47f 100644 --- a/server/core.c +++ b/server/core.c @@ -4878,6 +4878,7 @@ static void register_hooks(apr_pool_t *p) ap_hook_insert_network_bucket(core_insert_network_bucket, NULL, NULL, APR_HOOK_REALLY_LAST); ap_hook_dirwalk_stat(core_dirwalk_stat, NULL, NULL, APR_HOOK_REALLY_LAST); + ap_hook_open_htaccess(ap_open_htaccess, NULL, NULL, APR_HOOK_REALLY_LAST); /* register the core's insert_filter hook and register core-provided * filters diff --git a/server/core_filters.c b/server/core_filters.c index 0798d2ef..84e11497 100644 --- a/server/core_filters.c +++ b/server/core_filters.c @@ -473,6 +473,8 @@ apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *new_bb) } else if (rv != APR_SUCCESS) { /* The client has aborted the connection */ + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, c, + "core_output_filter: writing data to the network"); c->aborted = 1; } setaside_remaining_output(f, ctx, bb, c); @@ -543,6 +545,8 @@ apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *new_bb) &(ctx->bytes_written), c); if (rv != APR_SUCCESS) { /* The client has aborted the connection */ + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, c, + "core_output_filter: writing data to the network"); c->aborted = 1; return rv; } @@ -554,6 +558,8 @@ apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *new_bb) &(ctx->bytes_written), c); if ((rv != APR_SUCCESS) && (!APR_STATUS_IS_EAGAIN(rv))) { /* The client has aborted the connection */ + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, c, + "core_output_filter: writing data to the network"); c->aborted = 1; return rv; } @@ -739,7 +745,9 @@ static apr_status_t send_brigade_blocking(apr_socket_t *s, pollset.reqevents = APR_POLLOUT; pollset.desc.s = s; apr_socket_timeout_get(s, &timeout); - rv = apr_poll(&pollset, 1, &nsds, timeout); + do { + rv = apr_poll(&pollset, 1, &nsds, timeout); + } while (APR_STATUS_IS_EINTR(rv)); if (rv != APR_SUCCESS) { break; } diff --git a/server/log.c b/server/log.c index f9680a8b..bcfdcdb6 100644 --- a/server/log.c +++ b/server/log.c @@ -509,9 +509,16 @@ int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */, * XXX: This is BS - /dev/null is non-portable * errno-as-apr_status_t is also non-portable */ - if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) { + +#ifdef WIN32 +#define NULL_DEVICE "nul" +#else +#define NULL_DEVICE "/dev/null" +#endif + + if (replace_stderr && freopen(NULL_DEVICE, "w", stderr) == NULL) { ap_log_error(APLOG_MARK, APLOG_CRIT, errno, s_main, APLOGNO(00093) - "unable to replace stderr with /dev/null"); + "unable to replace stderr with %s", NULL_DEVICE); } for (virt = s_main->next; virt; virt = virt->next) { @@ -1255,7 +1262,7 @@ static void log_error_core(const char *file, int line, int module_index, * prepare and log one line */ - if (log_format) { + if (log_format && !info.startup) { len += do_errorlog_format(log_format, &info, errstr + len, MAX_STRING_LEN - len, &errstr_start, &errstr_end, fmt, args); diff --git a/server/mpm/config.m4 b/server/mpm/config.m4 index 0b263cbc..07118bd9 100644 --- a/server/mpm/config.m4 +++ b/server/mpm/config.m4 @@ -38,6 +38,17 @@ AC_CACHE_CHECK([whether APR supports thread-safe pollsets], [ac_cv_have_threadsa fi ]) +dnl See if APR has skiplist +dnl The base httpd prereq is APR 1.4.x, so we don't have to consider +dnl earlier versions. +case $APR_VERSION in + 1.4*) + apr_has_skiplist=no + ;; + *) + apr_has_skiplist=yes +esac + dnl See if this is a forking platform w.r.t. MPMs case $host in *mingw32* | *os2-emx*) diff --git a/server/mpm/event/config.m4 b/server/mpm/event/config.m4 index 351f1acf..c891c758 100644 --- a/server/mpm/event/config.m4 +++ b/server/mpm/event/config.m4 @@ -7,6 +7,8 @@ elif test $have_threaded_sig_graceful != yes; then AC_MSG_RESULT(no - SIG_GRACEFUL cannot be used with a threaded MPM) elif test $ac_cv_have_threadsafe_pollset != yes; then AC_MSG_RESULT(no - APR_POLLSET_THREADSAFE is not supported) +elif test $apr_has_skiplist != yes; then + AC_MSG_RESULT(no - APR skiplist is not available, need APR 1.5.x or later) else AC_MSG_RESULT(yes) APACHE_MPM_SUPPORTED(event, yes, yes) diff --git a/server/mpm/event/config3.m4 b/server/mpm/event/config3.m4 index e7ec6320..8aa1631f 100644 --- a/server/mpm/event/config3.m4 +++ b/server/mpm/event/config3.m4 @@ -2,6 +2,6 @@ dnl ## XXX - Need a more thorough check of the proper flags to use APACHE_SUBST(MOD_MPM_EVENT_LDADD) -APACHE_MPM_MODULE(event, $enable_mpm_event, event.lo fdqueue.lo pod.lo,[ +APACHE_MPM_MODULE(event, $enable_mpm_event, event.lo fdqueue.lo,[ AC_CHECK_FUNCS(pthread_kill) ], , [\$(MOD_MPM_EVENT_LDADD)]) diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index c64b08f5..306837db 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -84,7 +84,6 @@ #include "http_core.h" /* for get_remote_host */ #include "http_connection.h" #include "ap_mpm.h" -#include "pod.h" #include "mpm_common.h" #include "ap_listen.h" #include "scoreboard.h" @@ -92,6 +91,7 @@ #include "mpm_default.h" #include "http_vhost.h" #include "unixd.h" +#include "apr_skiplist.h" #include <signal.h> #include <limits.h> /* for INT_MAX */ @@ -321,7 +321,7 @@ static event_retained_data *retained; #define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t) -static ap_event_pod_t *pod; +static ap_pod_t *pod; /* The event MPM respects a couple of runtime flags that can aid * in debugging. Setting the -DNO_DETACH flag will prevent the root process @@ -790,7 +790,10 @@ static int start_lingering_close_common(event_conn_state_t *cs) apr_atomic_inc32(&lingering_count); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(*q, cs); - cs->pfd.reqevents = APR_POLLIN | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_WRITE ? APR_POLLOUT : + APR_POLLIN) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; rv = apr_pollset_add(event_pollset, &cs->pfd); apr_thread_mutex_unlock(timeout_mutex); if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) { @@ -938,6 +941,7 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc */ cs->pub.state = CONN_STATE_READ_REQUEST_LINE; + cs->pub.sense = CONN_SENSE_DEFAULT; } else { c = cs->c; @@ -946,9 +950,11 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc } if (c->clogging_input_filters && !c->aborted) { - /* Since we have an input filter which 'cloggs' the input stream, - * like mod_ssl, lets just do the normal read from input filters, - * like the Worker MPM does. + /* Since we have an input filter which 'clogs' the input stream, + * like mod_ssl used to, lets just do the normal read from input + * filters, like the Worker MPM does. Filters that need to write + * where they would otherwise read, or read where they would + * otherwise write, should set the sense appropriately. */ apr_atomic_inc32(&clogged_count); ap_run_process_connection(c); @@ -994,7 +1000,10 @@ read_request: cs->expiration_time = ap_server_conf->timeout + apr_time_now(); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(write_completion_q, cs); - cs->pfd.reqevents = APR_POLLOUT | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN : + APR_POLLOUT) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; rc = apr_pollset_add(event_pollset, &cs->pfd); apr_thread_mutex_unlock(timeout_mutex); return; @@ -1017,8 +1026,6 @@ read_request: return; } else if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) { - apr_status_t rc; - /* It greatly simplifies the logic to use a single timeout value here * because the new element can just be added to the end of the list and * it will stay sorted in expiration time sequence. If brand new @@ -1029,6 +1036,7 @@ read_request: */ cs->expiration_time = ap_server_conf->keep_alive_timeout + apr_time_now(); + c->sbh = NULL; apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(keepalive_q, cs); @@ -1042,6 +1050,7 @@ read_request: "process_socket: apr_pollset_add failure"); AP_DEBUG_ASSERT(rc == APR_SUCCESS); } + return; } else if (cs->pub.state == CONN_STATE_SUSPENDED) { apr_atomic_inc32(&suspended_count); @@ -1053,7 +1062,6 @@ read_request: * or timeout. */ c->sbh = NULL; - return; } @@ -1217,34 +1225,44 @@ static void get_worker(int *have_idle_worker_p, int blocking, int *all_busy) } } -/* XXXXXX: Convert to skiplist or other better data structure - * (yes, this is VERY VERY VERY VERY BAD) - */ - /* Structures to reuse */ static APR_RING_HEAD(timer_free_ring_t, timer_event_t) timer_free_ring; -/* Active timers */ -static APR_RING_HEAD(timer_ring_t, timer_event_t) timer_ring; -static apr_thread_mutex_t *g_timer_ring_mtx; +static apr_skiplist *timer_skiplist; + +static int indexing_comp(void *a, void *b) +{ + apr_time_t t1 = (apr_time_t) (((timer_event_t *) a)->when); + apr_time_t t2 = (apr_time_t) (((timer_event_t *) b)->when); + AP_DEBUG_ASSERT(t1); + AP_DEBUG_ASSERT(t2); + return ((t1 < t2) ? -1 : ((t1 > t2) ? 1 : 0)); +} + +static int indexing_compk(void *ac, void *b) +{ + apr_time_t *t1 = (apr_time_t *) ac; + apr_time_t t2 = (apr_time_t) (((timer_event_t *) b)->when); + AP_DEBUG_ASSERT(t2); + return ((*t1 < t2) ? -1 : ((*t1 > t2) ? 1 : 0)); +} + +static apr_thread_mutex_t *g_timer_skiplist_mtx; static apr_status_t event_register_timed_callback(apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton) { - int inserted = 0; - timer_event_t *ep; timer_event_t *te; /* oh yeah, and make locking smarter/fine grained. */ - apr_thread_mutex_lock(g_timer_ring_mtx); + apr_thread_mutex_lock(g_timer_skiplist_mtx); if (!APR_RING_EMPTY(&timer_free_ring, timer_event_t, link)) { te = APR_RING_FIRST(&timer_free_ring); APR_RING_REMOVE(te, link); } else { - /* XXXXX: lol, pool allocation without a context from any thread.Yeah. Right. MPMs Suck. */ - te = ap_malloc(sizeof(timer_event_t)); + te = apr_skiplist_alloc(timer_skiplist, sizeof(timer_event_t)); APR_RING_ELEM_INIT(te, link); } @@ -1254,27 +1272,14 @@ static apr_status_t event_register_timed_callback(apr_time_t t, te->when = t + apr_time_now(); /* Okay, insert sorted by when.. */ - for (ep = APR_RING_FIRST(&timer_ring); - ep != APR_RING_SENTINEL(&timer_ring, - timer_event_t, link); - ep = APR_RING_NEXT(ep, link)) - { - if (ep->when > te->when) { - inserted = 1; - APR_RING_INSERT_BEFORE(ep, te, link); - break; - } - } - - if (!inserted) { - APR_RING_INSERT_TAIL(&timer_ring, te, timer_event_t, link); - } + apr_skiplist_insert(timer_skiplist, (void *)te); - apr_thread_mutex_unlock(g_timer_ring_mtx); + apr_thread_mutex_unlock(g_timer_skiplist_mtx); return APR_SUCCESS; } + /* * Close socket and clean up if remote closed its end while we were in * lingering close. @@ -1296,7 +1301,7 @@ static void process_lingering_close(event_conn_state_t *cs, const apr_pollfd_t * rv = apr_socket_recv(csd, dummybuf, &nbytes); } while (rv == APR_SUCCESS); - if (!APR_STATUS_IS_EOF(rv)) { + if (APR_STATUS_IS_EAGAIN(rv)) { return; } @@ -1437,9 +1442,9 @@ static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy) } } - apr_thread_mutex_lock(g_timer_ring_mtx); - if (!APR_RING_EMPTY(&timer_ring, timer_event_t, link)) { - te = APR_RING_FIRST(&timer_ring); + apr_thread_mutex_lock(g_timer_skiplist_mtx); + te = apr_skiplist_peek(timer_skiplist); + if (te) { if (te->when > now) { timeout_interval = te->when - now; } @@ -1450,7 +1455,7 @@ static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy) else { timeout_interval = apr_time_from_msec(100); } - apr_thread_mutex_unlock(g_timer_ring_mtx); + apr_thread_mutex_unlock(g_timer_skiplist_mtx); rc = apr_pollset_poll(event_pollset, timeout_interval, &num, &out_pfd); if (rc != APR_SUCCESS) { @@ -1473,21 +1478,19 @@ static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy) } now = apr_time_now(); - apr_thread_mutex_lock(g_timer_ring_mtx); - for (ep = APR_RING_FIRST(&timer_ring); - ep != APR_RING_SENTINEL(&timer_ring, - timer_event_t, link); - ep = APR_RING_FIRST(&timer_ring)) - { + apr_thread_mutex_lock(g_timer_skiplist_mtx); + ep = apr_skiplist_peek(timer_skiplist); + while (ep) { if (ep->when < now + EVENT_FUDGE_FACTOR) { - APR_RING_REMOVE(ep, link); + apr_skiplist_pop(timer_skiplist, NULL); push_timer2worker(ep); } else { break; } + ep = apr_skiplist_peek(timer_skiplist); } - apr_thread_mutex_unlock(g_timer_ring_mtx); + apr_thread_mutex_unlock(g_timer_skiplist_mtx); while (num) { pt = (listener_poll_type *) out_pfd->client_data; @@ -1801,9 +1804,9 @@ static void *APR_THREAD_FUNC worker_thread(apr_thread_t * thd, void *dummy) te->cbfunc(te->baton); { - apr_thread_mutex_lock(g_timer_ring_mtx); + apr_thread_mutex_lock(g_timer_skiplist_mtx); APR_RING_INSERT_TAIL(&timer_free_ring, te, timer_event_t, link); - apr_thread_mutex_unlock(g_timer_ring_mtx); + apr_thread_mutex_unlock(g_timer_skiplist_mtx); } } else { @@ -1877,6 +1880,7 @@ static void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy) int loops; int prev_threads_created; int max_recycled_pools = -1; + int good_methods[] = {APR_POLLSET_KQUEUE, APR_POLLSET_PORT, APR_POLLSET_EPOLL}; /* We must create the fd queues before we start up the listener * and worker threads. */ @@ -1915,18 +1919,34 @@ static void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy) } /* Create the main pollset */ - rv = apr_pollset_create(&event_pollset, - threads_per_child, /* XXX don't we need more, to handle + for (i = 0; i < sizeof(good_methods) / sizeof(void*); i++) { + rv = apr_pollset_create_ex(&event_pollset, + threads_per_child*2, /* XXX don't we need more, to handle * connections in K-A or lingering * close? */ - pchild, APR_POLLSET_THREADSAFE | APR_POLLSET_NOCOPY); + pchild, APR_POLLSET_THREADSAFE | APR_POLLSET_NOCOPY | APR_POLLSET_NODEFAULT, + good_methods[i]); + if (rv == APR_SUCCESS) { + break; + } + } + if (rv != APR_SUCCESS) { + rv = apr_pollset_create(&event_pollset, + threads_per_child*2, /* XXX don't we need more, to handle + * connections in K-A or lingering + * close? + */ + pchild, APR_POLLSET_THREADSAFE | APR_POLLSET_NOCOPY); + } if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, "apr_pollset_create with Thread Safety failed."); clean_child_exit(APEXIT_CHILDFATAL); } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02471) + "start_threads: Using %s", apr_pollset_method_name(event_pollset)); worker_sockets = apr_pcalloc(pchild, threads_per_child * sizeof(apr_socket_t *)); @@ -2087,9 +2107,10 @@ static void child_main(int child_num_arg) clean_child_exit(APEXIT_CHILDFATAL); } - apr_thread_mutex_create(&g_timer_ring_mtx, APR_THREAD_MUTEX_DEFAULT, pchild); + apr_thread_mutex_create(&g_timer_skiplist_mtx, APR_THREAD_MUTEX_DEFAULT, pchild); APR_RING_INIT(&timer_free_ring, timer_event_t, link); - APR_RING_INIT(&timer_ring, timer_event_t, link); + apr_skiplist_init(&timer_skiplist, pchild); + apr_skiplist_set_compare(timer_skiplist, indexing_comp, indexing_compk); ap_run_child_init(pchild, ap_server_conf); /* done with init critical section */ @@ -2188,25 +2209,25 @@ static void child_main(int child_num_arg) apr_signal(SIGTERM, dummy_signal_handler); /* Watch for any messages from the parent over the POD */ while (1) { - rv = ap_event_pod_check(pod); - if (rv == AP_NORESTART) { + rv = ap_mpm_podx_check(pod); + if (rv == AP_MPM_PODX_NORESTART) { /* see if termination was triggered while we slept */ switch (terminate_mode) { case ST_GRACEFUL: - rv = AP_GRACEFUL; + rv = AP_MPM_PODX_GRACEFUL; break; case ST_UNGRACEFUL: - rv = AP_RESTART; + rv = AP_MPM_PODX_RESTART; break; } } - if (rv == AP_GRACEFUL || rv == AP_RESTART) { + if (rv == AP_MPM_PODX_GRACEFUL || rv == AP_MPM_PODX_RESTART) { /* make sure the start thread has finished; * signal_threads() and join_workers depend on that */ join_start_thread(start_thread_id); signal_threads(rv == - AP_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL); + AP_MPM_PODX_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL); break; } } @@ -2435,7 +2456,7 @@ static void perform_idle_server_maintenance(void) if (idle_thread_count > max_spare_threads) { /* Kill off one child */ - ap_event_pod_signal(pod, TRUE); + ap_mpm_podx_signal(pod, AP_MPM_PODX_GRACEFUL); retained->idle_spawn_rate = 1; } else if (idle_thread_count < min_spare_threads) { @@ -2666,7 +2687,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) /* Time to shut down: * Kill child processes, tell them to call child_exit, etc... */ - ap_event_pod_killpg(pod, ap_daemons_limit, FALSE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_RESTART); ap_reclaim_child_processes(1, /* Start with SIGTERM */ event_note_child_killed); @@ -2687,7 +2708,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) /* Close our listeners, and then ask our children to do same */ ap_close_listeners(); - ap_event_pod_killpg(pod, ap_daemons_limit, TRUE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_GRACEFUL); ap_relieve_child_processes(event_note_child_killed); if (!child_fatal) { @@ -2727,7 +2748,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) * way, try and make sure that all of our processes are * really dead. */ - ap_event_pod_killpg(pod, ap_daemons_limit, FALSE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_RESTART); ap_reclaim_child_processes(1, event_note_child_killed); return DONE; @@ -2753,7 +2774,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) AP_SIG_GRACEFUL_STRING " received. Doing graceful restart"); /* wake up the children...time to die. But we'll have more soon */ - ap_event_pod_killpg(pod, ap_daemons_limit, TRUE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_GRACEFUL); /* This is mostly for debugging... so that we know what is still @@ -2766,7 +2787,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) * and a SIGHUP, we may as well use the same signal, because some user * pthreads are stealing signals from us left and right. */ - ap_event_pod_killpg(pod, ap_daemons_limit, FALSE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_RESTART); ap_reclaim_child_processes(1, /* Start with SIGTERM */ event_note_child_killed); @@ -2803,13 +2824,15 @@ static int event_open_logs(apr_pool_t * p, apr_pool_t * plog, } if (!one_process) { - if ((rv = ap_event_pod_open(pconf, &pod))) { + if ((rv = ap_mpm_podx_open(pconf, &pod))) { ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, (startup ? NULL : s), "could not open pipe-of-death"); return DONE; } } + /* for skiplist */ + srand((unsigned int)apr_time_now()); return OK; } @@ -2843,6 +2866,18 @@ static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog, } ++retained->module_loads; if (retained->module_loads == 2) { + int i; + static apr_uint32_t foo = 0; + + apr_atomic_inc32(&foo); + apr_atomic_dec32(&foo); + apr_atomic_dec32(&foo); + i = apr_atomic_dec32(&foo); + if (i >= 0) { + ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, APLOGNO(02405) + "atomics not working as expected"); + return HTTP_INTERNAL_SERVER_ERROR; + } rv = apr_pollset_create(&event_pollset, 1, plog, APR_POLLSET_THREADSAFE | APR_POLLSET_NOCOPY); if (rv != APR_SUCCESS) { diff --git a/server/mpm/event/pod.c b/server/mpm/event/pod.c deleted file mode 100644 index 5deed8ba..00000000 --- a/server/mpm/event/pod.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "pod.h" - -#include "apr_portable.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - -APLOG_USE_MODULE(mpm_event); - -AP_DECLARE(apr_status_t) ap_event_pod_open(apr_pool_t * p, ap_event_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_event_pod_check(ap_event_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 RESTART_CHAR: - return AP_RESTART; - case GRACEFUL_CHAR: - return AP_GRACEFUL; - } - } - return AP_NORESTART; -} - -AP_DECLARE(apr_status_t) ap_event_pod_close(ap_event_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 pod_signal_internal(ap_event_pod_t * pod, int graceful) -{ - apr_status_t rv; - char char_of_death = graceful ? GRACEFUL_CHAR : RESTART_CHAR; - apr_size_t one = 1; - - 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(00522) - "write pipe_of_death"); - } - return rv; -} - -AP_DECLARE(apr_status_t) ap_event_pod_signal(ap_event_pod_t * pod, int graceful) -{ - return pod_signal_internal(pod, graceful); -} - -AP_DECLARE(void) ap_event_pod_killpg(ap_event_pod_t * pod, int num, int graceful) -{ - int i; - apr_status_t rv = APR_SUCCESS; - - for (i = 0; i < num && rv == APR_SUCCESS; i++) { - rv = pod_signal_internal(pod, graceful); - } -} diff --git a/server/mpm/event/pod.h b/server/mpm/event/pod.h deleted file mode 100644 index 861e4d99..00000000 --- a/server/mpm/event/pod.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file event/pod.h - * @brief pod definitions - * - * @addtogroup APACHE_MPM_EVENT - * @{ - */ - -#include "apr.h" -#include "apr_strings.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_main.h" -#include "mpm_common.h" -#include "ap_mpm.h" -#include "ap_listen.h" -#include "mpm_default.h" - -#define RESTART_CHAR '$' -#define GRACEFUL_CHAR '!' - -#define AP_RESTART 0 -#define AP_GRACEFUL 1 - -typedef struct ap_event_pod_t ap_event_pod_t; - -struct ap_event_pod_t -{ - apr_file_t *pod_in; - apr_file_t *pod_out; - apr_pool_t *p; -}; - -AP_DECLARE(apr_status_t) ap_event_pod_open(apr_pool_t * p, ap_event_pod_t ** pod); -AP_DECLARE(int) ap_event_pod_check(ap_event_pod_t * pod); -AP_DECLARE(apr_status_t) ap_event_pod_close(ap_event_pod_t * pod); -AP_DECLARE(apr_status_t) ap_event_pod_signal(ap_event_pod_t * pod, int graceful); -AP_DECLARE(void) ap_event_pod_killpg(ap_event_pod_t * pod, int num, int graceful); -/** @} */ 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); diff --git a/server/mpm/worker/config3.m4 b/server/mpm/worker/config3.m4 index dc2bccb5..c28b73bf 100644 --- a/server/mpm/worker/config3.m4 +++ b/server/mpm/worker/config3.m4 @@ -1,5 +1,5 @@ dnl ## XXX - Need a more thorough check of the proper flags to use -APACHE_MPM_MODULE(worker, $enable_mpm_worker, worker.lo fdqueue.lo pod.lo,[ +APACHE_MPM_MODULE(worker, $enable_mpm_worker, worker.lo fdqueue.lo,[ AC_CHECK_FUNCS(pthread_kill) ]) diff --git a/server/mpm/worker/pod.c b/server/mpm/worker/pod.c deleted file mode 100644 index 86f7b39d..00000000 --- a/server/mpm/worker/pod.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "apr_portable.h" -#include "pod.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - -APLOG_USE_MODULE(mpm_worker); - -AP_DECLARE(apr_status_t) ap_worker_pod_open(apr_pool_t *p, ap_worker_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_worker_pod_check(ap_worker_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 RESTART_CHAR: - return AP_RESTART; - case GRACEFUL_CHAR: - return AP_GRACEFUL; - } - } - return AP_NORESTART; -} - -AP_DECLARE(apr_status_t) ap_worker_pod_close(ap_worker_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 pod_signal_internal(ap_worker_pod_t *pod, int graceful) -{ - apr_status_t rv; - char char_of_death = graceful ? GRACEFUL_CHAR : RESTART_CHAR; - apr_size_t one = 1; - - 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(00325) - "write pipe_of_death"); - } - return rv; -} - -AP_DECLARE(apr_status_t) ap_worker_pod_signal(ap_worker_pod_t *pod, int graceful) -{ - return pod_signal_internal(pod, graceful); -} - -AP_DECLARE(void) ap_worker_pod_killpg(ap_worker_pod_t *pod, int num, int graceful) -{ - int i; - apr_status_t rv = APR_SUCCESS; - - for (i = 0; i < num && rv == APR_SUCCESS; i++) { - rv = pod_signal_internal(pod, graceful); - } -} - diff --git a/server/mpm/worker/pod.h b/server/mpm/worker/pod.h deleted file mode 100644 index ccb9cf9d..00000000 --- a/server/mpm/worker/pod.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file worker/pod.h - * @brief Worker MPM Pipe of Death - * - * @addtogroup APACHE_MPM_WORKER - * @{ - */ - -#include "apr.h" -#include "apr_strings.h" -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_main.h" -#include "mpm_common.h" -#include "ap_mpm.h" -#include "ap_listen.h" -#include "mpm_default.h" - -#define RESTART_CHAR '$' -#define GRACEFUL_CHAR '!' - -#define AP_RESTART 0 -#define AP_GRACEFUL 1 - -typedef struct ap_worker_pod_t ap_worker_pod_t; - -struct ap_worker_pod_t { - apr_file_t *pod_in; - apr_file_t *pod_out; - apr_pool_t *p; -}; - -AP_DECLARE(apr_status_t) ap_worker_pod_open(apr_pool_t *p, ap_worker_pod_t **pod); -AP_DECLARE(int) ap_worker_pod_check(ap_worker_pod_t *pod); -AP_DECLARE(apr_status_t) ap_worker_pod_close(ap_worker_pod_t *pod); -AP_DECLARE(apr_status_t) ap_worker_pod_signal(ap_worker_pod_t *pod, int graceful); -AP_DECLARE(void) ap_worker_pod_killpg(ap_worker_pod_t *pod, int num, int graceful); -/** @} */ diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index 4d7a92a7..85b7adb0 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -58,7 +58,6 @@ #include "http_core.h" /* for get_remote_host */ #include "http_connection.h" #include "ap_mpm.h" -#include "pod.h" #include "mpm_common.h" #include "ap_listen.h" #include "scoreboard.h" @@ -189,7 +188,7 @@ typedef struct { #define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t) -static ap_worker_pod_t *pod; +static ap_pod_t *pod; /* The worker MPM respects a couple of runtime flags that can aid * in debugging. Setting the -DNO_DETACH flag will prevent the root process @@ -1130,7 +1129,8 @@ static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) return NULL; } -static void join_workers(apr_thread_t *listener, apr_thread_t **threads) +static void join_workers(apr_thread_t *listener, apr_thread_t **threads, + int mode) { int i; apr_status_t rv, thread_rv; @@ -1174,12 +1174,14 @@ static void join_workers(apr_thread_t *listener, apr_thread_t **threads) for (i = 0; i < threads_per_child; i++) { if (threads[i]) { /* if we ever created this thread */ + if (mode != ST_GRACEFUL) { #ifdef HAVE_PTHREAD_KILL - apr_os_thread_t *worker_os_thread; + apr_os_thread_t *worker_os_thread; - apr_os_thread_get(&worker_os_thread, threads[i]); - pthread_kill(*worker_os_thread, WORKER_SIGNAL); + apr_os_thread_get(&worker_os_thread, threads[i]); + pthread_kill(*worker_os_thread, WORKER_SIGNAL); #endif + } rv = apr_thread_join(&thread_rv, threads[i]); if (rv != APR_SUCCESS) { @@ -1325,7 +1327,7 @@ static void child_main(int child_num_arg) * If the worker hasn't exited, then this blocks until * they have (then cleans up). */ - join_workers(ts->listener, threads); + join_workers(ts->listener, threads, ST_UNGRACEFUL); } else { /* !one_process */ /* remove SIGTERM from the set of blocked signals... if one of @@ -1336,24 +1338,24 @@ static void child_main(int child_num_arg) apr_signal(SIGTERM, dummy_signal_handler); /* Watch for any messages from the parent over the POD */ while (1) { - rv = ap_worker_pod_check(pod); - if (rv == AP_NORESTART) { + rv = ap_mpm_podx_check(pod); + if (rv == AP_MPM_PODX_NORESTART) { /* see if termination was triggered while we slept */ switch(terminate_mode) { case ST_GRACEFUL: - rv = AP_GRACEFUL; + rv = AP_MPM_PODX_GRACEFUL; break; case ST_UNGRACEFUL: - rv = AP_RESTART; + rv = AP_MPM_PODX_RESTART; break; } } - if (rv == AP_GRACEFUL || rv == AP_RESTART) { + if (rv == AP_MPM_PODX_GRACEFUL || rv == AP_MPM_PODX_RESTART) { /* make sure the start thread has finished; * signal_threads() and join_workers depend on that */ join_start_thread(start_thread_id); - signal_threads(rv == AP_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL); + signal_threads(rv == AP_MPM_PODX_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL); break; } } @@ -1365,7 +1367,8 @@ static void child_main(int child_num_arg) * If the worker hasn't exited, then this blocks until * they have (then cleans up). */ - join_workers(ts->listener, threads); + join_workers(ts->listener, threads, + rv == AP_MPM_PODX_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL); } free(threads); @@ -1578,7 +1581,7 @@ static void perform_idle_server_maintenance(void) if (idle_thread_count > max_spare_threads) { /* Kill off one child */ - ap_worker_pod_signal(pod, TRUE); + ap_mpm_podx_signal(pod, AP_MPM_PODX_GRACEFUL); retained->idle_spawn_rate = 1; } else if (idle_thread_count < min_spare_threads) { @@ -1833,7 +1836,7 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) /* Time to shut down: * Kill child processes, tell them to call child_exit, etc... */ - ap_worker_pod_killpg(pod, ap_daemons_limit, FALSE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_RESTART); ap_reclaim_child_processes(1, /* Start with SIGTERM */ worker_note_child_killed); @@ -1854,7 +1857,7 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) /* Close our listeners, and then ask our children to do same */ ap_close_listeners(); - ap_worker_pod_killpg(pod, ap_daemons_limit, TRUE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_GRACEFUL); ap_relieve_child_processes(worker_note_child_killed); if (!child_fatal) { @@ -1894,7 +1897,7 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) * way, try and make sure that all of our processes are * really dead. */ - ap_worker_pod_killpg(pod, ap_daemons_limit, FALSE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_RESTART); ap_reclaim_child_processes(1, worker_note_child_killed); return DONE; @@ -1919,7 +1922,7 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00297) AP_SIG_GRACEFUL_STRING " received. Doing graceful restart"); /* wake up the children...time to die. But we'll have more soon */ - ap_worker_pod_killpg(pod, ap_daemons_limit, TRUE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_GRACEFUL); /* This is mostly for debugging... so that we know what is still @@ -1932,7 +1935,7 @@ static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) * and a SIGHUP, we may as well use the same signal, because some user * pthreads are stealing signals from us left and right. */ - ap_worker_pod_killpg(pod, ap_daemons_limit, FALSE); + ap_mpm_podx_killpg(pod, ap_daemons_limit, AP_MPM_PODX_RESTART); ap_reclaim_child_processes(1, /* Start with SIGTERM */ worker_note_child_killed); @@ -1968,7 +1971,7 @@ static int worker_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, } if (!one_process) { - if ((rv = ap_worker_pod_open(pconf, &pod))) { + if ((rv = ap_mpm_podx_open(pconf, &pod))) { ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, (startup ? NULL : s), "could not open pipe-of-death"); diff --git a/server/mpm_common.c b/server/mpm_common.c index 4448ec60..348e6676 100644 --- a/server/mpm_common.c +++ b/server/mpm_common.c @@ -378,6 +378,7 @@ const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy, return err; } + errno = 0; value = strtol(arg, NULL, 10); if (value < 0 || errno == ERANGE) return apr_pstrcat(cmd->pool, "Invalid MaxMemFree value: ", @@ -397,6 +398,7 @@ const char *ap_mpm_set_thread_stacksize(cmd_parms *cmd, void *dummy, return err; } + errno = 0; value = strtol(arg, NULL, 10); if (value < 0 || errno == ERANGE) return apr_pstrcat(cmd->pool, "Invalid ThreadStackSize value: ", diff --git a/server/mpm_unix.c b/server/mpm_unix.c index 65c09407..063af725 100644 --- a/server/mpm_unix.c +++ b/server/mpm_unix.c @@ -501,6 +501,107 @@ static apr_status_t pod_signal_internal(ap_pod_t *pod) return rv; } +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(2404) + "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 diff --git a/server/scoreboard.c b/server/scoreboard.c index bef2b909..24e9bc61 100644 --- a/server/scoreboard.c +++ b/server/scoreboard.c @@ -389,7 +389,7 @@ AP_DECLARE(void) ap_increment_counts(ap_sb_handle_t *sb, request_rec *r) AP_DECLARE(int) ap_find_child_by_pid(apr_proc_t *pid) { int i; - int max_daemons_limit; + int max_daemons_limit = 0; ap_mpm_query(AP_MPMQ_MAX_DAEMONS, &max_daemons_limit); diff --git a/server/util_fcgi.c b/server/util_fcgi.c new file mode 100644 index 00000000..450f3000 --- /dev/null +++ b/server/util_fcgi.c @@ -0,0 +1,287 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "httpd.h" +#include "http_core.h" +#include "http_log.h" +#include "util_fcgi.h" + +/* we know core's module_index is 0 */ +#undef APLOG_MODULE_INDEX +#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX + +AP_DECLARE(void) ap_fcgi_header_to_array(ap_fcgi_header *h, + unsigned char a[]) +{ + a[AP_FCGI_HDR_VERSION_OFFSET] = h->version; + a[AP_FCGI_HDR_TYPE_OFFSET] = h->type; + a[AP_FCGI_HDR_REQUEST_ID_B1_OFFSET] = h->requestIdB1; + a[AP_FCGI_HDR_REQUEST_ID_B0_OFFSET] = h->requestIdB0; + a[AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET] = h->contentLengthB1; + a[AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET] = h->contentLengthB0; + a[AP_FCGI_HDR_PADDING_LEN_OFFSET] = h->paddingLength; + a[AP_FCGI_HDR_RESERVED_OFFSET] = h->reserved; +} + +AP_DECLARE(void) ap_fcgi_header_from_array(ap_fcgi_header *h, + unsigned char a[]) +{ + h->version = a[AP_FCGI_HDR_VERSION_OFFSET]; + h->type = a[AP_FCGI_HDR_TYPE_OFFSET]; + h->requestIdB1 = a[AP_FCGI_HDR_REQUEST_ID_B1_OFFSET]; + h->requestIdB0 = a[AP_FCGI_HDR_REQUEST_ID_B0_OFFSET]; + h->contentLengthB1 = a[AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET]; + h->contentLengthB0 = a[AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET]; + h->paddingLength = a[AP_FCGI_HDR_PADDING_LEN_OFFSET]; + h->reserved = a[AP_FCGI_HDR_RESERVED_OFFSET]; +} + +AP_DECLARE(void) ap_fcgi_header_fields_from_array(unsigned char *version, + unsigned char *type, + apr_uint16_t *request_id, + apr_uint16_t *content_len, + unsigned char *padding_len, + unsigned char a[]) +{ + *version = a[AP_FCGI_HDR_VERSION_OFFSET]; + *type = a[AP_FCGI_HDR_TYPE_OFFSET]; + *request_id = (a[AP_FCGI_HDR_REQUEST_ID_B1_OFFSET] << 8) + + a[AP_FCGI_HDR_REQUEST_ID_B0_OFFSET]; + *content_len = (a[AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET] << 8) + + a[AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET]; + *padding_len = a[AP_FCGI_HDR_PADDING_LEN_OFFSET]; +} + +AP_DECLARE(void) ap_fcgi_begin_request_body_to_array(ap_fcgi_begin_request_body *h, + unsigned char a[]) +{ + a[AP_FCGI_BRB_ROLEB1_OFFSET] = h->roleB1; + a[AP_FCGI_BRB_ROLEB0_OFFSET] = h->roleB0; + a[AP_FCGI_BRB_FLAGS_OFFSET] = h->flags; + a[AP_FCGI_BRB_RESERVED0_OFFSET] = h->reserved[0]; + a[AP_FCGI_BRB_RESERVED1_OFFSET] = h->reserved[1]; + a[AP_FCGI_BRB_RESERVED2_OFFSET] = h->reserved[2]; + a[AP_FCGI_BRB_RESERVED3_OFFSET] = h->reserved[3]; + a[AP_FCGI_BRB_RESERVED4_OFFSET] = h->reserved[4]; +} + +AP_DECLARE(void) ap_fcgi_fill_in_header(ap_fcgi_header *header, + unsigned char type, + apr_uint16_t request_id, + apr_uint16_t content_len, + unsigned char padding_len) +{ + header->version = AP_FCGI_VERSION_1; + + header->type = type; + + header->requestIdB1 = ((request_id >> 8) & 0xff); + header->requestIdB0 = ((request_id) & 0xff); + + header->contentLengthB1 = ((content_len >> 8) & 0xff); + header->contentLengthB0 = ((content_len) & 0xff); + + header->paddingLength = padding_len; + + header->reserved = 0; +} + +AP_DECLARE(void) ap_fcgi_fill_in_request_body(ap_fcgi_begin_request_body *brb, + int role, + unsigned char flags) +{ + brb->roleB1 = ((role >> 8) & 0xff); + brb->roleB0 = (role & 0xff); + brb->flags = flags; + brb->reserved[0] = 0; + brb->reserved[1] = 0; + brb->reserved[2] = 0; + brb->reserved[3] = 0; + brb->reserved[4] = 0; +} + +AP_DECLARE(apr_size_t) ap_fcgi_encoded_env_len(apr_table_t *env, + apr_size_t maxlen, + int *starting_elem) +{ + const apr_array_header_t *envarr; + const apr_table_entry_t *elts; + apr_size_t envlen, actualenvlen; + int i; + + if (maxlen > AP_FCGI_MAX_CONTENT_LEN) { + maxlen = AP_FCGI_MAX_CONTENT_LEN; + } + + envarr = apr_table_elts(env); + elts = (const apr_table_entry_t *) envarr->elts; + + /* envlen - speculative, may overflow the limit + * actualenvlen - len required without overflowing + */ + envlen = actualenvlen = 0; + for (i = *starting_elem; i < envarr->nelts; ) { + apr_size_t keylen, vallen; + + if (!elts[i].key) { + (*starting_elem)++; + i++; + continue; + } + + keylen = strlen(elts[i].key); + + if (keylen >> 7 == 0) { + envlen += 1; + } + else { + envlen += 4; + } + + envlen += keylen; + + vallen = strlen(elts[i].val); + + if (vallen >> 7 == 0) { + envlen += 1; + } + else { + envlen += 4; + } + + envlen += vallen; + + if (envlen > maxlen) { + break; + } + + actualenvlen = envlen; + (*starting_elem)++; + i++; + } + + return actualenvlen; +} + +AP_DECLARE(apr_status_t) ap_fcgi_encode_env(request_rec *r, + apr_table_t *env, + void *buffer, + apr_size_t buflen, + int *starting_elem) +{ + apr_status_t rv = APR_SUCCESS; + const apr_array_header_t *envarr; + const apr_table_entry_t *elts; + char *itr; + int i; + + envarr = apr_table_elts(env); + elts = (const apr_table_entry_t *) envarr->elts; + + itr = buffer; + + for (i = *starting_elem; i < envarr->nelts; ) { + apr_size_t keylen, vallen; + + if (!elts[i].key) { + (*starting_elem)++; + i++; + continue; + } + + keylen = strlen(elts[i].key); + + if (keylen >> 7 == 0) { + if (buflen < 1) { + rv = APR_ENOSPC; /* overflow */ + break; + } + itr[0] = keylen & 0xff; + itr += 1; + buflen -= 1; + } + else { + if (buflen < 4) { + rv = APR_ENOSPC; /* overflow */ + break; + } + itr[0] = ((keylen >> 24) & 0xff) | 0x80; + itr[1] = ((keylen >> 16) & 0xff); + itr[2] = ((keylen >> 8) & 0xff); + itr[3] = ((keylen) & 0xff); + itr += 4; + buflen -= 4; + } + + vallen = strlen(elts[i].val); + + if (vallen >> 7 == 0) { + if (buflen < 1) { + rv = APR_ENOSPC; /* overflow */ + break; + } + itr[0] = vallen & 0xff; + itr += 1; + buflen -= 1; + } + else { + if (buflen < 4) { + rv = APR_ENOSPC; /* overflow */ + break; + } + itr[0] = ((vallen >> 24) & 0xff) | 0x80; + itr[1] = ((vallen >> 16) & 0xff); + itr[2] = ((vallen >> 8) & 0xff); + itr[3] = ((vallen) & 0xff); + itr += 4; + buflen -= 4; + } + + if (buflen < keylen) { + rv = APR_ENOSPC; /* overflow */ + break; + } + memcpy(itr, elts[i].key, keylen); + itr += keylen; + buflen -= keylen; + + if (buflen < vallen) { + rv = APR_ENOSPC; /* overflow */ + break; + } + memcpy(itr, elts[i].val, vallen); + itr += vallen; + + if (buflen == vallen) { + (*starting_elem)++; + i++; + break; /* filled up predicted space, as expected */ + } + + buflen -= vallen; + + (*starting_elem)++; + i++; + } + + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + APLOGNO(02492) "ap_fcgi_encode_env: out of space " + "encoding environment"); + } + + return rv; +} diff --git a/server/util_script.c b/server/util_script.c index 12a056f5..3bc1b00a 100644 --- a/server/util_script.c +++ b/server/util_script.c @@ -73,9 +73,10 @@ static char *http2env(request_rec *r, const char *w) *cp++ = '_'; } else { - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "Not exporting header with invalid name as envvar: %s", - ap_escape_logitem(r->pool, w)); + if (APLOGrtrace1(r)) + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Not exporting header with invalid name as envvar: %s", + ap_escape_logitem(r->pool, w)); return NULL; } } @@ -594,9 +595,10 @@ AP_DECLARE(int) ap_scan_script_header_err_core_ex(request_rec *r, char *buffer, "Invalid status line from script '%s': %.30s", apr_filepath_name_get(r->filename), l); else - ap_log_rerror(SCRIPT_LOG_MARK, APLOG_TRACE1, 0, r, - "Status line from script '%s': %.30s", - apr_filepath_name_get(r->filename), l); + if (APLOGrtrace1(r)) + ap_log_rerror(SCRIPT_LOG_MARK, APLOG_TRACE1, 0, r, + "Status line from script '%s': %.30s", + apr_filepath_name_get(r->filename), l); r->status_line = apr_pstrdup(r->pool, l); } else if (!strcasecmp(w, "Location")) { diff --git a/server/vhost.c b/server/vhost.c index fd7c0ad6..111311b4 100644 --- a/server/vhost.c +++ b/server/vhost.c @@ -577,14 +577,22 @@ AP_DECLARE(void) ap_fini_vhost_config(apr_pool_t *p, server_rec *main_s) */ for (s = main_s->next; s; s = s->next) { + server_addr_rec *sar_prev = NULL; has_default_vhost_addr = 0; for (sar = s->addrs; sar; sar = sar->next) { ipaddr_chain *ic; char inaddr_any[16] = {0}; /* big enough to handle IPv4 or IPv6 */ - + /* XXX: this treats 0.0.0.0 as a "default" server which matches no-exact-match for IPv6 */ if (!memcmp(sar->host_addr->ipaddr_ptr, inaddr_any, sar->host_addr->ipaddr_len)) { ic = find_default_server(sar->host_port); - if (!ic || sar->host_port != ic->sar->host_port) { + + if (ic && sar->host_port == ic->sar->host_port) { /* we're a match for an existing "default server" */ + if (!sar_prev || memcmp(sar_prev->host_addr->ipaddr_ptr, inaddr_any, sar_prev->host_addr->ipaddr_len) + || sar_prev->host_port != sar->host_port) { + add_name_vhost_config(p, main_s, s, sar, ic); + } + } + else { /* No default server, or we found a default server but ** exactly one of us is a wildcard port, which means we want ** two ip-based vhosts not an NVH with two names @@ -592,6 +600,7 @@ AP_DECLARE(void) ap_fini_vhost_config(apr_pool_t *p, server_rec *main_s) ic = new_ipaddr_chain(p, s, sar); ic->next = default_list; default_list = ic; + add_name_vhost_config(p, main_s, s, sar, ic); } has_default_vhost_addr = 1; } @@ -609,8 +618,9 @@ AP_DECLARE(void) ap_fini_vhost_config(apr_pool_t *p, server_rec *main_s) ic->next = *iphash_table_tail[bucket]; *iphash_table_tail[bucket] = ic; } + add_name_vhost_config(p, main_s, s, sar, ic); } - add_name_vhost_config(p, main_s, s, sar, ic); + sar_prev = sar; } /* Ok now we want to set up a server_hostname if the user was |