Reinstate r1897458 accidentally reverted in r1897760.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1897861 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Graham Leggett
2022-02-08 11:22:14 +00:00
parent fd79f533bf
commit 17f35eb66d
2 changed files with 85 additions and 43 deletions

View File

@ -0,0 +1,5 @@
*) ab: Respond appropriately to SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE.
Previously the correct event was polled for, but the response to the poll
would call write instead of read, and read instead of write. PR 55952
[Graham Leggett]

View File

@ -237,7 +237,11 @@ typedef enum {
* know if it worked yet * know if it worked yet
*/ */
STATE_CONNECTED, /* we know TCP connect completed */ STATE_CONNECTED, /* we know TCP connect completed */
STATE_READ #ifdef USE_SSL
STATE_HANDSHAKE, /* in the handshake phase */
#endif
STATE_WRITE, /* in the write phase */
STATE_READ /* in the read phase */
} connect_state_e; } connect_state_e;
#define CBUFFSIZE (8192) #define CBUFFSIZE (8192)
@ -520,21 +524,13 @@ static void set_polled_events(struct connection *c, apr_int16_t new_reqevents)
} }
} }
static void set_conn_state(struct connection *c, connect_state_e new_state) static void set_conn_state(struct connection *c, connect_state_e new_state,
apr_int16_t events)
{ {
apr_int16_t events_by_state[] = {
0, /* for STATE_UNCONNECTED */
APR_POLLOUT, /* for STATE_CONNECTING */
APR_POLLIN, /* for STATE_CONNECTED; we don't poll in this state,
* so prepare for polling in the following state --
* STATE_READ
*/
APR_POLLIN /* for STATE_READ */
};
c->state = new_state; c->state = new_state;
set_polled_events(c, events_by_state[new_state]); set_polled_events(c, events);
} }
/* --------------------------------------------------------- */ /* --------------------------------------------------------- */
@ -707,7 +703,7 @@ static void ssl_print_info(struct connection *c)
} }
ssl_print_connection_info(bio_err,c->ssl); ssl_print_connection_info(bio_err,c->ssl);
SSL_SESSION_print(bio_err, SSL_get_session(c->ssl)); SSL_SESSION_print(bio_err, SSL_get_session(c->ssl));
} }
static void ssl_proceed_handshake(struct connection *c) static void ssl_proceed_handshake(struct connection *c)
{ {
@ -783,14 +779,19 @@ static void ssl_proceed_handshake(struct connection *c)
} }
#endif #endif
write_request(c); write_request(c);
do_next = 0; do_next = 0;
break; break;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
set_polled_events(c, APR_POLLIN);
set_conn_state(c, STATE_HANDSHAKE, APR_POLLIN);
do_next = 0; do_next = 0;
break; break;
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
set_polled_events(c, APR_POLLOUT);
set_conn_state(c, STATE_HANDSHAKE, APR_POLLOUT);
do_next = 0; do_next = 0;
break; break;
case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_CONNECT:
@ -810,9 +811,6 @@ static void ssl_proceed_handshake(struct connection *c)
static void write_request(struct connection * c) static void write_request(struct connection * c)
{ {
if (started >= requests) {
return;
}
do { do {
apr_time_t tnow; apr_time_t tnow;
@ -845,10 +843,14 @@ static void write_request(struct connection * c)
if (e <= 0) { if (e <= 0) {
switch (SSL_get_error(c->ssl, e)) { switch (SSL_get_error(c->ssl, e)) {
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
set_polled_events(c, APR_POLLIN);
set_conn_state(c, STATE_WRITE, APR_POLLIN);
break; break;
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
set_polled_events(c, APR_POLLOUT);
set_conn_state(c, STATE_WRITE, APR_POLLOUT);
break; break;
default: default:
BIO_printf(bio_err, "SSL write failed - closing connection\n"); BIO_printf(bio_err, "SSL write failed - closing connection\n");
@ -871,7 +873,7 @@ static void write_request(struct connection * c)
close_connection(c); close_connection(c);
} }
else { else {
set_polled_events(c, APR_POLLOUT); set_conn_state(c, STATE_WRITE, APR_POLLOUT);
} }
return; return;
} }
@ -883,7 +885,8 @@ static void write_request(struct connection * c)
c->endwrite = lasttime = apr_time_now(); c->endwrite = lasttime = apr_time_now();
started++; started++;
set_conn_state(c, STATE_READ);
set_conn_state(c, STATE_READ, APR_POLLIN);
} }
/* --------------------------------------------------------- */ /* --------------------------------------------------------- */
@ -1355,8 +1358,9 @@ static void start_connect(struct connection * c)
{ {
apr_status_t rv; apr_status_t rv;
if (!(started < requests)) if (!(started < requests)) {
return; return;
}
c->read = 0; c->read = 0;
c->bread = 0; c->bread = 0;
@ -1439,12 +1443,12 @@ static void start_connect(struct connection * c)
#endif #endif
if ((rv = apr_socket_connect(c->aprsock, destsa)) != APR_SUCCESS) { if ((rv = apr_socket_connect(c->aprsock, destsa)) != APR_SUCCESS) {
if (APR_STATUS_IS_EINPROGRESS(rv)) { if (APR_STATUS_IS_EINPROGRESS(rv)) {
set_conn_state(c, STATE_CONNECTING); set_conn_state(c, STATE_CONNECTING, APR_POLLOUT);
c->rwrite = 0; c->rwrite = 0;
return; return;
} }
else { else {
set_conn_state(c, STATE_UNCONNECTED); set_conn_state(c, STATE_UNCONNECTED, 0);
apr_socket_close(c->aprsock); apr_socket_close(c->aprsock);
if (good == 0 && destsa->next) { if (good == 0 && destsa->next) {
destsa = destsa->next; destsa = destsa->next;
@ -1465,7 +1469,6 @@ static void start_connect(struct connection * c)
} }
/* connected first time */ /* connected first time */
set_conn_state(c, STATE_CONNECTED);
#ifdef USE_SSL #ifdef USE_SSL
if (c->ssl) { if (c->ssl) {
ssl_proceed_handshake(c); ssl_proceed_handshake(c);
@ -1513,7 +1516,7 @@ static void close_connection(struct connection * c)
} }
} }
set_conn_state(c, STATE_UNCONNECTED); set_conn_state(c, STATE_UNCONNECTED, 0);
#ifdef USE_SSL #ifdef USE_SSL
if (c->ssl) { if (c->ssl) {
SSL_shutdown(c->ssl); SSL_shutdown(c->ssl);
@ -1571,10 +1574,14 @@ read_more:
return; return;
} }
else if (scode == SSL_ERROR_WANT_READ) { else if (scode == SSL_ERROR_WANT_READ) {
set_polled_events(c, APR_POLLIN);
set_conn_state(c, STATE_READ, APR_POLLIN);
} }
else if (scode == SSL_ERROR_WANT_WRITE) { else if (scode == SSL_ERROR_WANT_WRITE) {
set_polled_events(c, APR_POLLOUT);
set_conn_state(c, STATE_READ, APR_POLLOUT);
} }
else { else {
/* some fatal error: */ /* some fatal error: */
@ -1668,7 +1675,7 @@ read_more:
} }
else { else {
/* header is in invalid or too big - close connection */ /* header is in invalid or too big - close connection */
set_conn_state(c, STATE_UNCONNECTED); set_conn_state(c, STATE_UNCONNECTED, 0);
apr_socket_close(c->aprsock); apr_socket_close(c->aprsock);
err_response++; err_response++;
if (bad++ > 10) { if (bad++ > 10) {
@ -1758,7 +1765,13 @@ read_more:
goto read_more; goto read_more;
} }
if (c->keepalive && (c->bread >= c->length)) { /* are we done? */
if (started >= requests && (c->bread >= c->length)) {
close_connection(c);
}
/* are we keepalive? if so, reuse existing connection */
else if (c->keepalive && (c->bread >= c->length)) {
/* finished a keep-alive connection */ /* finished a keep-alive connection */
good++; good++;
/* save out time */ /* save out time */
@ -1790,7 +1803,7 @@ read_more:
c->read = c->bread = 0; c->read = c->bread = 0;
/* zero connect time with keep-alive */ /* zero connect time with keep-alive */
c->start = c->connect = lasttime = apr_time_now(); c->start = c->connect = lasttime = apr_time_now();
set_conn_state(c, STATE_CONNECTED);
write_request(c); write_request(c);
} }
} }
@ -1980,6 +1993,7 @@ static void test(void)
do { do {
status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults); status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults);
} while (APR_STATUS_IS_EINTR(status)); } while (APR_STATUS_IS_EINTR(status));
if (status != APR_SUCCESS) if (status != APR_SUCCESS)
apr_err("apr_pollset_poll", status); apr_err("apr_pollset_poll", status);
@ -2015,8 +2029,23 @@ static void test(void)
* connection is done and we loop here endlessly calling * connection is done and we loop here endlessly calling
* apr_poll(). * apr_poll().
*/ */
if ((rtnev & APR_POLLIN) || (rtnev & APR_POLLPRI) || (rtnev & APR_POLLHUP)) if ((rtnev & APR_POLLIN) || (rtnev & APR_POLLPRI) || (rtnev & APR_POLLHUP)) {
switch (c->state) {
#ifdef USE_SSL
case STATE_HANDSHAKE:
ssl_proceed_handshake(c);
break;
#endif
case STATE_WRITE:
write_request(c);
break;
case STATE_READ:
read_connection(c); read_connection(c);
break;
}
}
if ((rtnev & APR_POLLERR) || (rtnev & APR_POLLNVAL)) { if ((rtnev & APR_POLLERR) || (rtnev & APR_POLLNVAL)) {
if (destsa->next && c->state == STATE_CONNECTING && good == 0) { if (destsa->next && c->state == STATE_CONNECTING && good == 0) {
destsa = destsa->next; destsa = destsa->next;
@ -2040,7 +2069,7 @@ static void test(void)
/* call connect() again to detect errors */ /* call connect() again to detect errors */
rv = apr_socket_connect(c->aprsock, destsa); rv = apr_socket_connect(c->aprsock, destsa);
if (rv != APR_SUCCESS) { if (rv != APR_SUCCESS) {
set_conn_state(c, STATE_UNCONNECTED); set_conn_state(c, STATE_UNCONNECTED, 0);
apr_socket_close(c->aprsock); apr_socket_close(c->aprsock);
err_conn++; err_conn++;
if (bad++ > 10) { if (bad++ > 10) {
@ -2052,7 +2081,7 @@ static void test(void)
continue; continue;
} }
else { else {
set_conn_state(c, STATE_CONNECTED);
#ifdef USE_SSL #ifdef USE_SSL
if (c->ssl) if (c->ssl)
ssl_proceed_handshake(c); ssl_proceed_handshake(c);
@ -2060,16 +2089,24 @@ static void test(void)
#endif #endif
write_request(c); write_request(c);
} }
} }
else { else {
/* POLLOUT is one shot */
set_polled_events(c, APR_POLLIN); switch (c->state) {
if (c->state == STATE_READ) { #ifdef USE_SSL
read_connection(c); case STATE_HANDSHAKE:
} ssl_proceed_handshake(c);
else { break;
#endif
case STATE_WRITE:
write_request(c); write_request(c);
break;
case STATE_READ:
read_connection(c);
break;
} }
} }
} }
} }