From 357828f9d22e2f430bdfe6fe728998c3e93241ab Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Fri, 23 Aug 2013 16:48:42 +0000 Subject: [PATCH] Allow for a simple socket check in addition to the higher level protocol-level checks for backends... Not sure if it makes sense to do both or not... Comments? git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1516930 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_proxy.xml | 4 ++- modules/proxy/mod_proxy.c | 2 +- modules/proxy/mod_proxy.h | 7 ++++++ modules/proxy/mod_proxy_ajp.c | 45 ++++++++++++++++++++++------------ modules/proxy/mod_proxy_http.c | 14 ++++++++++- modules/proxy/proxy_util.c | 6 ++--- 6 files changed, 56 insertions(+), 22 deletions(-) diff --git a/docs/manual/mod/mod_proxy.xml b/docs/manual/mod/mod_proxy.xml index aa77959658..5a1ab09db4 100644 --- a/docs/manual/mod/mod_proxy.xml +++ b/docs/manual/mod/mod_proxy.xml @@ -1003,7 +1003,9 @@ ProxyPass /mirror/foo http://backend.example.com ping 0 Ping property tells the webserver to "test" the connection to - the backend before forwarding the request. For AJP, it causes + the backend before forwarding the request. For negative values + the test is a simple socket check, for positive values it's + a more functional check, dependent upon the protocol. For AJP, it causes mod_proxy_ajpto send a CPING request on the ajp13 connection (implemented on Tomcat 3.3.2+, 4.1.28+ and 5.0.13+). For HTTP, it causes mod_proxy_http diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index a0a937f4fd..96f32304c0 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -233,7 +233,7 @@ static const char *set_worker_param(apr_pool_t *p, */ if (ap_timeout_parameter_parse(val, &timeout, "s") != APR_SUCCESS) return "Ping/Pong timeout has wrong format"; - if (timeout < 1000) + if (timeout < 1000 && timeout >= 0) return "Ping/Pong timeout must be at least one millisecond"; worker->s->ping_timeout = timeout; worker->s->ping_timeout_set = 1; diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 8ff4b85149..e36f3f734c 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -972,6 +972,13 @@ PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc, APR_DECLARE_OPTIONAL_FN(int, ap_proxy_clear_connection, (request_rec *r, apr_table_t *headers)); + +/** + * @param socket socket to test + * @return TRUE if socket is connected/active + */ +PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket); + #define PROXY_LBMETHOD "proxylbmethod" /* The number of dynamic workers that can be added when reconfiguring. diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index 46cda6ed10..e78fdb0b5f 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -759,22 +759,35 @@ static int proxy_ajp_handler(request_rec *r, proxy_worker *worker, /* Handle CPING/CPONG */ if (worker->s->ping_timeout_set) { - status = ajp_handle_cping_cpong(backend->sock, r, - worker->s->ping_timeout); - /* - * In case the CPING / CPONG failed for the first time we might be - * just out of luck and got a faulty backend connection, but the - * backend might be healthy nevertheless. So ensure that the backend - * TCP connection gets closed and try it once again. - */ - if (status != APR_SUCCESS) { - backend->close = 1; - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00897) - "cping/cpong failed to %pI (%s)", - worker->cp->addr, worker->s->hostname); - status = HTTP_SERVICE_UNAVAILABLE; - retry++; - continue; + if (worker->s->ping_timeout_set < 0) { + if (!ap_proxy_is_socket_connected(backend->sock)) { + backend->close = 1; + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO() + "socket check failed to %pI (%s)", + worker->cp->addr, worker->s->hostname); + status = HTTP_SERVICE_UNAVAILABLE; + retry++; + continue; + } + } + else { + status = ajp_handle_cping_cpong(backend->sock, r, + worker->s->ping_timeout); + /* + * In case the CPING / CPONG failed for the first time we might be + * just out of luck and got a faulty backend connection, but the + * backend might be healthy nevertheless. So ensure that the backend + * TCP connection gets closed and try it once again. + */ + if (status != APR_SUCCESS) { + backend->close = 1; + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00897) + "cping/cpong failed to %pI (%s)", + worker->cp->addr, worker->s->hostname); + status = HTTP_SERVICE_UNAVAILABLE; + retry++; + continue; + } } } /* Step Three: Process the Request */ diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 55dabba2af..892aa2f3b8 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -1975,13 +1975,25 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, } } + /* Step Three-and-a-Half: See if the socket is still connected (if desired) */ + if (worker->s->ping_timeout_set && worker->s->ping_timeout < 0 && + !ap_proxy_is_socket_connected(backend->sock)) { + backend->close = 1; + ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r, APLOGNO() + "socket check failed to %pI (%s)", + worker->cp->addr, worker->s->hostname); + retry++; + continue; + } + /* Step Four: Send the Request * On the off-chance that we forced a 100-Continue as a * kinda HTTP ping test, allow for retries */ if ((status = ap_proxy_http_request(p, r, backend, worker, conf, uri, locurl, server_portstr)) != OK) { - if ((status == HTTP_SERVICE_UNAVAILABLE) && worker->s->ping_timeout_set) { + if ((status == HTTP_SERVICE_UNAVAILABLE) && worker->s->ping_timeout_set && + worker->s->ping_timeout > 0) { backend->close = 1; ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r, APLOGNO(01115) "HTTP: 100-Continue failed to %pI (%s)", diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index b7c10709f1..1b62c5d97f 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -2245,7 +2245,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, #endif #if USE_ALTERNATE_IS_CONNECTED && defined(APR_MSG_PEEK) -static int is_socket_connected(apr_socket_t *socket) +PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket) { apr_pollfd_t pfds[1]; apr_status_t status; @@ -2283,7 +2283,7 @@ static int is_socket_connected(apr_socket_t *socket) } #else -static int is_socket_connected(apr_socket_t *sock) +PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket) { apr_size_t buffer_len = 1; @@ -2466,7 +2466,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); if (conn->sock) { - if (!(connected = is_socket_connected(conn->sock))) { + if (!(connected = ap_proxy_is_socket_connected(conn->sock))) { socket_cleanup(conn); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00951) "%s: backend socket is disconnected.", -- 2.50.0