1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-07 04:02:58 +03:00

Add in rough uds support (Bugx 54101) from Blaise Tarr <blaise.tarr@gmail.com>

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1451633 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jim Jagielski
2013-03-01 16:21:49 +00:00
parent 9c4a88068a
commit f5f921a2f2
3 changed files with 200 additions and 83 deletions

View File

@@ -414,6 +414,7 @@
* add ap_has_cntrl() * add ap_has_cntrl()
* 20121222.2 (2.5.0-dev) Add ap_password_validate() * 20121222.2 (2.5.0-dev) Add ap_password_validate()
* 20121222.3 (2.5.0-dev) Add ppinherit to proxy_server_conf * 20121222.3 (2.5.0-dev) Add ppinherit to proxy_server_conf
* 20121222.4 (2.5.0-dev) Add uds_path to proxy_conn_rec
*/ */
#define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */

View File

@@ -236,6 +236,7 @@ typedef struct {
* that is used over the backend connection. */ * that is used over the backend connection. */
proxy_worker *worker; /* Connection pool this connection belongs to */ proxy_worker *worker; /* Connection pool this connection belongs to */
apr_pool_t *pool; /* Subpool for hostname and addr data */ apr_pool_t *pool; /* Subpool for hostname and addr data */
const char *uds_path; /* Unix domain socket path */
const char *hostname; const char *hostname;
apr_sockaddr_t *addr; /* Preparsed remote address info */ apr_sockaddr_t *addr; /* Preparsed remote address info */
apr_pool_t *scpool; /* Subpool used for socket and connection data */ apr_pool_t *scpool; /* Subpool used for socket and connection data */

View File

@@ -31,6 +31,11 @@
#define apr_socket_create apr_socket_create_ex #define apr_socket_create apr_socket_create_ex
#endif #endif
#if APR_HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#include "apr_support.h" /* for apr_wait_for_io_or_timeout() */
APLOG_USE_MODULE(proxy); APLOG_USE_MODULE(proxy);
/* /*
@@ -2008,6 +2013,7 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
(*conn)->worker = worker; (*conn)->worker = worker;
(*conn)->close = 0; (*conn)->close = 0;
(*conn)->inreslist = 0; (*conn)->inreslist = 0;
(*conn)->uds_path = NULL;
return OK; return OK;
} }
@@ -2024,6 +2030,30 @@ PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,
return OK; return OK;
} }
/*
* Decodes a '%' escaped string, and returns the number of characters
*/
static int decodeenc(char *x)
{
int i, j, ch;
if (x[0] == '\0') {
/* special case for no characters */
return 0;
}
for (i = 0, j = 0; x[i] != '\0'; i++, j++) {
/* decode it if not already done */
ch = x[i];
if (ch == '%' && apr_isxdigit(x[i + 1]) && apr_isxdigit(x[i + 2])) {
ch = ap_proxy_hex2c(&x[i + 1]);
i += 2;
}
x[j] = ch;
}
x[j] = '\0';
return j;
}
PROXY_DECLARE(int) PROXY_DECLARE(int)
ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
proxy_server_conf *conf, proxy_server_conf *conf,
@@ -2118,11 +2148,18 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
conn->port = uri->port; conn->port = uri->port;
} }
socket_cleanup(conn); socket_cleanup(conn);
if (strncmp(conn->hostname, "socket=", 7) == 0) {
char *uds_path = apr_pstrdup(conn->pool, conn->hostname + 7);
decodeenc(uds_path);
conn->uds_path = uds_path;
}
else {
err = apr_sockaddr_info_get(&(conn->addr), err = apr_sockaddr_info_get(&(conn->addr),
conn->hostname, APR_UNSPEC, conn->hostname, APR_UNSPEC,
conn->port, 0, conn->port, 0,
conn->pool); conn->pool);
} }
}
else if (!worker->cp->addr) { else if (!worker->cp->addr) {
if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock"); ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock");
@@ -2346,6 +2383,50 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
} }
/* 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;
}
PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
proxy_conn_rec *conn, proxy_conn_rec *conn,
proxy_worker *worker, proxy_worker *worker,
@@ -2370,13 +2451,46 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
proxy_function); proxy_function);
} }
} }
while (backend_addr && !connected) { while ((backend_addr || conn->uds_path) && !connected) {
if (conn->uds_path) {
struct sockaddr_un sa;
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()
"%s: error creating Unix domain socket for "
"target %s",
proxy_function,
worker->s->hostname);
break;
}
conn->connection = NULL;
sa.sun_family = AF_UNIX;
apr_cpystrn(sa.sun_path, conn->uds_path, sizeof(sa.sun_path));
rv = socket_connect_un(newsock, &sa);
if (rv != APR_SUCCESS) {
apr_socket_close(newsock);
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO()
"%s: attempt to connect to Unix domain socket "
"%s (%s) failed",
proxy_function,
conn->uds_path,
worker->s->hostname);
break;
}
}
else {
if ((rv = apr_socket_create(&newsock, backend_addr->family, if ((rv = apr_socket_create(&newsock, backend_addr->family,
SOCK_STREAM, APR_PROTO_TCP, SOCK_STREAM, APR_PROTO_TCP,
conn->scpool)) != APR_SUCCESS) { conn->scpool)) != APR_SUCCESS) {
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952) ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952)
"%s: error creating fam %d socket for target %s", "%s: error creating fam %d socket for "
"target %s",
proxy_function, proxy_function,
backend_addr->family, backend_addr->family,
worker->s->hostname); worker->s->hostname);
@@ -2458,6 +2572,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
backend_addr = backend_addr->next; backend_addr = backend_addr->next;
continue; continue;
} }
}
/* Set a timeout on the socket */ /* Set a timeout on the socket */
if (worker->s->timeout_set) { if (worker->s->timeout_set) {
@@ -2472,7 +2587,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
conn->sock = newsock; conn->sock = newsock;
if (conn->forward) { if (!conn->uds_path && conn->forward) {
forward_info *forward = (forward_info *)conn->forward; forward_info *forward = (forward_info *)conn->forward;
/* /*
* For HTTP CONNECT we need to prepend CONNECT request before * For HTTP CONNECT we need to prepend CONNECT request before