summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorArno Töll <arno@debian.org>2013-12-23 23:50:09 -1100
committerArno Töll <arno@debian.org>2013-12-23 23:50:09 -1100
commit86d5cc79d9d6750da8771fdb0c9ab22c19b8ad45 (patch)
tree5037da70bf37c0ee93f0ea09f054bdfb278befe0 /server
parent4a336a5b117419c33c29eadd6409c69df78cd586 (diff)
downloadapache2-86d5cc79d9d6750da8771fdb0c9ab22c19b8ad45.tar.gz
Imported Upstream version 2.4.7upstream/2.4.7
Diffstat (limited to 'server')
-rw-r--r--server/Makefile.in3
-rw-r--r--server/config.c32
-rw-r--r--server/core.c1
-rw-r--r--server/core_filters.c10
-rw-r--r--server/log.c13
-rw-r--r--server/mpm/config.m411
-rw-r--r--server/mpm/event/config.m42
-rw-r--r--server/mpm/event/config3.m42
-rw-r--r--server/mpm/event/event.c177
-rw-r--r--server/mpm/event/pod.c113
-rw-r--r--server/mpm/event/pod.h59
-rw-r--r--server/mpm/winnt/child.c105
-rw-r--r--server/mpm/winnt/mpm_winnt.c2
-rw-r--r--server/mpm/winnt/mpm_winnt.h2
-rw-r--r--server/mpm/worker/config3.m42
-rw-r--r--server/mpm/worker/pod.c113
-rw-r--r--server/mpm/worker/pod.h58
-rw-r--r--server/mpm/worker/worker.c45
-rw-r--r--server/mpm_common.c2
-rw-r--r--server/mpm_unix.c101
-rw-r--r--server/scoreboard.c2
-rw-r--r--server/util_fcgi.c287
-rw-r--r--server/util_script.c14
-rw-r--r--server/vhost.c16
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