ap_proxy_initialize_worker(conf->forward, s);
/* Do not disable worker in case of errors */
conf->forward->s->status |= PROXY_WORKER_IGNORE_ERRORS;
+ /* Disable address cache for generic forward worker */
+ conf->forward->is_address_reusable = 0;
}
if (!reverse) {
reverse = ap_proxy_create_worker(p);
ap_proxy_initialize_worker(reverse, s);
/* Do not disable worker in case of errors */
reverse->s->status |= PROXY_WORKER_IGNORE_ERRORS;
+ /* Disable address cache for generic reverse worker */
+ reverse->is_address_reusable = 0;
}
conf->reverse = reverse;
s = s->next;
proxy_conn_pool *cp; /* Connection pool to use */
proxy_worker_stat *s; /* Shared data */
void *opaque; /* per scheme worker data */
+ int is_address_reusable;
+#if APR_HAS_THREADS
+ apr_thread_mutex_t *mutex; /* Thread lock for updating address cache */
+#endif
};
struct proxy_balancer {
#endif
};
+#if APR_HAS_THREADS
+#define PROXY_THREAD_LOCK(x) apr_thread_mutex_lock((x)->mutex)
+#define PROXY_THREAD_UNLOCK(x) apr_thread_mutex_unlock((x)->mutex)
+#else
+#define PROXY_THREAD_LOCK(x) APR_SUCCESS
+#define PROXY_THREAD_UNLOCK(x) APR_SUCCESS
+#endif
+
/* hooks */
/* Create a set of PROXY_DECLARE(type), PROXY_DECLARE_NONSTD(type) and
module AP_MODULE_DECLARE_DATA proxy_balancer_module;
-#if APR_HAS_THREADS
-#define PROXY_BALANCER_LOCK(b) apr_thread_mutex_lock((b)->mutex)
-#define PROXY_BALANCER_UNLOCK(b) apr_thread_mutex_unlock((b)->mutex)
-#else
-#define PROXY_BALANCER_LOCK(b) APR_SUCCESS
-#define PROXY_BALANCER_UNLOCK(b) APR_SUCCESS
-#endif
-
static int init_balancer_members(proxy_server_conf *conf, server_rec *s,
proxy_balancer *balancer)
{
proxy_worker *worker = (proxy_worker *)balancer->workers->elts;
proxy_worker *candidate = NULL;
- if (PROXY_BALANCER_LOCK(balancer) != APR_SUCCESS)
+ if (PROXY_THREAD_LOCK(balancer) != APR_SUCCESS)
return NULL;
/* First try to see if we have available candidate */
if (candidate) {
candidate->s->lbstatus -= total_factor;
candidate->s->elected++;
- PROXY_BALANCER_UNLOCK(balancer);
+ PROXY_THREAD_UNLOCK(balancer);
return candidate;
}
else {
- PROXY_BALANCER_UNLOCK(balancer);
+ PROXY_THREAD_UNLOCK(balancer);
/* All the workers are in error state or disabled.
* If the balancer has a timeout sleep for a while
* and try again to find the worker. The chances are
/* Lock the LoadBalancer
* XXX: perhaps we need the process lock here
*/
- if ((rv = PROXY_BALANCER_LOCK(*balancer)) != APR_SUCCESS) {
+ if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
"proxy: BALANCER: lock");
return DECLINED;
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);
- PROXY_BALANCER_UNLOCK(*balancer);
+ PROXY_THREAD_UNLOCK(*balancer);
return HTTP_SERVICE_UNAVAILABLE;
}
- PROXY_BALANCER_UNLOCK(*balancer);
+ PROXY_THREAD_UNLOCK(*balancer);
if (!*worker) {
runtime = find_best_worker(*balancer, r);
if (!runtime) {
{
apr_status_t rv;
- if ((rv = PROXY_BALANCER_LOCK(balancer)) != APR_SUCCESS) {
+ if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
"proxy: BALANCER: lock");
return HTTP_INTERNAL_SERVER_ERROR;
* track on that.
*/
- PROXY_BALANCER_UNLOCK(balancer);
+ PROXY_THREAD_UNLOCK(balancer);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy_balancer_post_request for (%s)", balancer->name);
conn_rec *c = r->connection;
proxy_conn_rec *backend;
apr_socket_t *sock, *local_sock, *data_sock = NULL;
- apr_sockaddr_t *connect_addr;
+ apr_sockaddr_t *connect_addr = NULL;
apr_status_t rv;
conn_rec *origin, *data = NULL;
apr_status_t err = APR_SUCCESS;
int connect = 0, use_port = 0;
char dates[APR_RFC822_DATE_LEN];
int status;
+ apr_pool_t *address_pool;
/* is this for us? */
if (proxyhost) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: FTP: connecting %s to %s:%d", url, connectname, connectport);
+ if (worker->is_address_reusable) {
+ if (!worker->cp->addr) {
+ if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server,
+ "proxy: FTP: lock");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+ connect_addr = worker->cp->addr;
+ address_pool = worker->cp->pool;
+ }
+ else
+ address_pool = r->pool;
+
/* do a DNS lookup for the destination host */
- if (!worker->cp->addr)
- err = apr_sockaddr_info_get(&(worker->cp->addr),
+ if (!connect_addr)
+ err = apr_sockaddr_info_get(&(connect_addr),
connectname, APR_UNSPEC,
connectport, 0,
- worker->cp->pool);
+ address_pool);
+ if (worker->is_address_reusable && !worker->cp->addr) {
+ worker->cp->addr = connect_addr;
+ PROXY_THREAD_UNLOCK(worker);
+ }
/*
* get all the possible IP addresses for the destname and loop through
* them until we get a successful connection
}
/* check if ProxyBlock directive on this host */
- if (OK != ap_proxy_checkproxyblock(r, conf, worker->cp->addr)) {
+ if (OK != ap_proxy_checkproxyblock(r, conf, connect_addr)) {
return ap_proxyerror(r, HTTP_FORBIDDEN,
"Connect to remote machine blocked");
}
return status;
}
/* TODO: see if ftp could use determine_connection */
- backend->addr = worker->cp->addr;
+ backend->addr = connect_addr;
ap_set_module_config(c->conn_config, &proxy_ftp_module, backend);
}
if (ap_proxy_connect_backend("FTP", backend, worker, r->server)) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: FTP: an error occurred creating a new connection to %pI (%s)",
- worker->cp->addr, connectname);
+ connect_addr, connectname);
proxy_ftp_cleanup(r, backend);
return HTTP_SERVICE_UNAVAILABLE;
}
/* Use old naming */
origin = backend->connection;
- connect_addr = worker->cp->addr;
sock = backend->sock;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: request failed to %pI (%s)",
- conn->worker->cp->addr, conn->hostname);
+ conn->addr, conn->hostname);
return status;
}
}
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: pass request data failed to %pI (%s)",
- conn->worker->cp->addr, conn->hostname);
+ conn->addr, conn->hostname);
return status;
}
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: pass request data failed to %pI (%s)",
- conn->worker->cp->addr, conn->hostname);
+ conn->addr, conn->hostname);
return status;
}
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
"proxy: pass request data failed to %pI (%s)",
- conn->worker->cp->addr, conn->hostname);
+ conn->addr, conn->hostname);
return status;
}
apr_brigade_length(body_brigade, 0, &transfered);
/* Increase the total worker count */
proxy_lb_workers++;
init_conn_pool(p, *worker);
+#if APR_HAS_THREADS
+ if (apr_thread_mutex_create(&((*worker)->mutex),
+ APR_THREAD_MUTEX_DEFAULT, p) != APR_SUCCESS) {
+ /* XXX: Do we need to log something here */
+ return "can not create thread mutex";
+ }
+#endif
return NULL;
}
/* Set default parameters */
if (!worker->retry)
worker->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY);
+ /* By default address is reusable */
+ worker->is_address_reusable = 1;
}
}
}
/* TODO: add address cache for forward proxies */
- conn->addr = worker->cp->addr;
- if (r->proxyreq == PROXYREQ_PROXY) {
+ if (r->proxyreq == PROXYREQ_PROXY || r->proxyreq == PROXYREQ_REVERSE ||
+ !worker->is_address_reusable) {
err = apr_sockaddr_info_get(&(conn->addr),
conn->hostname, APR_UNSPEC,
conn->port, 0,
conn->pool);
}
else if (!worker->cp->addr) {
+ if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server,
+ "proxy: lock");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
/* Worker can have the single constant backend adress.
* The single DNS lookup is used once per worker.
* If dynamic change is needed then set the addr to NULL
conn->port, 0,
worker->cp->pool);
conn->addr = worker->cp->addr;
+ PROXY_THREAD_UNLOCK(worker);
}
if (err != APR_SUCCESS) {
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
server_port);
}
}
-
/* check if ProxyBlock directive on this host */
if (OK != ap_proxy_checkproxyblock(r, conf, conn->addr)) {
return ap_proxyerror(r, HTTP_FORBIDDEN,