X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=modules%2Fproxy%2Fmod_proxy_balancer.c;h=ffc2ef60a73eab6ff5b167586dfe5a11fb5a6e04;hb=7cc83fe9abdabc41b3d389280f2455fc9ce7ae25;hp=e7566051c79502854b587843cd58cf0d3db4308a;hpb=31c4a9e21ebf55a7252a6e9363e671264e281425;p=apache diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index e7566051c7..ffc2ef60a7 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -20,7 +20,7 @@ #include "scoreboard.h" #include "ap_mpm.h" #include "apr_version.h" -#include "apr_hooks.h" +#include "ap_hooks.h" #include "apr_date.h" static const char *balancer_mutex_type = "proxy-balancer-shm"; @@ -28,6 +28,11 @@ ap_slotmem_provider_t *storage = NULL; module AP_MODULE_DECLARE_DATA proxy_balancer_module; +static APR_OPTIONAL_FN_TYPE(set_worker_hc_param) *set_worker_hc_param_f = NULL; + +static int (*ap_proxy_retry_worker_fn)(const char *proxy_function, + proxy_worker *worker, server_rec *s) = NULL; + /* * Register our mutex type before the config is read so we * can adjust the mutex settings using the Mutex directive. @@ -43,7 +48,7 @@ static int balancer_pre_config(apr_pool_t *pconf, apr_pool_t *plog, if (rv != APR_SUCCESS) { return rv; } - + set_worker_hc_param_f = APR_RETRIEVE_OPTIONAL_FN(set_worker_hc_param); return OK; } @@ -60,22 +65,21 @@ static int proxy_balancer_canon(request_rec *r, char *url) apr_port_t port = 0; /* TODO: offset of BALANCER_PREFIX ?? */ - if (strncasecmp(url, "balancer:", 9) == 0) { + if (ap_casecmpstrn(url, "balancer:", 9) == 0) { url += 9; } else { return DECLINED; } - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, r->server, - "proxy: BALANCER: canonicalising URL %s", url); + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "canonicalising URL %s", url); /* do syntatic check. * We break the URL into host, port, path, search */ err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); if (err) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01157) "error parsing URL %s: %s", url, err); return HTTP_BAD_REQUEST; @@ -96,7 +100,7 @@ static int proxy_balancer_canon(request_rec *r, char *url) if (path == NULL) return HTTP_BAD_REQUEST; - r->filename = apr_pstrcat(r->pool, "proxy:", BALANCER_PREFIX, host, + r->filename = apr_pstrcat(r->pool, "proxy:" BALANCER_PREFIX, host, "/", path, (search) ? "?" : "", (search) ? search : "", NULL); r->path_info = apr_pstrcat(r->pool, "/", path, NULL); @@ -104,7 +108,7 @@ static int proxy_balancer_canon(request_rec *r, char *url) return OK; } -static void init_balancer_members(proxy_server_conf *conf, server_rec *s, +static void init_balancer_members(apr_pool_t *p, server_rec *s, proxy_balancer *balancer) { int i; @@ -115,11 +119,12 @@ static void init_balancer_members(proxy_server_conf *conf, server_rec *s, for (i = 0; i < balancer->workers->nelts; i++) { int worker_is_initialized; proxy_worker *worker = *workers; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "Looking at %s -> %s initialized?", balancer->name, worker->s->name); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01158) + "Looking at %s -> %s initialized?", balancer->s->name, + ap_proxy_worker_name(p, worker)); worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(worker); if (!worker_is_initialized) { - ap_proxy_initialize_worker(worker, s, conf->pool); + ap_proxy_initialize_worker(worker, s, p); } ++workers; } @@ -127,9 +132,9 @@ static void init_balancer_members(proxy_server_conf *conf, server_rec *s, /* Set default number of attempts to the number of * workers. */ - if (!balancer->max_attempts_set && balancer->workers->nelts > 1) { - balancer->max_attempts = balancer->workers->nelts - 1; - balancer->max_attempts_set = 1; + if (!balancer->s->max_attempts_set && balancer->workers->nelts > 1) { + balancer->s->max_attempts = balancer->workers->nelts - 1; + balancer->s->max_attempts_set = 1; } } @@ -149,7 +154,7 @@ static char *get_path_param(apr_pool_t *pool, char *url, path += strlen(name); if (*path == '=') { /* - * Session path was found, get it's value + * Session path was found, get its value */ ++path; if (*path) { @@ -180,7 +185,7 @@ static char *get_cookie_param(request_rec *r, const char *name) ++start_cookie; if (*start_cookie++ == '=' && *start_cookie) { /* - * Session cookie was found, get it's value + * Session cookie was found, get its value */ char *end_cookie, *cookie; cookie = apr_pstrdup(r->pool, start_cookie); @@ -215,7 +220,7 @@ static proxy_worker *find_route_worker(proxy_balancer *balancer, if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) continue; if (*(worker->s->route) && strcmp(worker->s->route, route) == 0) { - if (worker && PROXY_WORKER_IS_USABLE(worker)) { + if (PROXY_WORKER_IS_USABLE(worker)) { return worker; } else { /* @@ -225,7 +230,7 @@ static proxy_worker *find_route_worker(proxy_balancer *balancer, * The worker might still be unusable, but we try * anyway. */ - ap_proxy_retry_worker("BALANCER", worker, r->server); + ap_proxy_retry_worker_fn("BALANCER", worker, r->server); if (PROXY_WORKER_IS_USABLE(worker)) { return worker; } else { @@ -249,7 +254,7 @@ static proxy_worker *find_route_worker(proxy_balancer *balancer, * The worker might still be unusable, but we try * anyway. */ - ap_proxy_retry_worker("BALANCER", rworker, r->server); + ap_proxy_retry_worker_fn("BALANCER", rworker, r->server); } if (rworker && PROXY_WORKER_IS_USABLE(rworker)) return rworker; @@ -271,34 +276,34 @@ static proxy_worker *find_session_route(proxy_balancer *balancer, { proxy_worker *worker = NULL; - if (!balancer->sticky) + if (!*balancer->s->sticky) return NULL; /* Try to find the sticky route inside url */ - *route = get_path_param(r->pool, *url, balancer->sticky_path, balancer->scolonsep); + *route = get_path_param(r->pool, *url, balancer->s->sticky_path, balancer->s->scolonsep); if (*route) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER: Found value %s for " - "stickysession %s", *route, balancer->sticky_path); - *sticky_used = balancer->sticky_path; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01159) + "Found value %s for stickysession %s", + *route, balancer->s->sticky_path); + *sticky_used = balancer->s->sticky_path; } else { - *route = get_cookie_param(r, balancer->sticky); + *route = get_cookie_param(r, balancer->s->sticky); if (*route) { - *sticky_used = balancer->sticky; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER: Found value %s for " - "stickysession %s", *route, balancer->sticky); + *sticky_used = balancer->s->sticky; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01160) + "Found value %s for stickysession %s", + *route, balancer->s->sticky); } } /* - * If we found a value for sticksession, find the first '.' within. - * Everything after '.' (if present) is our route. + * If we found a value for stickysession, find the first '.' (or whatever + * sticky_separator is set to) within. Everything after '.' (if present) + * is our route. */ - if ((*route) && ((*route = strchr(*route, '.')) != NULL )) + if ((*route) && (balancer->s->sticky_separator != 0) && ((*route = strchr(*route, balancer->s->sticky_separator)) != NULL )) (*route)++; if ((*route) && (**route)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER: Found route %s", *route); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01161) "Found route %s", *route); /* We have a route in path or in cookie * Find the worker that has this route defined. */ @@ -309,9 +314,9 @@ static proxy_worker *find_session_route(proxy_balancer *balancer, * the route supplied by the client. */ apr_table_setn(r->subprocess_env, "BALANCER_ROUTE_CHANGED", "1"); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER: Route changed from %s to %s", - *route, worker->s->route); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01162) + "Route changed from %s to %s", + *route, worker->s->route); } return worker; } @@ -325,9 +330,10 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, proxy_worker *candidate = NULL; apr_status_t rv; - if ((rv = PROXY_GLOBAL_LOCK(balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Lock failed for find_best_worker()", balancer->name); + if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01163) + "%s: Lock failed for find_best_worker()", + balancer->s->name); return NULL; } @@ -336,14 +342,10 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, if (candidate) candidate->s->elected++; -/* - PROXY_GLOBAL_UNLOCK(conf); - return NULL; -*/ - - if ((rv = PROXY_GLOBAL_UNLOCK(balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Unlock failed for find_best_worker()", balancer->name); + if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01164) + "%s: Unlock failed for find_best_worker()", + balancer->s->name); } if (candidate == NULL) { @@ -354,18 +356,18 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, * By default the timeout is not set, and the server * returns SERVER_BUSY. */ - if (balancer->timeout) { + if (balancer->s->timeout) { /* XXX: This can perhaps be build using some * smarter mechanism, like tread_cond. * But since the statuses can came from * different childs, use the provided algo. */ - apr_interval_time_t timeout = balancer->timeout; + apr_interval_time_t timeout = balancer->s->timeout; apr_interval_time_t step, tval = 0; /* Set the timeout to 0 so that we don't * end in infinite loop */ - balancer->timeout = 0; + balancer->s->timeout = 0; step = timeout / 100; while (tval < timeout) { apr_sleep(step); @@ -375,7 +377,7 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, tval += step; } /* restore the timeout */ - balancer->timeout = timeout; + balancer->s->timeout = timeout; } } @@ -418,27 +420,38 @@ static void force_recovery(proxy_balancer *balancer, server_rec *s) } else { /* Try if we can recover */ - ap_proxy_retry_worker("BALANCER", *worker, s); + ap_proxy_retry_worker_fn("BALANCER", *worker, s); if (!((*worker)->s->status & PROXY_WORKER_IN_ERROR)) { ok = 1; break; } } } - if (!ok) { + if (!ok && balancer->s->forcerecovery) { /* If all workers are in error state force the recovery. */ worker = (proxy_worker **)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++, worker++) { ++(*worker)->s->retries; (*worker)->s->status &= ~PROXY_WORKER_IN_ERROR; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "proxy: BALANCER: (%s). Forcing recovery for worker (%s)", - balancer->name, (*worker)->s->hostname); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01165) + "%s: Forcing recovery for worker (%s)", + balancer->s->name, (*worker)->s->hostname); } } } +static apr_status_t decrement_busy_count(void *worker_) +{ + proxy_worker *worker = worker_; + + if (worker->s->busy) { + worker->s->busy--; + } + + return APR_SUCCESS; +} + static int proxy_balancer_pre_request(proxy_worker **worker, proxy_balancer **balancer, request_rec *r, @@ -457,16 +470,15 @@ static int proxy_balancer_pre_request(proxy_worker **worker, * for balancer, because this is failover attempt. */ if (!*balancer && - !(*balancer = ap_proxy_get_balancer(r->pool, conf, *url))) + !(*balancer = ap_proxy_get_balancer(r->pool, conf, *url, 1))) return DECLINED; /* Step 2: Lock the LoadBalancer * XXX: perhaps we need the process lock here */ - if ((rv = PROXY_GLOBAL_LOCK(*balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Lock failed for pre_request", - (*balancer)->name); + if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01166) + "%s: Lock failed for pre_request", (*balancer)->s->name); return DECLINED; } @@ -475,7 +487,7 @@ static int proxy_balancer_pre_request(proxy_worker **worker, /* Step 3.5: Update member list for the balancer */ /* TODO: Implement as provider! */ - /* proxy_update_members(balancer, r, conf); */ + ap_proxy_sync_balancer(*balancer, r->server, conf); /* Step 4: find the session route */ runtime = find_session_route(*balancer, r, &route, &sticky, url); @@ -509,7 +521,7 @@ static int proxy_balancer_pre_request(proxy_worker **worker, *worker = runtime; } - else if (route && (*balancer)->sticky_force) { + else if (route && (*balancer)->s->sticky_force) { int i, member_of = 0; proxy_worker **workers; /* @@ -526,39 +538,39 @@ static int proxy_balancer_pre_request(proxy_worker **worker, workers++; } if (member_of) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "proxy: BALANCER: (%s). All workers are in error state for route (%s)", - (*balancer)->name, route); - if ((rv = PROXY_GLOBAL_UNLOCK(*balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Unlock failed for pre_request", - (*balancer)->name); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01167) + "%s: All workers are in error state for route (%s)", + (*balancer)->s->name, route); + if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01168) + "%s: Unlock failed for pre_request", + (*balancer)->s->name); } return HTTP_SERVICE_UNAVAILABLE; } } - if ((rv = PROXY_GLOBAL_UNLOCK(*balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Unlock failed for pre_request", - (*balancer)->name); + if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01169) + "%s: Unlock failed for pre_request", + (*balancer)->s->name); } if (!*worker) { runtime = find_best_worker(*balancer, r); if (!runtime) { if ((*balancer)->workers->nelts) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "proxy: BALANCER: (%s). All workers are in error state", - (*balancer)->name); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01170) + "%s: All workers are in error state", + (*balancer)->s->name); } else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "proxy: BALANCER: (%s). No workers in balancer", - (*balancer)->name); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01171) + "%s: No workers in balancer", + (*balancer)->s->name); } return HTTP_SERVICE_UNAVAILABLE; } - if ((*balancer)->sticky && runtime) { + if (*(*balancer)->s->sticky && runtime) { /* * This balancer has sticky sessions and the client either has not * supplied any routing information or all workers for this route @@ -573,10 +585,12 @@ static int proxy_balancer_pre_request(proxy_worker **worker, } (*worker)->s->busy++; + apr_pool_cleanup_register(r->pool, *worker, decrement_busy_count, + apr_pool_cleanup_null); /* Add balancer/worker info to env. */ apr_table_setn(r->subprocess_env, - "BALANCER_NAME", (*balancer)->name); + "BALANCER_NAME", (*balancer)->s->name); apr_table_setn(r->subprocess_env, "BALANCER_WORKER_NAME", (*worker)->s->name); apr_table_setn(r->subprocess_env, @@ -599,9 +613,9 @@ static int proxy_balancer_pre_request(proxy_worker **worker, apr_table_setn(r->subprocess_env, "BALANCER_SESSION_ROUTE", route); } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER (%s) worker (%s) rewritten to %s", - (*balancer)->name, (*worker)->s->name, *url); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01172) + "%s: worker (%s) rewritten to %s", + (*balancer)->s->name, (*worker)->s->name, *url); return access_status; } @@ -614,21 +628,25 @@ static int proxy_balancer_post_request(proxy_worker *worker, apr_status_t rv; - if ((rv = PROXY_GLOBAL_LOCK(balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Lock failed for post_request", - balancer->name); + if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01173) + "%s: Lock failed for post_request", + balancer->s->name); return HTTP_INTERNAL_SERVER_ERROR; } - if (!apr_is_empty_array(balancer->errstatuses)) { + if (!apr_is_empty_array(balancer->errstatuses) + && !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) { int i; for (i = 0; i < balancer->errstatuses->nelts; i++) { int val = ((int *)balancer->errstatuses->elts)[i]; if (r->status == val) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Forcing recovery for worker (%s), failonstatus %d", - balancer->name, worker->s->name, val); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01174) + "%s: Forcing worker (%s) into error state " + "due to status code %d matching 'failonstatus' " + "balancer parameter", + balancer->s->name, ap_proxy_worker_name(r->pool, worker), + val); worker->s->status |= PROXY_WORKER_IN_ERROR; worker->s->error_time = apr_time_now(); break; @@ -636,19 +654,26 @@ static int proxy_balancer_post_request(proxy_worker *worker, } } - if ((rv = PROXY_GLOBAL_UNLOCK(balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Unlock failed for post_request", - balancer->name); + if (balancer->failontimeout + && !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS) + && (apr_table_get(r->notes, "proxy_timedout")) != NULL) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02460) + "%s: Forcing worker (%s) into error state " + "due to timeout and 'failontimeout' parameter being set", + balancer->s->name, ap_proxy_worker_name(r->pool, worker)); + worker->s->status |= PROXY_WORKER_IN_ERROR; + worker->s->error_time = apr_time_now(); + } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy_balancer_post_request for (%s)", balancer->name); - if (worker && worker->s->busy) - worker->s->busy--; + if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01175) + "%s: Unlock failed for post_request", balancer->s->name); + } + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01176) + "proxy_balancer_post_request for (%s)", balancer->s->name); return OK; - } static void recalc_factors(proxy_balancer *balancer) @@ -659,7 +684,7 @@ static void recalc_factors(proxy_balancer *balancer) /* Recalculate lbfactors */ workers = (proxy_worker **)balancer->workers->elts; - /* Special case if there is only one worker it's + /* Special case if there is only one worker its * load factor will always be 1 */ if (balancer->workers->nelts == 1) { @@ -682,9 +707,9 @@ static apr_status_t lock_remove(void *data) balancer = (proxy_balancer *)conf->balancers->elts; for (i = 0; i < conf->balancers->nelts; i++, balancer++) { - if (balancer->mutex) { - apr_global_mutex_destroy(balancer->mutex); - balancer->mutex = NULL; + if (balancer->gmutex) { + apr_global_mutex_destroy(balancer->gmutex); + balancer->gmutex = NULL; } } return(0); @@ -694,95 +719,201 @@ static apr_status_t lock_remove(void *data) static int balancer_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { - void *data; - void *sconf = s->module_config; - proxy_server_conf *conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); - const char *userdata_key = "mod_proxy_balancer_init"; + apr_status_t rv; + proxy_server_conf *conf; + ap_slotmem_instance_t *new = NULL; + apr_time_t tstamp; - /* balancer_post_config() will be called twice during startup. So, only + /* balancer_post_config() will be called twice during startup. So, don't * set up the static data the 1st time through. */ - apr_pool_userdata_get(&data, userdata_key, s->process->pool); - if (!data) { - apr_pool_userdata_set((const void *)1, userdata_key, - apr_pool_cleanup_null, s->process->pool); + if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) { return OK; } + if (!ap_proxy_retry_worker_fn) { + ap_proxy_retry_worker_fn = + APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker); + if (!ap_proxy_retry_worker_fn) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02230) + "mod_proxy must be loaded for mod_proxy_balancer"); + return !OK; + } + } + /* - * Get worker slotmem setup + * Get slotmem setups */ - storage = ap_lookup_provider(AP_SLOTMEM_PROVIDER_GROUP, "shared", "0"); + storage = ap_lookup_provider(AP_SLOTMEM_PROVIDER_GROUP, "shm", + AP_SLOTMEM_PROVIDER_VERSION); if (!storage) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, 0, s, - "ap_lookup_provider %s failed", AP_SLOTMEM_PROVIDER_GROUP); + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01177) + "Failed to lookup provider 'shm' for '%s': is " + "mod_slotmem_shm loaded??", + AP_SLOTMEM_PROVIDER_GROUP); return !OK; } + + tstamp = apr_time_now(); /* * Go thru each Vhost and create the shared mem slotmem for * each balancer's workers */ while (s) { int i,j; - apr_status_t rv; + char *id; proxy_balancer *balancer; - sconf = s->module_config; + ap_slotmem_type_t type; + void *sconf = s->module_config; conf = (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module); + /* + * During create_proxy_config() we created a dummy id. Now that + * we have identifying info, we can create the real id + */ + id = apr_psprintf(pconf, "%s.%s.%d.%s.%s.%u.%s", + (s->server_scheme ? s->server_scheme : "????"), + (s->server_hostname ? s->server_hostname : "???"), + (int)s->port, + (s->server_admin ? s->server_admin : "??"), + (s->defn_name ? s->defn_name : "?"), + s->defn_line_number, + (s->error_fname ? s->error_fname : DEFAULT_ERRORLOG)); + conf->id = apr_psprintf(pconf, "p%x", + ap_proxy_hashfunc(id, PROXY_HASHFUNC_DEFAULT)); + if (conf->bslot) { + /* Shared memory already created for this proxy_server_conf. + */ + s = s->next; + continue; + } + if (conf->bal_persist) { + type = AP_SLOTMEM_TYPE_PERSIST; + } else { + type = 0; + } + if (conf->balancers->nelts) { + conf->max_balancers = conf->balancers->nelts + conf->bgrowth; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01178) "Doing balancers create: %d, %d (%d)", + (int)ALIGNED_PROXY_BALANCER_SHARED_SIZE, + (int)conf->balancers->nelts, conf->max_balancers); + + rv = storage->create(&new, conf->id, + ALIGNED_PROXY_BALANCER_SHARED_SIZE, + conf->max_balancers, type, pconf); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01179) "balancer slotmem_create failed"); + return !OK; + } + conf->bslot = new; + } + conf->storage = storage; /* Initialize shared scoreboard data */ balancer = (proxy_balancer *)conf->balancers->elts; for (i = 0; i < conf->balancers->nelts; i++, balancer++) { proxy_worker **workers; proxy_worker *worker; - ap_slotmem_instance_t *new = NULL; + proxy_balancer_shared *bshm; + const char *sname; + unsigned int index; + + /* now that we have the right id, we need to redo the sname field */ + ap_pstr2_alnum(pconf, balancer->s->name + sizeof(BALANCER_PREFIX) - 1, + &sname); + sname = apr_pstrcat(pconf, conf->id, "_", sname, NULL); + PROXY_STRNCPY(balancer->s->sname, sname); /* We know this will succeed */ balancer->max_workers = balancer->workers->nelts + balancer->growth; - balancer->sname = ap_md5(pconf, (const unsigned char *)balancer->name); /* Create global mutex */ - rv = ap_global_mutex_create(&(balancer->mutex), NULL, balancer_mutex_type, - balancer->sname, s, pconf, 0); - if (rv != APR_SUCCESS || !balancer->mutex) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, + rv = ap_global_mutex_create(&(balancer->gmutex), NULL, balancer_mutex_type, + balancer->s->sname, s, pconf, 0); + if (rv != APR_SUCCESS || !balancer->gmutex) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01180) "mutex creation of %s : %s failed", balancer_mutex_type, - balancer->sname); + balancer->s->sname); return HTTP_INTERNAL_SERVER_ERROR; } apr_pool_cleanup_register(pconf, (void *)s, lock_remove, apr_pool_cleanup_null); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Doing create: %s (%s), %d, %d", - balancer->name, balancer->sname, - (int)sizeof(proxy_worker_shared), - (int)balancer->max_workers); + /* setup shm for balancers */ + bshm = ap_proxy_find_balancershm(storage, conf->bslot, balancer, &index); + if (bshm) { + if ((rv = storage->fgrab(conf->bslot, index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02408) "balancer slotmem_fgrab failed"); + return !OK; + } + } + else { + if ((rv = storage->grab(conf->bslot, &index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01181) "balancer slotmem_grab failed"); + return !OK; + } + if ((rv = storage->dptr(conf->bslot, index, (void *)&bshm)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01182) "balancer slotmem_dptr failed"); + return !OK; + } + } + if ((rv = ap_proxy_share_balancer(balancer, bshm, index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01183) "Cannot share balancer"); + return !OK; + } + + /* create slotmem slots for workers */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01184) "Doing workers create: %s (%s), %d, %d [%u]", + balancer->s->name, balancer->s->sname, + (int)ALIGNED_PROXY_WORKER_SHARED_SIZE, + (int)balancer->max_workers, i); - rv = storage->create(&new, balancer->sname, sizeof(proxy_worker_shared), - balancer->max_workers, AP_SLOTMEM_TYPE_PREGRAB, pconf); + rv = storage->create(&new, balancer->s->sname, + ALIGNED_PROXY_WORKER_SHARED_SIZE, + balancer->max_workers, type, pconf); if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, "slotmem_create failed"); + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01185) "worker slotmem_create failed"); return !OK; } - balancer->slot = new; + balancer->wslot = new; + balancer->storage = storage; + /* sync all timestamps */ + balancer->wupdated = balancer->s->wupdated = tstamp; + + /* now go thru each worker */ workers = (proxy_worker **)balancer->workers->elts; for (j = 0; j < balancer->workers->nelts; j++, workers++) { proxy_worker_shared *shm; - unsigned int index; worker = *workers; - if ((rv = storage->grab(balancer->slot, &index)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, "slotmem_grab failed"); - return !OK; + shm = ap_proxy_find_workershm(storage, balancer->wslot, worker, &index); + if (shm) { + if ((rv = storage->fgrab(balancer->wslot, index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02409) "worker slotmem_fgrab failed"); + return !OK; + } } - if ((rv = storage->dptr(balancer->slot, index, (void *)&shm)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, "slotmem_dptr failed"); - return !OK; + else { + if ((rv = storage->grab(balancer->wslot, &index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01186) "worker slotmem_grab failed"); + return !OK; + + } + if ((rv = storage->dptr(balancer->wslot, index, (void *)&shm)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01187) "worker slotmem_dptr failed"); + return !OK; + } } if ((rv = ap_proxy_share_worker(worker, shm, index)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, "Cannot share worker"); + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01188) "Cannot share worker"); return !OK; } + worker->s->updated = tstamp; + } + if (conf->bal_persist) { + /* We could have just read-in a persisted config. Force a sync. */ + balancer->wupdated--; + ap_proxy_sync_balancer(balancer, s, conf); } } s = s->next; @@ -791,7 +922,64 @@ static int balancer_post_config(apr_pool_t *pconf, apr_pool_t *plog, return OK; } +static void create_radio(const char *name, unsigned int flag, request_rec *r) +{ + ap_rvputs(r, "
\n", r); +} + +static void push2table(const char *input, apr_table_t *params, + const char *allowed[], apr_pool_t *p) +{ + char *args; + char *tok, *val; + char *key; + + if (input == NULL) { + return; + } + args = apr_pstrdup(p, input); + + key = apr_strtok(args, "&", &tok); + while (key) { + val = strchr(key, '='); + if (val) { + *val++ = '\0'; + } + else { + val = ""; + } + ap_unescape_url(key); + ap_unescape_url(val); + if (allowed == NULL) { /* allow all */ + apr_table_set(params, key, val); + } + else { + const char **ok = allowed; + while (*ok) { + if (strcmp(*ok, key) == 0) { + apr_table_set(params, key, val); + break; + } + ok++; + } + } + key = apr_strtok(NULL, "&", &tok); + } +} + /* Manages the loadfactors and member status + * The balancer, worker and nonce are obtained from + * the request args (?b=...&w=...&nonce=....). + * All other params are pulled from any POST + * data that exists. + * TODO: + * /...//balancer/worker/nonce */ static int balancer_handler(request_rec *r) { @@ -801,17 +989,21 @@ static int balancer_handler(request_rec *r) proxy_worker *worker, *wsel = NULL; proxy_worker **workers = NULL; apr_table_t *params; - int access_status; int i, n; + int ok2change = 1; const char *name; + const char *action; + apr_status_t rv; /* is this for us? */ if (strcmp(r->handler, "balancer-manager")) { return DECLINED; } - r->allowed = (AP_METHOD_BIT << M_GET); - if (r->method_number != M_GET) { + r->allowed = 0 + | (AP_METHOD_BIT << M_GET) + | (AP_METHOD_BIT << M_POST); + if ((r->method_number != M_GET) && (r->method_number != M_POST)) { return DECLINED; } @@ -819,53 +1011,73 @@ static int balancer_handler(request_rec *r) conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); params = apr_table_make(r->pool, 10); - if (r->args) { - char *args = apr_pstrdup(r->pool, r->args); - char *tok, *val; - while (args && *args) { - if ((val = ap_strchr(args, '='))) { - *val++ = '\0'; - if ((tok = ap_strchr(val, '&'))) - *tok++ = '\0'; - /* - * Special case: workers are allowed path information - */ - if ((access_status = ap_unescape_url(val)) != OK) - if (strcmp(args, "w") || (access_status != HTTP_NOT_FOUND)) - return access_status; - apr_table_setn(params, args, val); - args = tok; - } - else - return HTTP_BAD_REQUEST; + balancer = (proxy_balancer *)conf->balancers->elts; + for (i = 0; i < conf->balancers->nelts; i++, balancer++) { + if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01189) + "%s: Lock failed for balancer_handler", + balancer->s->name); + } + ap_proxy_sync_balancer(balancer, r->server, conf); + if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01190) + "%s: Unlock failed for balancer_handler", + balancer->s->name); } } + if (r->args && (r->method_number == M_GET)) { + const char *allowed[] = { "w", "b", "nonce", "xml", NULL }; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01191) "parsing r->args"); + + push2table(r->args, params, allowed, r->pool); + } + if (r->method_number == M_POST) { + apr_bucket_brigade *ib; + apr_size_t len = 1024; + char *buf = apr_pcalloc(r->pool, len+1); + + ib = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc); + rv = ap_get_brigade(r->input_filters, ib, AP_MODE_READBYTES, + APR_BLOCK_READ, len); + if (rv != APR_SUCCESS) { + return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); + } + apr_brigade_flatten(ib, buf, &len); + buf[len] = '\0'; + push2table(buf, params, NULL, r->pool); + } if ((name = apr_table_get(params, "b"))) bsel = ap_proxy_get_balancer(r->pool, conf, - apr_pstrcat(r->pool, BALANCER_PREFIX, name, NULL)); + apr_pstrcat(r->pool, BALANCER_PREFIX, name, NULL), 0); if ((name = apr_table_get(params, "w"))) { wsel = ap_proxy_get_worker(r->pool, bsel, conf, name); } -#if 0 + /* Check that the supplied nonce matches this server's nonce; * otherwise ignore all parameters, to prevent a CSRF attack. */ - if (*balancer_nonce && - ((name = apr_table_get(params, "nonce")) == NULL - || strcmp(balancer_nonce, name) != 0)) { + if (!bsel || + (*bsel->s->nonce && + ( + (name = apr_table_get(params, "nonce")) == NULL || + strcmp(bsel->s->nonce, name) != 0 + ) + ) + ) { apr_table_clear(params); + ok2change = 0; } -#endif + /* First set the params */ - /* - * Note that it is not possible set the proxy_balancer because it is not - * in shared memory. - */ - if (wsel) { + if (wsel && ok2change) { const char *val; - if ((val = apr_table_get(params, "lf"))) { + int was_usable = PROXY_WORKER_IS_USABLE(wsel); + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01192) "settings worker params"); + + if ((val = apr_table_get(params, "w_lf"))) { int ival = atoi(val); if (ival >= 1 && ival <= 100) { wsel->s->lbfactor = ival; @@ -873,52 +1085,343 @@ static int balancer_handler(request_rec *r) recalc_factors(bsel); } } - if ((val = apr_table_get(params, "wr"))) { + if ((val = apr_table_get(params, "w_wr"))) { if (strlen(val) && strlen(val) < sizeof(wsel->s->route)) strcpy(wsel->s->route, val); else *wsel->s->route = '\0'; } - if ((val = apr_table_get(params, "rr"))) { + if ((val = apr_table_get(params, "w_rr"))) { if (strlen(val) && strlen(val) < sizeof(wsel->s->redirect)) strcpy(wsel->s->redirect, val); else *wsel->s->redirect = '\0'; } - if ((val = apr_table_get(params, "dw"))) { - if (!strcasecmp(val, "Disable")) - wsel->s->status |= PROXY_WORKER_DISABLED; - else if (!strcasecmp(val, "Enable")) - wsel->s->status &= ~PROXY_WORKER_DISABLED; + if ((val = apr_table_get(params, "w_status_I"))) { + ap_proxy_set_wstatus(PROXY_WORKER_IGNORE_ERRORS_FLAG, atoi(val), wsel); + } + if ((val = apr_table_get(params, "w_status_N"))) { + ap_proxy_set_wstatus(PROXY_WORKER_DRAIN_FLAG, atoi(val), wsel); + } + if ((val = apr_table_get(params, "w_status_D"))) { + ap_proxy_set_wstatus(PROXY_WORKER_DISABLED_FLAG, atoi(val), wsel); } - if ((val = apr_table_get(params, "ls"))) { + if ((val = apr_table_get(params, "w_status_H"))) { + ap_proxy_set_wstatus(PROXY_WORKER_HOT_STANDBY_FLAG, atoi(val), wsel); + } + if ((val = apr_table_get(params, "w_ls"))) { int ival = atoi(val); if (ival >= 0 && ival <= 99) { wsel->s->lbset = ival; } } + /* if enabling, we need to reset all lb params */ + if (bsel && !was_usable && PROXY_WORKER_IS_USABLE(wsel)) { + bsel->s->need_reset = 1; + } } + + if (bsel && ok2change) { + const char *val; + int ival; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01193) + "settings balancer params"); + if ((val = apr_table_get(params, "b_lbm"))) { + if ((strlen(val) < (sizeof(bsel->s->lbpname)-1)) && + strcmp(val, bsel->s->lbpname)) { + proxy_balancer_method *lbmethod; + lbmethod = ap_lookup_provider(PROXY_LBMETHOD, val, "0"); + if (lbmethod) { + PROXY_STRNCPY(bsel->s->lbpname, val); + bsel->lbmethod = lbmethod; + bsel->s->wupdated = apr_time_now(); + bsel->s->need_reset = 1; + } + } + } + if ((val = apr_table_get(params, "b_tmo"))) { + ival = atoi(val); + if (ival >= 0 && ival <= 7200) { /* 2 hrs enuff? */ + bsel->s->timeout = apr_time_from_sec(ival); + } + } + if ((val = apr_table_get(params, "b_max"))) { + ival = atoi(val); + if (ival >= 0 && ival <= 99) { + bsel->s->max_attempts = ival; + } + } + if ((val = apr_table_get(params, "b_sforce"))) { + ival = atoi(val); + bsel->s->sticky_force = (ival != 0); + } + if ((val = apr_table_get(params, "b_ss")) && *val) { + if (strlen(val) < (sizeof(bsel->s->sticky_path)-1)) { + if (*val == '-' && *(val+1) == '\0') + *bsel->s->sticky_path = *bsel->s->sticky = '\0'; + else { + char *path; + PROXY_STRNCPY(bsel->s->sticky_path, val); + PROXY_STRNCPY(bsel->s->sticky, val); + + if ((path = strchr((char *)bsel->s->sticky, '|'))) { + *path++ = '\0'; + PROXY_STRNCPY(bsel->s->sticky_path, path); + } + } + } + } + if ((val = apr_table_get(params, "b_wyes")) && + (*val == '1' && *(val+1) == '\0') && + (val = apr_table_get(params, "b_nwrkr"))) { + char *ret; + proxy_worker *nworker; + nworker = ap_proxy_get_worker(r->pool, bsel, conf, val); + if (!nworker && storage->num_free_slots(bsel->wslot)) { + if ((rv = PROXY_GLOBAL_LOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01194) + "%s: Lock failed for adding worker", + bsel->s->name); + } + ret = ap_proxy_define_worker(conf->pool, &nworker, bsel, conf, val, 0); + if (!ret) { + unsigned int index; + proxy_worker_shared *shm; + PROXY_COPY_CONF_PARAMS(nworker, conf); + if ((rv = storage->grab(bsel->wslot, &index)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01195) + "worker slotmem_grab failed"); + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01196) + "%s: Unlock failed for adding worker", + bsel->s->name); + } + return HTTP_BAD_REQUEST; + } + if ((rv = storage->dptr(bsel->wslot, index, (void *)&shm)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01197) + "worker slotmem_dptr failed"); + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01198) + "%s: Unlock failed for adding worker", + bsel->s->name); + } + return HTTP_BAD_REQUEST; + } + if ((rv = ap_proxy_share_worker(nworker, shm, index)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01199) + "Cannot share worker"); + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01200) + "%s: Unlock failed for adding worker", + bsel->s->name); + } + return HTTP_BAD_REQUEST; + } + if ((rv = ap_proxy_initialize_worker(nworker, r->server, conf->pool)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01201) + "Cannot init worker"); + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01202) + "%s: Unlock failed for adding worker", + bsel->s->name); + } + return HTTP_BAD_REQUEST; + } + /* sync all timestamps */ + bsel->wupdated = bsel->s->wupdated = nworker->s->updated = apr_time_now(); + /* by default, all new workers are disabled */ + ap_proxy_set_wstatus(PROXY_WORKER_DISABLED_FLAG, 1, nworker); + } + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01203) + "%s: Unlock failed for adding worker", + bsel->s->name); + } + } + + } + + } + + action = ap_construct_url(r->pool, r->uri, r); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01204) "genning page"); + if (apr_table_get(params, "xml")) { + char date[APR_RFC822_DATE_LEN]; ap_set_content_type(r, "text/xml"); - ap_rputs("\n", r); - ap_rputs("\n", r); + ap_rputs("\n", r); + ap_rputs("\n", r); ap_rputs(" \n", r); balancer = (proxy_balancer *)conf->balancers->elts; for (i = 0; i < conf->balancers->nelts; i++) { ap_rputs(" \n", r); - ap_rvputs(r, " ", balancer->name, "\n", NULL); + /* Start proxy_balancer */ + ap_rvputs(r, " ", balancer->s->name, "\n", NULL); + if (*balancer->s->sticky) { + ap_rvputs(r, " ", balancer->s->sticky, + "\n", NULL); + ap_rprintf(r, + " %s\n", + (balancer->s->sticky_force ? "On" : "Off")); + } + ap_rprintf(r, + " %" APR_TIME_T_FMT "", + apr_time_sec(balancer->s->timeout)); + if (balancer->s->max_attempts_set) { + ap_rprintf(r, + " %d\n", + balancer->s->max_attempts); + } + ap_rvputs(r, " ", balancer->lbmethod->name, + "\n", NULL); + if (*balancer->s->sticky) { + ap_rprintf(r, + " %s\n", + (balancer->s->scolonsep ? "On" : "Off")); + } + /* End proxy_balancer */ ap_rputs(" \n", r); workers = (proxy_worker **)balancer->workers->elts; for (n = 0; n < balancer->workers->nelts; n++) { worker = *workers; + /* Start proxy_worker */ ap_rputs(" \n", r); + ap_rvputs(r, " ", ap_proxy_worker_name(r->pool, worker), + "\n", NULL); ap_rvputs(r, " ", worker->s->scheme, "\n", NULL); ap_rvputs(r, " ", worker->s->hostname, "\n", NULL); ap_rprintf(r, " %d\n", worker->s->lbfactor); + ap_rprintf(r, + " %d\n", + worker->s->port); + ap_rprintf(r, " %d\n", + worker->s->min); + ap_rprintf(r, " %d\n", + worker->s->smax); + ap_rprintf(r, " %d\n", + worker->s->hmax); + ap_rprintf(r, + " %" APR_TIME_T_FMT "\n", + apr_time_sec(worker->s->ttl)); + if (worker->s->timeout_set) { + ap_rprintf(r, + " %" APR_TIME_T_FMT "\n", + apr_time_sec(worker->s->timeout)); + } + if (worker->s->acquire_set) { + ap_rprintf(r, + " %" APR_TIME_T_FMT "\n", + apr_time_msec(worker->s->acquire)); + } + if (worker->s->recv_buffer_size_set) { + ap_rprintf(r, + " %" APR_SIZE_T_FMT "\n", + worker->s->recv_buffer_size); + } + if (worker->s->io_buffer_size_set) { + ap_rprintf(r, + " %" APR_SIZE_T_FMT "\n", + worker->s->io_buffer_size); + } + if (worker->s->keepalive_set) { + ap_rprintf(r, + " %s\n", + (worker->s->keepalive ? "On" : "Off")); + } + /* Begin proxy_worker_stat */ + ap_rputs(" ", r); + if (worker->s->status & PROXY_WORKER_DISABLED) + ap_rputs("Disabled", r); + else if (worker->s->status & PROXY_WORKER_IN_ERROR) + ap_rputs("Error", r); + else if (worker->s->status & PROXY_WORKER_STOPPED) + ap_rputs("Stopped", r); + else if (worker->s->status & PROXY_WORKER_HOT_STANDBY) + ap_rputs("Standby", r); + else if (PROXY_WORKER_IS_USABLE(worker)) + ap_rputs("OK", r); + else if (!PROXY_WORKER_IS_INITIALIZED(worker)) + ap_rputs("Uninitialized", r); + ap_rputs("\n", r); + if ((worker->s->error_time > 0) && apr_rfc822_date(date, worker->s->error_time) == APR_SUCCESS) { + ap_rvputs(r, " ", date, + "\n", NULL); + } + ap_rprintf(r, + " %d\n", + worker->s->retries); + ap_rprintf(r, + " %d\n", + worker->s->lbstatus); + ap_rprintf(r, + " %d\n", + worker->s->lbfactor); + ap_rprintf(r, + " %" APR_OFF_T_FMT "\n", + worker->s->transferred); + ap_rprintf(r, + " %" APR_OFF_T_FMT "\n", + worker->s->read); + ap_rprintf(r, + " %" APR_SIZE_T_FMT "\n", + worker->s->elected); + ap_rvputs(r, " ", + ap_escape_html(r->pool, worker->s->route), + "\n", NULL); + ap_rvputs(r, " ", + ap_escape_html(r->pool, worker->s->redirect), + "\n", NULL); + ap_rprintf(r, + " %" APR_SIZE_T_FMT "\n", + worker->s->busy); + ap_rprintf(r, " %d\n", + worker->s->lbset); + /* End proxy_worker_stat */ + if (!ap_casecmpstr(worker->s->scheme, "ajp")) { + ap_rputs(" ", r); + switch (worker->s->flush_packets) { + case flush_off: + ap_rputs("Off", r); + break; + case flush_on: + ap_rputs("On", r); + break; + case flush_auto: + ap_rputs("Auto", r); + break; + } + ap_rputs("\n", r); + if (worker->s->flush_packets == flush_auto) { + ap_rprintf(r, + " %d\n", + worker->s->flush_wait); + } + if (worker->s->ping_timeout_set) { + ap_rprintf(r, + " %" APR_TIME_T_FMT "", + apr_time_msec(worker->s->ping_timeout)); + } + } + if (worker->s->disablereuse_set) { + ap_rprintf(r, + " %s\n", + (worker->s->disablereuse ? "On" : "Off")); + } + if (worker->s->conn_timeout_set) { + ap_rprintf(r, + " %" APR_TIME_T_FMT "\n", + apr_time_msec(worker->s->conn_timeout)); + } + if (worker->s->retry_set) { + ap_rprintf(r, + " %" APR_TIME_T_FMT "\n", + apr_time_sec(worker->s->retry)); + } ap_rputs(" \n", r); ++workers; } @@ -932,79 +1435,134 @@ static int balancer_handler(request_rec *r) else { ap_set_content_type(r, "text/html; charset=ISO-8859-1"); ap_rputs(DOCTYPE_HTML_3_2 - "Balancer Manager\n", r); + "Balancer Manager\n", r); + ap_rputs("\n\n", r); ap_rputs("

Load Balancer Manager for ", r); - ap_rvputs(r, ap_get_server_name(r), "

\n\n", NULL); + ap_rvputs(r, ap_escape_html(r->pool, ap_get_server_name(r)), + "\n\n", NULL); ap_rvputs(r, "
Server Version: ", ap_get_server_description(), "
\n", NULL); ap_rvputs(r, "
Server Built: ", - ap_get_server_built(), "\n
\n", NULL); + ap_get_server_built(), "\n", NULL); + ap_rvputs(r, "
Balancer changes will ", conf->bal_persist ? "" : "NOT ", + "be persisted on restart.
", NULL); + ap_rvputs(r, "
Balancers are ", conf->inherit ? "" : "NOT ", + "inherited from main server.
", NULL); + ap_rvputs(r, "
ProxyPass settings are ", conf->ppinherit ? "" : "NOT ", + "inherited from main server.
", NULL); + ap_rputs("\n", r); balancer = (proxy_balancer *)conf->balancers->elts; for (i = 0; i < conf->balancers->nelts; i++) { ap_rputs("
\n

LoadBalancer Status for ", r); - ap_rvputs(r, balancer->name, "

\n\n", NULL); - ap_rputs("\n\n" - "" - "\n", r); - if (balancer->sticky) { - if (strcmp(balancer->sticky, balancer->sticky_path)) { - ap_rvputs(r, "
StickySessionTimeoutFailoverAttemptsMethod
", balancer->sticky, " | ", - balancer->sticky_path, NULL); + ap_rvputs(r, "pool, r->uri), "?b=", + balancer->s->name + sizeof(BALANCER_PREFIX) - 1, + "&nonce=", balancer->s->nonce, + "\">", NULL); + ap_rvputs(r, balancer->s->name, " [",balancer->s->sname, "]\n", NULL); + ap_rputs("\n\n" + "" + "\n", r); + /* the below is a safe cast, since the number of slots total will + * never be more than max_workers, which is restricted to int */ + ap_rprintf(r, "\n", balancer->max_workers, + balancer->max_workers - (int)storage->num_free_slots(balancer->wslot)); + if (*balancer->s->sticky) { + if (strcmp(balancer->s->sticky, balancer->s->sticky_path)) { + ap_rvputs(r, "\n", + balancer->s->sticky_force ? "On" : "Off"); + ap_rprintf(r, "", + apr_time_sec(balancer->s->timeout)); + ap_rprintf(r, "\n", balancer->s->max_attempts); + ap_rprintf(r, "\n", + balancer->s->lbpname); + ap_rputs("", - apr_time_sec(balancer->timeout)); - ap_rprintf(r, "\n", balancer->max_attempts); + ap_rvputs(r, balancer->s->vpath, "\n", NULL); ap_rprintf(r, "\n", - balancer->lbmethod->name); + !balancer->s->inactive ? "Yes" : "No"); ap_rputs("
MaxMembersStickySessionDisableFailoverTimeoutFailoverAttemptsMethodPathActive
%d [%d Used]", balancer->s->sticky, " | ", + balancer->s->sticky_path, NULL); } else { - ap_rvputs(r, "", balancer->sticky, NULL); + ap_rvputs(r, "", balancer->s->sticky, NULL); } } else { - ap_rputs(" - ", r); + ap_rputs(" (None) ", r); + } + ap_rprintf(r, "%s%" APR_TIME_T_FMT "%d%s", r); + if (*balancer->s->vhost) { + ap_rvputs(r, balancer->s->vhost, " -> ", NULL); } - ap_rprintf(r, "%" APR_TIME_T_FMT "%d%s
\n
", r); - ap_rputs("\n\n" + ap_rputs("\n\n
" "" "" "" - "" - "\n", r); + "", r); + if (set_worker_hc_param_f) { + ap_rputs("", r); + } + ap_rputs("\n", r); workers = (proxy_worker **)balancer->workers->elts; for (n = 0; n < balancer->workers->nelts; n++) { char fbuf[50]; worker = *workers; - ap_rvputs(r, "\n\n", NULL); + ap_rvputs(r, (*worker->s->uds_path ? "" : ""), ap_proxy_worker_name(r->pool, worker), + (*worker->s->uds_path ? "" : ""), "", NULL); ap_rvputs(r, "", worker->s->lbfactor); ap_rprintf(r, "", r); - ap_rprintf(r, "", worker->s->elected); + ap_rprintf(r, "", worker->s->busy); + ap_rprintf(r, "", ap_proxy_show_hcmethod(worker->s->method)); + ap_rprintf(r, "", (int)apr_time_sec(worker->s->interval)); + ap_rprintf(r, "", worker->s->passes,worker->s->pcount); + ap_rprintf(r, "", worker->s->fails, worker->s->fcount); + ap_rprintf(r, "\n", r); ++workers; @@ -1015,43 +1573,98 @@ static int balancer_handler(request_rec *r) ap_rputs("
\n", r); if (wsel && bsel) { ap_rputs("

Edit worker settings for ", r); - ap_rvputs(r, wsel->s->name, "

\n", NULL); - ap_rvputs(r, "uri, "\">\n
", NULL); - ap_rputs("
Worker URLRouteRouteRedirFactorSetStatusElectedToFrom
ElectedBusyLoadToFromMethodIntervalPassesFailsURI
uri, "?b=", - balancer->name + sizeof(BALANCER_PREFIX) - 1, "&w=", + ap_rvputs(r, "
pool, r->uri), "?b=", + balancer->s->name + sizeof(BALANCER_PREFIX) - 1, "&w=", ap_escape_uri(r->pool, worker->s->name), - "&nonce=", balancer->nonce, + "&nonce=", balancer->s->nonce, "\">", NULL); - ap_rvputs(r, worker->s->name, "", ap_escape_html(r->pool, worker->s->route), NULL); ap_rvputs(r, "", ap_escape_html(r->pool, worker->s->redirect), NULL); ap_rprintf(r, "%d%d", worker->s->lbset); - if (worker->s->status & PROXY_WORKER_DISABLED) - ap_rputs("Dis ", r); - if (worker->s->status & PROXY_WORKER_IN_ERROR) - ap_rputs("Err ", r); - if (worker->s->status & PROXY_WORKER_STOPPED) - ap_rputs("Stop ", r); - if (worker->s->status & PROXY_WORKER_HOT_STANDBY) - ap_rputs("Stby ", r); - if (PROXY_WORKER_IS_USABLE(worker)) - ap_rputs("Ok", r); - if (!PROXY_WORKER_IS_INITIALIZED(worker)) - ap_rputs("-", r); + ap_rvputs(r, ap_proxy_parse_wstatus(r->pool, worker), NULL); ap_rputs("%" APR_SIZE_T_FMT "", worker->s->elected); + ap_rprintf(r, "%" APR_SIZE_T_FMT "%" APR_SIZE_T_FMT "%d", worker->s->lbstatus); ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r); ap_rputs("", r); ap_rputs(apr_strfsize(worker->s->read, fbuf), r); + if (set_worker_hc_param_f) { + ap_rprintf(r, "%s%d%d (%d)%d (%d)%s", worker->s->hcuri); + } ap_rputs("
\n", wsel->s->lbfactor); - ap_rputs("\n", wsel->s->lbset); - ap_rputs("", r); + ap_rputs("\n", r); + ap_rvputs(r, "
Load factor:
LB Set:
Route:s->uds_path?"":""), ap_proxy_worker_name(r->pool, wsel), (*wsel->s->uds_path?"":""), "\n", NULL); + ap_rputs("pool, action), "\">\n", NULL); + ap_rputs("\n", wsel->s->lbfactor); + ap_rputs("\n", wsel->s->lbset); + ap_rputs("\n", r); - ap_rputs("\n", r); - ap_rputs("\n", r); - ap_rputs("\n", r); - ap_rvputs(r, "
Load factor:
LB Set:
Route:pool, wsel->s->route), NULL); ap_rputs("\">
Route Redirect:Route Redirect:pool, wsel->s->redirect), NULL); ap_rputs("\">
Status:Disabled: s->status & PROXY_WORKER_DISABLED) - ap_rputs(" checked", r); - ap_rputs("> | Enabled: s->status & PROXY_WORKER_DISABLED)) - ap_rputs(" checked", r); - ap_rputs(">
\npool, wsel->s->name), "\">\n", NULL); - ap_rvputs(r, "name + sizeof(BALANCER_PREFIX) - 1, - "\">\n", NULL); - ap_rvputs(r, "nonce, "\">\n", NULL); - ap_rvputs(r, "\n", NULL); + ap_rputs("
Status:" + "" + "" + "" + "\n", r); + create_radio("w_status_I", (PROXY_WORKER_IGNORE_ERRORS & wsel->s->status), r); + create_radio("w_status_N", (PROXY_WORKER_DRAIN & wsel->s->status), r); + create_radio("w_status_D", (PROXY_WORKER_DISABLED & wsel->s->status), r); + create_radio("w_status_H", (PROXY_WORKER_HOT_STANDBY & wsel->s->status), r); + ap_rputs("
Ignore ErrorsDraining ModeDisabledHot Standby
\n", r); + ap_rputs("
\n\n", NULL); + ap_rvputs(r, "\n", NULL); + ap_rvputs(r, "\n", NULL); + ap_rputs("\n", r); + ap_rputs("
\n", r); + } else if (bsel) { + const apr_array_header_t *provs; + const ap_list_provider_names_t *pname; + int i; + ap_rputs("

Edit balancer settings for ", r); + ap_rvputs(r, bsel->s->name, "

\n", NULL); + ap_rputs("
\n", NULL); + ap_rputs("\n", r); + provs = ap_list_provider_names(r->pool, PROXY_LBMETHOD, "0"); + if (provs) { + ap_rputs("", r); + ap_rputs("\n", r); + } + ap_rputs("\n", apr_time_sec(bsel->s->timeout)); + ap_rputs("\n", bsel->s->max_attempts); + ap_rputs("", r); + create_radio("b_sforce", bsel->s->sticky_force, r); + ap_rputs("\n", r); + if (storage->num_free_slots(bsel->wslot) != 0) { + ap_rputs("", r); + } + ap_rputs("\n", r); + ap_rvputs(r, "
LBmethod:\n\n
Timeout:
Failover Attempts:
Disable Failover:
Sticky Session:s->sticky, bsel->s->sticky_path)) { + ap_rvputs(r, "value ='", bsel->s->sticky, " | ", + bsel->s->sticky_path, NULL); + } + else { + ap_rvputs(r, "value ='", bsel->s->sticky, NULL); + } + ap_rputs("'>    (Use '-' to delete)
Add New Worker:" + "    Are you sure? " + "
\n\n", NULL); + ap_rvputs(r, "\n", NULL); + ap_rputs("
\n", r); ap_rputs("
\n", r); } ap_rputs(ap_psignature("",r), r); ap_rputs("\n", r); + ap_rflush(r); } - return OK; + return DONE; } static void balancer_child_init(apr_pool_t *p, server_rec *s) @@ -1063,43 +1676,27 @@ static void balancer_child_init(apr_pool_t *p, server_rec *s) proxy_server_conf *conf = (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module); apr_status_t rv; - balancer = (proxy_balancer *)conf->balancers->elts; - for (i = 0; i < conf->balancers->nelts; i++) { + if (conf->balancers->nelts) { apr_size_t size; unsigned int num; - - /* - * for each balancer we need to init the global - * mutex and then attach to the shared worker shm - */ - if (!balancer->mutex) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "no mutex %s: %s", balancer->name, - balancer_mutex_type); - return; - } - - /* Re-open the mutex for the child. */ - rv = apr_global_mutex_child_init(&(balancer->mutex), - apr_global_mutex_lockfile(balancer->mutex), - p); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "Failed to reopen mutex %s: %s in child", - balancer->name, balancer_mutex_type); + storage->attach(&(conf->bslot), conf->id, &size, &num, p); + if (!conf->bslot) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01205) "slotmem_attach failed"); exit(1); /* Ugly, but what else? */ } + } - /* now attach */ - storage->attach(&(balancer->slot), balancer->sname, &size, &num, p); - if (!balancer->slot) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, 0, s, "slotmem_attach failed"); + balancer = (proxy_balancer *)conf->balancers->elts; + for (i = 0; i < conf->balancers->nelts; i++, balancer++) { + rv = ap_proxy_initialize_balancer(balancer, s, p); + + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(01206) + "Failed to init balancer %s in child", + balancer->s->name); exit(1); /* Ugly, but what else? */ } - if (balancer->lbmethod && balancer->lbmethod->reset) - balancer->lbmethod->reset(balancer, s); - init_balancer_members(conf, s, balancer); - balancer++; + init_balancer_members(conf->pool, s, balancer); } s = s->next; } @@ -1112,9 +1709,10 @@ static void ap_proxy_balancer_register_hook(apr_pool_t *p) * make sure that we are called after the mpm * initializes */ - static const char *const aszPred[] = { "mpm_winnt.c", NULL}; + static const char *const aszPred[] = { "mpm_winnt.c", "mod_slotmem_shm.c", NULL}; + static const char *const aszPred2[] = { "mod_proxy.c", NULL}; /* manager handler */ - ap_hook_post_config(balancer_post_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_post_config(balancer_post_config, aszPred2, NULL, APR_HOOK_MIDDLE); ap_hook_pre_config(balancer_pre_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_handler(balancer_handler, NULL, NULL, APR_HOOK_FIRST); ap_hook_child_init(balancer_child_init, aszPred, NULL, APR_HOOK_MIDDLE);