From a47569f7c178f01494b78af9df82c55642fb6b17 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Mon, 22 Apr 2013 19:48:25 +0000 Subject: [PATCH] core, mod_ssl: Lift the restriction that prevents mod_ssl taking full advantage of the event MPM. Enable the ability for a module to reverse the sense of a poll event from a read to a write or vice versa. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1470679 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 5 +++++ include/ap_mmn.h | 3 ++- include/httpd.h | 8 ++++++++ modules/ssl/ssl_engine_io.c | 18 ++++++++++++++++-- server/mpm/event/event.c | 19 ++++++++++++++----- server/mpm/eventopt/eventopt.c | 19 ++++++++++++++----- 6 files changed, 59 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index 290064da86..8acdf18699 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) core, mod_ssl: Lift the restriction that prevents mod_ssl taking + full advantage of the event MPM. Enable the ability for a module + to reverse the sense of a poll event from a read to a write or vice + versa. [Graham Leggett] + *) core: Add workaround for gcc bug on sparc/64bit. PR 52900. [Stefan Fritsch] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 2db39c108b..56203997d6 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -420,6 +420,7 @@ * ap_proxy_pass_brigade() * 20121222.7 (2.5.0-dev) Add ap_remove_input|output_filter_byhandle() * 20121222.8 (2.5.0-dev) Add dav_join_error() + * 20121222.9 (2.5.0-dev) Add conn_sense_e */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -427,7 +428,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20121222 #endif -#define MODULE_MAGIC_NUMBER_MINOR 8 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 9 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/httpd.h b/include/httpd.h index 6ab82b0d3b..2b8f08ab55 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1177,12 +1177,20 @@ typedef enum { CONN_STATE_LINGER_SHORT /* MPM has started lingering close with short timeout */ } conn_state_e; +typedef enum { + CONN_SENSE_DEFAULT, + CONN_SENSE_WANT_READ, /* next event must be read */ + CONN_SENSE_WANT_WRITE /* next event must be write */ +} conn_sense_e; + /** * @brief A structure to contain connection state information */ struct conn_state_t { /** Current state of the connection */ conn_state_e state; + /** Whether to read instead of write, or write instead of read */ + conn_sense_e sense; }; /* Per-vhost config... */ diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index a4e76ca31b..006c84d4f6 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -777,6 +777,18 @@ static apr_status_t ssl_filter_write(ap_filter_t *f, */ outctx->rc = APR_EAGAIN; } + else if (ssl_err == SSL_ERROR_WANT_READ) { + /* + * If OpenSSL wants to read during write, and we were + * nonblocking, set the sense explicitly to read and + * report as an EAGAIN. + * + * (This is usually the case when the client forces an SSL + * renegotiation which is handled implicitly by OpenSSL.) + */ + outctx->c->cs->sense = CONN_SENSE_WANT_READ; + outctx->rc = APR_EAGAIN; + } else if (ssl_err == SSL_ERROR_SYSCALL) { ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c, APLOGNO(01993) "SSL output filter write failed."); @@ -1927,8 +1939,10 @@ void ssl_io_filter_init(conn_rec *c, request_rec *r, SSL *ssl) filter_ctx->pbioWrite = BIO_new(&bio_filter_out_method); filter_ctx->pbioWrite->ptr = (void *)bio_filter_out_ctx_new(filter_ctx, c); - /* We insert a clogging input filter. Let the core know. */ - c->clogging_input_filters = 1; + /* write is non blocking for the benefit of async mpm */ + if (c->cs) { + BIO_set_nbio(filter_ctx->pbioWrite, 1); + } ssl_io_input_add_filter(filter_ctx, c, r, ssl); diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index 6526e8ae4d..8b57b735e5 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -810,7 +810,10 @@ static int start_lingering_close_common(event_conn_state_t *cs) apr_atomic_inc32(&lingering_count); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(*q, cs); - cs->pfd.reqevents = APR_POLLIN | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_WRITE ? APR_POLLOUT : + APR_POLLIN) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; rv = apr_pollset_add(event_pollset, &cs->pfd); apr_thread_mutex_unlock(timeout_mutex); if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) { @@ -958,6 +961,7 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc */ cs->pub.state = CONN_STATE_READ_REQUEST_LINE; + cs->pub.sense = CONN_SENSE_DEFAULT; } else { c = cs->c; @@ -966,9 +970,11 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc } if (c->clogging_input_filters && !c->aborted) { - /* Since we have an input filter which 'cloggs' the input stream, - * like mod_ssl, lets just do the normal read from input filters, - * like the Worker MPM does. + /* Since we have an input filter which 'clogs' the input stream, + * like mod_ssl used to, lets just do the normal read from input + * filters, like the Worker MPM does. Filters that need to write + * where they would otherwise read, or read where they would + * otherwise write, should set the sense appropriately. */ apr_atomic_inc32(&clogged_count); ap_run_process_connection(c); @@ -1014,7 +1020,10 @@ read_request: cs->expiration_time = ap_server_conf->timeout + apr_time_now(); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(write_completion_q, cs); - cs->pfd.reqevents = APR_POLLOUT | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN : + APR_POLLOUT) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; rc = apr_pollset_add(event_pollset, &cs->pfd); apr_thread_mutex_unlock(timeout_mutex); return; diff --git a/server/mpm/eventopt/eventopt.c b/server/mpm/eventopt/eventopt.c index cf42fd9121..180f15229b 100644 --- a/server/mpm/eventopt/eventopt.c +++ b/server/mpm/eventopt/eventopt.c @@ -875,7 +875,10 @@ static int start_lingering_close(event_conn_state_t *cs, ap_equeue_t *eq) cs->pub.state = CONN_STATE_LINGER_NORMAL; } apr_atomic_inc32(&lingering_count); - cs->pfd.reqevents = APR_POLLIN | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_WRITE ? APR_POLLOUT : + APR_POLLIN) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; v->cs = cs; if (eq != NULL) { ap_equeue_writer_onward(eq); @@ -1019,6 +1022,7 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc */ cs->pub.state = CONN_STATE_READ_REQUEST_LINE; + cs->pub.sense = CONN_SENSE_DEFAULT; } else { c = cs->c; @@ -1027,9 +1031,11 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc } if (c->clogging_input_filters && !c->aborted) { - /* Since we have an input filter which 'cloggs' the input stream, - * like mod_ssl, lets just do the normal read from input filters, - * like the Worker MPM does. + /* Since we have an input filter which 'clogs' the input stream, + * like mod_ssl used to, lets just do the normal read from input + * filters, like the Worker MPM does. Filters that need to write + * where they would otherwise read, or read where they would + * otherwise write, should set the sense appropriately. */ apr_atomic_inc32(&clogged_count); ap_run_process_connection(c); @@ -1075,7 +1081,10 @@ read_request: pollset_op_t *v = ap_equeue_writer_value(eq); cs->expiration_time = ap_server_conf->timeout + apr_time_now(); - cs->pfd.reqevents = APR_POLLOUT | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN : + APR_POLLOUT) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; v->cs = cs; v->timeout_type = TIMEOUT_WRITE_COMPLETION; -- 2.40.0