]> granicus.if.org Git - apache/commitdiff
On the 2.4.x branch:
authorStefan Eissing <icing@apache.org>
Tue, 7 Nov 2017 09:01:59 +0000 (09:01 +0000)
committerStefan Eissing <icing@apache.org>
Tue, 7 Nov 2017 09:01:59 +0000 (09:01 +0000)
Merged /httpd/httpd/trunk:r1811649,1811664,1814118

  *) ab: Make the TLS layer aware that the underlying socket is nonblocking,
     and use/handle POLLOUT where needed to avoid busy IOs and recover write
     errors when appropriate.  [Yann Ylavic]

  *) ab: Keep reading nonblocking to exhaust TCP or SSL buffers when previous
     read was incomplete (the SSL case can cause the next poll() to timeout
     since data are buffered already).  PR 61301 [Luca Toscano, Yann Ylavic]

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1814468 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
support/ab.c

diff --git a/CHANGES b/CHANGES
index 0449324bca661bfa52253b4895596c473e7a99a5..f65f33c29854377050298771d29356be3bf1cf8f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,14 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.4.30
 
+  *) ab: Make the TLS layer aware that the underlying socket is nonblocking,
+     and use/handle POLLOUT where needed to avoid busy IOs and recover write
+     errors when appropriate.  [Yann Ylavic]
+
+  *) ab: Keep reading nonblocking to exhaust TCP or SSL buffers when previous
+     read was incomplete (the SSL case can cause the next poll() to timeout
+     since data are buffered already).  PR 61301 [Luca Toscano, Yann Ylavic]
+
   *) mod_http2: avoid unnecessary data retrieval for a trace log. Allow certain
      information retrievals on null bucket beams where it makes sense. [Stefan Eissing]
 
diff --git a/STATUS b/STATUS
index ab6e1ede322a7e8be623996e63a256fcdf223864..a09027f76b80e62f2f2cc76a36ab16f7b493580a 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -118,13 +118,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-  *) ab: Keep reading nonblocking to exhaust TCP or SSL buffers when previous
-     read was incomplete.  PR 61301
-     trunk patch: https://svn.apache.org/r1811649
-     2.4.x patch: trunk works modulo CHANGES
-                  svn merge -c 1811649 ^/httpd/httpd/trunk .
-     +1: elukey, icing, ylavic
-
   *) core, mod_rewrite: introduce the 'keeps-redirect-vary' note in the internal redirect
                         workflow to keep the Vary headers set by RewriteCond/Rule
                         directives combinations in the directory context. PR: 58231
@@ -132,15 +125,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
      2.4.x: svn merge -c 1811744 ^/httpd/httpd/trunk .
      +1: elukey, icing, ylavic
 
-  *) ab: Make the TLS layer aware that the underlying socket is nonblocking,
-     and use/handle POLLOUT where needed to avoid busy IOs and recover write
-     errors when appropriate.
-     trunk patch: http://svn.apache.org/r1811664
-                  http://svn.apache.org/r1814118
-     2.4.x patch: trunk works (modulo CHANGES)
-                  svn merge -c 1811664,1814118 ^/httpd/httpd/trunk .
-     +1: ylavic, jim, icing
-
 
 PATCHES PROPOSED TO BACKPORT FROM TRUNK:
   [ New proposals should be added at the end of the list ]
index 0d0cf1125fcd8af44ff314f9b0e469f02f2325d7..39dc407bda59273800aee6a808b2c69fb88fd944 100644 (file)
@@ -739,8 +739,8 @@ static void ssl_proceed_handshake(struct connection *c)
             do_next = 0;
             break;
         case SSL_ERROR_WANT_WRITE:
-            /* Try again */
-            do_next = 1;
+            set_polled_events(c, APR_POLLOUT);
+            do_next = 0;
             break;
         case SSL_ERROR_WANT_CONNECT:
         case SSL_ERROR_SSL:
@@ -789,26 +789,40 @@ static void write_request(struct connection * c)
 
 #ifdef USE_SSL
         if (c->ssl) {
-            apr_size_t e_ssl;
-            e_ssl = SSL_write(c->ssl,request + c->rwrote, l);
-            if (e_ssl != l) {
-                BIO_printf(bio_err, "SSL write failed - closing connection\n");
-                ERR_print_errors(bio_err);
-                close_connection (c);
+            e = SSL_write(c->ssl, request + c->rwrote, l);
+            if (e <= 0) {
+                switch (SSL_get_error(c->ssl, e)) {
+                case SSL_ERROR_WANT_READ:
+                    set_polled_events(c, APR_POLLIN);
+                    break;
+                case SSL_ERROR_WANT_WRITE:
+                    set_polled_events(c, APR_POLLOUT);
+                    break;
+                default:
+                    BIO_printf(bio_err, "SSL write failed - closing connection\n");
+                    ERR_print_errors(bio_err);
+                    close_connection (c);
+                    break;
+                }
                 return;
             }
-            l = e_ssl;
-            e = APR_SUCCESS;
+            l = e;
         }
         else
 #endif
+        {
             e = apr_socket_send(c->aprsock, request + c->rwrote, &l);
-
-        if (e != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(e)) {
-            epipe++;
-            printf("Send request failed!\n");
-            close_connection(c);
-            return;
+            if (e != APR_SUCCESS && !l) {
+                if (!APR_STATUS_IS_EAGAIN(e)) {
+                    epipe++;
+                    printf("Send request failed!\n");
+                    close_connection(c);
+                }
+                else {
+                    set_polled_events(c, APR_POLLOUT);
+                }
+                return;
+            }
         }
         totalposted += l;
         c->rwrote += l;
@@ -1346,6 +1360,7 @@ static void start_connect(struct connection * c)
         ssl_rand_seed();
         apr_os_sock_get(&fd, c->aprsock);
         bio = BIO_new_socket(fd, BIO_NOCLOSE);
+        BIO_set_nbio(bio, 1);
         SSL_set_bio(c->ssl, bio, bio);
         SSL_set_connect_state(c->ssl);
         if (verbosity >= 4) {
@@ -1458,6 +1473,7 @@ static void read_connection(struct connection * c)
     char respcode[4];       /* 3 digits and null */
 
     r = sizeof(buffer);
+read_more:
 #ifdef USE_SSL
     if (c->ssl) {
         status = SSL_read(c->ssl, buffer, r);
@@ -1479,8 +1495,13 @@ static void read_connection(struct connection * c)
                 good++;
                 close_connection(c);
             }
-            else if (scode != SSL_ERROR_WANT_WRITE
-                     && scode != SSL_ERROR_WANT_READ) {
+            else if (scode == SSL_ERROR_WANT_READ) {
+                set_polled_events(c, APR_POLLIN);
+            }
+            else if (scode == SSL_ERROR_WANT_WRITE) {
+                set_polled_events(c, APR_POLLOUT);
+            }
+            else {
                 /* some fatal error: */
                 c->read = 0;
                 BIO_printf(bio_err, "SSL read failed (%d) - closing connection\n", scode);
@@ -1642,6 +1663,10 @@ static void read_connection(struct connection * c)
         c->bread += r;
         totalbread += r;
     }
+    if (r == sizeof(buffer) && c->bread < c->length) {
+        /* read was full, try more immediately (nonblocking already) */
+        goto read_more;
+    }
 
     if (c->keepalive && (c->bread >= c->length)) {
         /* finished a keep-alive connection */
@@ -1675,6 +1700,7 @@ static void read_connection(struct connection * c)
         c->read = c->bread = 0;
         /* zero connect time with keep-alive */
         c->start = c->connect = lasttime = apr_time_now();
+        set_conn_state(c, STATE_CONNECTED);
         write_request(c);
     }
 }
@@ -1916,6 +1942,7 @@ static void test(void)
             }
             if (rtnev & APR_POLLOUT) {
                 if (c->state == STATE_CONNECTING) {
+                    /* call connect() again to detect errors */
                     rv = apr_socket_connect(c->aprsock, destsa);
                     if (rv != APR_SUCCESS) {
                         set_conn_state(c, STATE_UNCONNECTED);
@@ -1940,7 +1967,14 @@ static void test(void)
                     }
                 }
                 else {
-                    write_request(c);
+                    /* POLLOUT is one shot */
+                    set_polled_events(c, APR_POLLIN);
+                    if (c->state == STATE_READ) {
+                        read_connection(c);
+                    }
+                    else {
+                        write_request(c);
+                    }
                 }
             }
         }