From: Jim Jagielski Date: Tue, 21 Jan 2014 16:44:04 +0000 (+0000) Subject: Merge r1451633, r1451905, r1451921, r1452259, r1453981, r1501913, r1513508, r1531340... X-Git-Tag: 2.4.8~230 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7f456709e34158f81c04ca3e2e6b19b467ca49ed;p=apache Merge r1451633, r1451905, r1451921, r1452259, r1453981, r1501913, r1513508, r1531340, r1531370, r1531962, r1533065, r1540052 from trunk: Add in rough uds support (Bugx 54101) from Blaise Tarr Make AF_UNIX aware... fix Windows/Netware?? Follow-up to r1451905 to fix NetWare/Windows compilation. apr trunk-able message tag for dom sock Note about new UDS support UDS subsequent request on a connection fix Reformat the UDS support inline with a new naming structure. Use a flag for speed for testing. syntax sugar... if the worker is associated w/ a UDS, then make sure the log reporting has a visual clue. Ensure that userland format of UDS is the same as how it is configured, no matter how we store and use it internally. Eclipse code analysis warning UDS urls need to be desockified when configuring... Submitted by: jim, fuankg, jim, jim, druggeri, druggeri, jim, jim, jim, jim, jim Reviewed/backported by: jim git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1560081 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index aa745101e0..c04f48f1d7 100644 --- a/CHANGES +++ b/CHANGES @@ -66,6 +66,10 @@ Changes with Apache 2.4.7 keys, and unconditionally disable aNULL, eNULL and EXP ciphers (not overridable via SSLCipherSuite). [Kaspar Brand] + *) mod_proxy: Added support for unix domain sockets as the + backend server endpoint [Jim Jagielski, Blaise Tarr + ] + *) Add experimental cmake-based build system for Windows. [Jeff Trawick, Tom Donovan] diff --git a/STATUS b/STATUS index 8ef3033c04..440cefe624 100644 --- a/STATUS +++ b/STATUS @@ -98,22 +98,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_proxy: support Unix domain sockets - trunk patch: https://svn.apache.org/viewvc?view=revision&revision=1451633 - https://svn.apache.org/viewvc?view=revision&revision=1451905 - https://svn.apache.org/viewvc?view=revision&revision=1451921 - https://svn.apache.org/viewvc?view=revision&revision=1452259 - https://svn.apache.org/viewvc?view=revision&revision=1453981 - https://svn.apache.org/viewvc?view=revision&revision=1501913 - https://svn.apache.org/viewvc?view=revision&revision=1513508 - https://svn.apache.org/viewvc?view=revision&revision=1531340 - https://svn.apache.org/viewvc?view=revision&revision=1531370 - https://svn.apache.org/viewvc?view=revision&revision=1531962 - https://svn.apache.org/viewvc?view=revision&revision=1533065 - https://svn.apache.org/viewvc?view=revision&revision=1540052 - 2.4.x patch: http://people.apache.org/~jim/patches/uds-2.4.patch - +1: jim, druggeri, humbedooh - * mod_ssl: address the "init functions should return status code rather than ssl_die()" todo from 2002 (avoid orphan IPC objects after startup or reload failures, see also the "ssl_die() and pool cleanup" thread diff --git a/docs/manual/mod/mod_proxy.xml b/docs/manual/mod/mod_proxy.xml index dd939941b9..987f46a60c 100644 --- a/docs/manual/mod/mod_proxy.xml +++ b/docs/manual/mod/mod_proxy.xml @@ -837,6 +837,14 @@ expressions usually be set off when using ProxyPass. +

Support for using a Unix Domain Socket is available by using a target + which prepends unix:/path/lis.sock|. For example, to proxy + HTTP and target the UDS at /home/www/socket you would use + unix:/home/www.socket|http://localhost/whatever/.

+ + Note: The path associated with the unix: + URL is DefaultRuntimeDir aware. +

Suppose the local server has address http://example.com/; then

diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 115e769fd7..c95274246e 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -423,6 +423,7 @@ * 20120211.26 (2.4.7-dev) Add util_fcgi.h, FastCGI protocol support * 20120211.27 (2.4.7-dev) Add ap_podx_restart_t and ap_mpm_podx_* * 20120211.28 (2.4.7-dev) Add ap_regname + * 20120211.29 (2.4.7-dev) Add uds_path to proxy_conn_rec */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -430,7 +431,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 28 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 29 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 15ba32a379..60e3e28f7a 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -1370,7 +1370,6 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv) return new; } - static const char * add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex) { @@ -1445,6 +1444,36 @@ static const char * return add_proxy(cmd, dummy, f1, r1, 1); } +static char *de_socketfy(apr_pool_t *p, char *url) +{ + char *ptr; + /* + * We could be passed a URL during the config stage that contains + * the UDS path... ignore it + */ + if (!strncasecmp(url, "unix:", 5) && + ((ptr = ap_strchr(url, '|')) != NULL)) { + /* move past the 'unix:...|' UDS path info */ + char *ret, *c; + + ret = ptr + 1; + /* special case: "unix:....|scheme:" is OK, expand + * to "unix:....|scheme://localhost" + * */ + c = ap_strchr(ret, ':'); + if (c == NULL) { + return NULL; + } + if (c[1] == '\0') { + return apr_pstrcat(p, ret, "//localhost", NULL); + } + else { + return ret; + } + } + return url; +} + static const char * add_pass(cmd_parms *cmd, void *dummy, const char *arg, int is_regex) { @@ -1536,7 +1565,7 @@ static const char * } new->fake = apr_pstrdup(cmd->pool, f); - new->real = apr_pstrdup(cmd->pool, r); + new->real = apr_pstrdup(cmd->pool, de_socketfy(cmd->pool, r)); new->flags = flags; if (use_regex) { new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED); @@ -1572,7 +1601,7 @@ static const char * new->balancer = balancer; } else { - proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, r); + proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->pool, r)); int reuse = 0; if (!worker) { const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0); @@ -1584,14 +1613,14 @@ static const char * reuse = 1; ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01145) "Sharing worker '%s' instead of creating new worker '%s'", - worker->s->name, new->real); + ap_proxy_worker_name(cmd->pool, worker), new->real); } for (i = 0; i < arr->nelts; i++) { if (reuse) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01146) "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing", - elts[i].key, elts[i].val, worker->s->name); + elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker)); } else { const char *err = set_worker_param(cmd->pool, worker, elts[i].key, elts[i].val); @@ -2048,7 +2077,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) } /* Try to find existing worker */ - worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, name); + worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, de_socketfy(cmd->temp_pool, name)); if (!worker) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147) "Defining worker '%s' for balancer '%s'", @@ -2057,13 +2086,13 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01148) "Defined worker '%s' for balancer '%s'", - worker->s->name, balancer->s->name); + ap_proxy_worker_name(cmd->pool, worker), balancer->s->name); PROXY_COPY_CONF_PARAMS(worker, conf); } else { reuse = 1; ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01149) "Sharing worker '%s' instead of creating new worker '%s'", - worker->s->name, name); + ap_proxy_worker_name(cmd->pool, worker), name); } arr = apr_table_elts(params); @@ -2072,7 +2101,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) if (reuse) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01150) "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing", - elts[i].key, elts[i].val, worker->s->name); + elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker)); } else { err = set_worker_param(cmd->pool, worker, elts[i].key, elts[i].val); @@ -2134,7 +2163,7 @@ static const char * } } else { - worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, name); + worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->temp_pool, name)); if (!worker) { if (in_proxy_section) { err = ap_proxy_define_worker(cmd->pool, &worker, NULL, @@ -2274,7 +2303,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) } else { worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf, - conf->p); + de_socketfy(cmd->temp_pool, (char*)conf->p)); if (!worker) { err = ap_proxy_define_worker(cmd->pool, &worker, NULL, sconf, conf->p, 0); diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 0afa8543f5..9d27ae01e9 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -253,6 +253,7 @@ typedef struct { unsigned int need_flush:1; /* Flag to decide whether we need to flush the * filter chain or not */ unsigned int inreslist:1; /* connection in apr_reslist? */ + const char *uds_path; /* Unix domain socket path */ } proxy_conn_rec; typedef struct { @@ -345,6 +346,7 @@ typedef struct { char route[PROXY_WORKER_MAX_ROUTE_SIZE]; /* balancing route */ char redirect[PROXY_WORKER_MAX_ROUTE_SIZE]; /* temporary balancing redirection route */ char flusher[PROXY_WORKER_MAX_SCHEME_SIZE]; /* flush provider used by mod_proxy_fdpass */ + char uds_path[PROXY_WORKER_MAX_NAME_SIZE]; /* path to worker's unix domain socket if applicable */ int lbset; /* load balancer cluster set */ int retries; /* number of retries on this worker */ int lbstatus; /* Current lbstatus */ @@ -589,6 +591,16 @@ typedef __declspec(dllimport) const char * /* Connection pool API */ +/** + * Return the user-land, UDS aware worker name + * @param p memory pool used for displaying worker name + * @param worker the worker + * @return name + */ + +PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, + proxy_worker *worker); + /** * Get the worker from proxy configuration * @param p memory pool used for finding worker diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index 5fd9e1513c..c927d3bf6e 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -118,7 +118,8 @@ static void init_balancer_members(apr_pool_t *p, server_rec *s, int worker_is_initialized; proxy_worker *worker = *workers; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01158) - "Looking at %s -> %s initialized?", balancer->s->name, worker->s->name); + "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, p); @@ -638,10 +639,11 @@ static int proxy_balancer_post_request(proxy_worker *worker, int val = ((int *)balancer->errstatuses->elts)[i]; if (r->status == val) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01174) - "%s: Forcing worker (%s) into error state " + "%s: Forcing worker (%s) into error state " "due to status code %d matching 'failonstatus' " "balancer parameter", - balancer->s->name, worker->s->name, val); + 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; @@ -654,7 +656,7 @@ static int proxy_balancer_post_request(proxy_worker *worker, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02460) "%s: Forcing worker (%s) into error state " "due to timeout and 'failonstatus' parameter being set", - balancer->s->name, worker->s->name); + balancer->s->name, ap_proxy_worker_name(r->pool, worker)); worker->s->status |= PROXY_WORKER_IN_ERROR; worker->s->error_time = apr_time_now(); @@ -1282,7 +1284,7 @@ static int balancer_handler(request_rec *r) worker = *workers; /* Start proxy_worker */ ap_rputs(" \n", r); - ap_rvputs(r, " ", worker->s->name, + ap_rvputs(r, " ", ap_proxy_worker_name(r->pool, worker), "\n", NULL); ap_rvputs(r, " ", worker->s->scheme, "\n", NULL); @@ -1531,7 +1533,8 @@ static int balancer_handler(request_rec *r) ap_escape_uri(r->pool, worker->s->name), "&nonce=", balancer->s->nonce, "\">", NULL); - ap_rvputs(r, worker->s->name, "", NULL); + ap_rvputs(r, (*worker->s->uds_path ? "" : ""), ap_proxy_worker_name(r->pool, worker), + (*worker->s->uds_path ? "" : ""), "", NULL); ap_rvputs(r, "", ap_escape_html(r->pool, worker->s->route), NULL); ap_rvputs(r, "", @@ -1556,7 +1559,7 @@ 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, (*wsel->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
Load factor: +#endif +#if (APR_MAJOR_VERSION < 2) +#include "apr_support.h" /* for apr_wait_for_io_or_timeout() */ +#endif + APLOG_USE_MODULE(proxy); /* @@ -86,14 +93,20 @@ PROXY_DECLARE(apr_status_t) ap_proxy_strncpy(char *dst, const char *src, char *thenil; apr_size_t thelen; + /* special case handling */ + if (!dlen) { + /* XXX: APR_ENOSPACE would be better */ + return APR_EGENERAL; + } + if (!src) { + *dst = '\0'; + return APR_SUCCESS; + } thenil = apr_cpystrn(dst, src, dlen); thelen = thenil - dst; - /* Assume the typical case is smaller copying into bigger - so we have a fast return */ - if ((thelen < dlen-1) || ((strlen(src)) == thelen)) { + if (src[thelen] == '\0') { return APR_SUCCESS; } - /* XXX: APR_ENOSPACE would be better */ return APR_EGENERAL; } @@ -1218,11 +1231,11 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_balancer(proxy_balancer *balancer, } else { action = "re-using"; } + balancer->s = shm; + balancer->s->index = i; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02337) "%s shm[%d] (0x%pp) for %s", action, i, (void *)shm, balancer->s->name); - balancer->s = shm; - balancer->s->index = i; /* the below should always succeed */ lbmethod = ap_lookup_provider(PROXY_LBMETHOD, balancer->s->lbpname, "0"); if (lbmethod) { @@ -1356,7 +1369,7 @@ static apr_status_t connection_cleanup(void *theconn) ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool, APLOGNO(00923) "Pooled connection 0x%pp for worker %s has been" " already returned to the connection pool.", conn, - worker->s->name); + ap_proxy_worker_name(conn->pool, worker)); return APR_SUCCESS; } @@ -1480,6 +1493,16 @@ static apr_status_t connection_destructor(void *resource, void *params, * WORKER related... */ +PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, + proxy_worker *worker) +{ + if (!(*worker->s->uds_path) || !p) { + /* just in case */ + return worker->s->name; + } + return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL); +} + PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, proxy_balancer *balancer, proxy_server_conf *conf, @@ -1495,6 +1518,10 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, char *url_copy; int i; + if (!url) { + return NULL; + } + c = ap_strchr_c(url, ':'); if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') { return NULL; @@ -1573,20 +1600,47 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, int do_malloc) { int rv; - apr_uri_t uri; + apr_uri_t uri, urisock; proxy_worker_shared *wshared; - char *ptr; + char *ptr, *sockpath = NULL; + /* + * Look to see if we are using UDS: + * require format: unix:/path/foo/bar.sock|http://ignored/path2/ + * This results in talking http to the socket at /path/foo/bar.sock + */ + ptr = ap_strchr((char *)url, '|'); + if (ptr) { + *ptr = '\0'; + rv = apr_uri_parse(p, url, &urisock); + if (rv == APR_SUCCESS && !strcasecmp(urisock.scheme, "unix")) { + sockpath = ap_runtime_dir_relative(p, urisock.path);; + url = ptr+1; /* so we get the scheme for the uds */ + } + else { + *ptr = '|'; + } + } rv = apr_uri_parse(p, url, &uri); if (rv != APR_SUCCESS) { - return "Unable to parse URL"; + return apr_pstrcat(p, "Unable to parse URL: ", url, NULL); } - if (!uri.hostname || !uri.scheme) { - return "URL must be absolute!"; + if (!uri.scheme) { + return apr_pstrcat(p, "URL must be absolute!: ", url, NULL); + } + /* allow for unix:/path|http: */ + if (!uri.hostname) { + if (sockpath) { + uri.hostname = "localhost"; + } + else { + return apr_pstrcat(p, "URL must be absolute!: ", url, NULL); + } + } + else { + ap_str_tolower(uri.hostname); } - - ap_str_tolower(uri.hostname); ap_str_tolower(uri.scheme); /* * Workers can be associated w/ balancers or on their @@ -1642,6 +1696,15 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, wshared->hash.def = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_DEFAULT); wshared->hash.fnv = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_FNV); wshared->was_malloced = (do_malloc != 0); + if (sockpath) { + if (PROXY_STRNCPY(wshared->uds_path, sockpath) != APR_SUCCESS) { + return apr_psprintf(p, "worker uds path (%s) too long", sockpath); + } + + } + else { + *wshared->uds_path = '\0'; + } (*worker)->hash = wshared->hash; (*worker)->context = NULL; @@ -1670,12 +1733,18 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_worker(proxy_worker *worker, proxy_wo } else { action = "re-using"; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338) - "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm, - worker->s->name); - worker->s = shm; worker->s->index = i; + { + apr_pool_t *pool; + apr_pool_create(&pool, ap_server_conf->process->pool); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338) + "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm, + ap_proxy_worker_name(pool, worker)); + if (pool) { + apr_pool_destroy(pool); + } + } return APR_SUCCESS; } @@ -1687,11 +1756,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser if (worker->s->status & PROXY_WORKER_INITIALIZED) { /* The worker is already initialized */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00924) - "worker %s shared already initialized", worker->s->name); + "worker %s shared already initialized", + ap_proxy_worker_name(p, worker)); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00925) - "initializing worker %s shared", worker->s->name); + "initializing worker %s shared", + ap_proxy_worker_name(p, worker)); /* Set default parameters */ if (!worker->s->retry_set) { worker->s->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY); @@ -1727,11 +1798,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser /* What if local is init'ed and shm isn't?? Even possible? */ if (worker->local_status & PROXY_WORKER_INITIALIZED) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00926) - "worker %s local already initialized", worker->s->name); + "worker %s local already initialized", + ap_proxy_worker_name(p, worker)); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927) - "initializing worker %s local", worker->s->name); + "initializing worker %s local", + ap_proxy_worker_name(p, worker)); apr_global_mutex_lock(proxy_mutex); /* Now init local worker data */ if (worker->tmutex == NULL) { @@ -2023,6 +2096,29 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, (*conn)->close = 0; (*conn)->inreslist = 0; + if (*worker->s->uds_path) { + if ((*conn)->uds_path == NULL) { + /* use (*conn)->pool instead of worker->cp->pool to match lifetime */ + (*conn)->uds_path = apr_pstrdup((*conn)->pool, worker->s->uds_path); + } + if ((*conn)->uds_path) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02545) + "%s: has determined UDS as %s", + proxy_function, (*conn)->uds_path); + } + else { + /* should never happen */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02546) + "%s: cannot determine UDS (%s)", + proxy_function, worker->s->uds_path); + + } + } + else { + (*conn)->uds_path = NULL; + } + + return OK; } @@ -2094,7 +2190,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, * spilling the cached addr from the worker. */ if (!conn->hostname || !worker->s->is_address_reusable || - worker->s->disablereuse) { + worker->s->disablereuse || *worker->s->uds_path) { if (proxyname) { conn->hostname = apr_pstrdup(conn->pool, proxyname); conn->port = proxyport; @@ -2132,7 +2228,8 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, conn->port = uri->port; } socket_cleanup(conn); - if (!worker->s->is_address_reusable || worker->s->disablereuse) { + if (!(*worker->s->uds_path) && + (!worker->s->is_address_reusable || worker->s->disablereuse)) { /* * Only do a lookup if we should not reuse the backend address. * Otherwise we will look it up once for the worker. @@ -2143,7 +2240,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, conn->pool); } } - if (worker->s->is_address_reusable && !worker->s->disablereuse) { + if (!(*worker->s->uds_path) && worker->s->is_address_reusable && !worker->s->disablereuse) { /* * Looking up the backend address for the worker only makes sense if * we can reuse the address. @@ -2372,6 +2469,52 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, } +#if APR_HAVE_SYS_UN_H +/* lifted from mod_proxy_fdpass.c; tweaked addrlen in connect() call */ +static apr_status_t socket_connect_un(apr_socket_t *sock, + struct sockaddr_un *sa) +{ + apr_status_t rv; + apr_os_sock_t rawsock; + apr_interval_time_t t; + + rv = apr_os_sock_get(&rawsock, sock); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_get(sock, &t); + if (rv != APR_SUCCESS) { + return rv; + } + + do { + const socklen_t addrlen = APR_OFFSETOF(struct sockaddr_un, sun_path) + + strlen(sa->sun_path) + 1; + rv = connect(rawsock, (struct sockaddr*)sa, addrlen); + } while (rv == -1 && errno == EINTR); + + if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY) + && (t > 0)) { +#if APR_MAJOR_VERSION < 2 + rv = apr_wait_for_io_or_timeout(NULL, sock, 0); +#else + rv = apr_socket_wait(sock, APR_WAIT_WRITE); +#endif + + if (rv != APR_SUCCESS) { + return rv; + } + } + + if (rv == -1 && errno != EISCONN) { + return errno; + } + + return APR_SUCCESS; +} +#endif + PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, proxy_conn_rec *conn, proxy_worker *worker, @@ -2396,93 +2539,131 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, proxy_function); } } - while (backend_addr && !connected) { - if ((rv = apr_socket_create(&newsock, backend_addr->family, - SOCK_STREAM, APR_PROTO_TCP, - conn->scpool)) != APR_SUCCESS) { - loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; - ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952) - "%s: error creating fam %d socket for target %s", - proxy_function, - backend_addr->family, - worker->s->hostname); - /* - * this could be an IPv6 address from the DNS but the - * local machine won't give us an IPv6 socket; hopefully the - * DNS returned an additional address to try - */ - backend_addr = backend_addr->next; - continue; - } - conn->connection = NULL; + while ((backend_addr || conn->uds_path) && !connected) { +#if APR_HAVE_SYS_UN_H + if (conn->uds_path) + { + struct sockaddr_un sa; - if (worker->s->recv_buffer_size > 0 && - (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF, - worker->s->recv_buffer_size))) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953) - "apr_socket_opt_set(SO_RCVBUF): Failed to set " - "ProxyReceiveBufferSize, using default"); - } + rv = apr_socket_create(&newsock, AF_UNIX, SOCK_STREAM, 0, + conn->scpool); + if (rv != APR_SUCCESS) { + loglevel = APLOG_ERR; + ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(02453) + "%s: error creating Unix domain socket for " + "target %s", + proxy_function, + worker->s->hostname); + break; + } + conn->connection = NULL; - rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1); - if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954) - "apr_socket_opt_set(APR_TCP_NODELAY): " - "Failed to set"); - } + sa.sun_family = AF_UNIX; + apr_cpystrn(sa.sun_path, conn->uds_path, sizeof(sa.sun_path)); - /* Set a timeout for connecting to the backend on the socket */ - if (worker->s->conn_timeout_set) { - apr_socket_timeout_set(newsock, worker->s->conn_timeout); - } - else if (worker->s->timeout_set) { - apr_socket_timeout_set(newsock, worker->s->timeout); - } - else if (conf->timeout_set) { - apr_socket_timeout_set(newsock, conf->timeout); - } - else { - apr_socket_timeout_set(newsock, s->timeout); - } - /* Set a keepalive option */ - if (worker->s->keepalive) { - if ((rv = apr_socket_opt_set(newsock, - APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955) - "apr_socket_opt_set(SO_KEEPALIVE): Failed to set" - " Keepalive"); + rv = socket_connect_un(newsock, &sa); + if (rv != APR_SUCCESS) { + apr_socket_close(newsock); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02454) + "%s: attempt to connect to Unix domain socket " + "%s (%s) failed", + proxy_function, + conn->uds_path, + worker->s->hostname); + break; } } - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, - "%s: fam %d socket created to connect to %s", - proxy_function, backend_addr->family, worker->s->hostname); + else +#endif + { + if ((rv = apr_socket_create(&newsock, backend_addr->family, + SOCK_STREAM, APR_PROTO_TCP, + conn->scpool)) != APR_SUCCESS) { + loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; + ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952) + "%s: error creating fam %d socket for " + "target %s", + proxy_function, + backend_addr->family, + worker->s->hostname); + /* + * this could be an IPv6 address from the DNS but the + * local machine won't give us an IPv6 socket; hopefully the + * DNS returned an additional address to try + */ + backend_addr = backend_addr->next; + continue; + } + conn->connection = NULL; + + if (worker->s->recv_buffer_size > 0 && + (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF, + worker->s->recv_buffer_size))) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953) + "apr_socket_opt_set(SO_RCVBUF): Failed to set " + "ProxyReceiveBufferSize, using default"); + } - if (conf->source_address_set) { - local_addr = apr_pmemdup(conn->pool, conf->source_address, - sizeof(apr_sockaddr_t)); - local_addr->pool = conn->pool; - rv = apr_socket_bind(newsock, local_addr); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956) - "%s: failed to bind socket to local address", - proxy_function); + rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1); + if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954) + "apr_socket_opt_set(APR_TCP_NODELAY): " + "Failed to set"); } - } - /* make the connection out of the socket */ - rv = apr_socket_connect(newsock, backend_addr); + /* Set a timeout for connecting to the backend on the socket */ + if (worker->s->conn_timeout_set) { + apr_socket_timeout_set(newsock, worker->s->conn_timeout); + } + else if (worker->s->timeout_set) { + apr_socket_timeout_set(newsock, worker->s->timeout); + } + else if (conf->timeout_set) { + apr_socket_timeout_set(newsock, conf->timeout); + } + else { + apr_socket_timeout_set(newsock, s->timeout); + } + /* Set a keepalive option */ + if (worker->s->keepalive) { + if ((rv = apr_socket_opt_set(newsock, + APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955) + "apr_socket_opt_set(SO_KEEPALIVE): Failed to set" + " Keepalive"); + } + } + ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, + "%s: fam %d socket created to connect to %s", + proxy_function, backend_addr->family, worker->s->hostname); + + if (conf->source_address_set) { + local_addr = apr_pmemdup(conn->pool, conf->source_address, + sizeof(apr_sockaddr_t)); + local_addr->pool = conn->pool; + rv = apr_socket_bind(newsock, local_addr); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956) + "%s: failed to bind socket to local address", + proxy_function); + } + } - /* if an error occurred, loop round and try again */ - if (rv != APR_SUCCESS) { - apr_socket_close(newsock); - loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; - ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957) - "%s: attempt to connect to %pI (%s) failed", - proxy_function, - backend_addr, - worker->s->hostname); - backend_addr = backend_addr->next; - continue; + /* make the connection out of the socket */ + rv = apr_socket_connect(newsock, backend_addr); + + /* if an error occurred, loop round and try again */ + if (rv != APR_SUCCESS) { + apr_socket_close(newsock); + loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; + ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957) + "%s: attempt to connect to %pI (%s) failed", + proxy_function, + backend_addr, + worker->s->hostname); + backend_addr = backend_addr->next; + continue; + } } /* Set a timeout on the socket */ @@ -2498,7 +2679,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, conn->sock = newsock; - if (conn->forward) { + if (!conn->uds_path && conn->forward) { forward_info *forward = (forward_info *)conn->forward; /* * For HTTP CONNECT we need to prepend CONNECT request before @@ -2779,7 +2960,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer(proxy_balancer *b, server_rec found = 1; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02402) "re-grabbing shm[%d] (0x%pp) for worker: %s", i, (void *)shm, - worker->s->name); + ap_proxy_worker_name(conf->pool, worker)); break; } }