Author: markt
Date: Tue Nov  3 23:21:20 2015
New Revision: 1712437

URL: http://svn.apache.org/viewvc?rev=1712437&view=rev
Log:
Forward port of r1409681 (mturk) from 1.1.x
Clean up SSL network layer. Ensure the behavior is similar to standard APR layer

Modified:
    tomcat/native/trunk/native/src/sslnetwork.c

Modified: tomcat/native/trunk/native/src/sslnetwork.c
URL: 
http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslnetwork.c?rev=1712437&r1=1712436&r2=1712437&view=diff
==============================================================================
--- tomcat/native/trunk/native/src/sslnetwork.c (original)
+++ tomcat/native/trunk/native/src/sslnetwork.c Tue Nov  3 23:21:20 2015
@@ -169,9 +169,9 @@ static tcn_ssl_conn_t *ssl_create(JNIEnv
 #endif
 
 static apr_status_t wait_for_io_or_timeout(tcn_ssl_conn_t *con,
-                                           int for_what)
+                                           int for_what,
+                                           apr_interval_time_t timeout)
 {
-    apr_interval_time_t timeout;
     apr_pollfd_t pfd;
     int type;
     apr_status_t status;
@@ -206,8 +206,11 @@ static apr_status_t wait_for_io_or_timeo
             return APR_EINVAL;
         break;
     }
-
-    apr_socket_timeout_get(con->sock, &timeout);
+    if (timeout <= 0) {
+        /* Waiting on zero or infinite timeouts is not allowed
+         */
+        return APR_EAGAIN;
+    }
     pfd.desc_type = APR_POLL_SOCKET;
     pfd.desc.s    = con->sock;
     pfd.reqevents = type;
@@ -305,6 +308,7 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, hand
 {
     tcn_socket_t *ss = J2P(sock, tcn_socket_t *);
     tcn_ssl_conn_t *con;
+    apr_interval_time_t timeout;
     int s, i;
     long vr;
     apr_status_t rv;
@@ -315,11 +319,14 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, hand
     if (ss->net->type != TCN_SOCKET_SSL)
         return APR_EINVAL;
     con = (tcn_ssl_conn_t *)ss->opaque;
+
+    apr_socket_timeout_get(con->sock, &timeout);
     while (!SSL_is_init_finished(con->ssl)) {
+        ERR_clear_error();
         if ((s = SSL_do_handshake(con->ssl)) <= 0) {
-            apr_status_t os = apr_get_netos_error();
             if (!con->ssl)
-                return os == APR_SUCCESS ? APR_ENOTSOCK : os;
+                return APR_ENOTSOCK;
+            rv = apr_get_netos_error();
             i = SSL_get_error(con->ssl, s);
             switch (i) {
                 case SSL_ERROR_NONE:
@@ -328,20 +335,19 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, hand
                 break;
                 case SSL_ERROR_WANT_READ:
                 case SSL_ERROR_WANT_WRITE:
-                    if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) {
+                    if ((rv = wait_for_io_or_timeout(con, i, timeout)) != 
APR_SUCCESS) {
                         con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
                         return rv;
                     }
                 break;
                 case SSL_ERROR_SYSCALL:
-                case SSL_ERROR_SSL:
-                    if (!APR_STATUS_IS_EAGAIN(os) &&
-                        !APR_STATUS_IS_EINTR(os)) {
-                        con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
-                        ERR_print_errors(con->ctx->bio_os);
-                        return os == APR_SUCCESS ? APR_EGENERAL : os;
+#if !defined(_WIN32)
+                    if (APR_STATUS_IS_EINTR(rv)) {
+                        /* Interrupted by signal */
+                        continue;
                     }
-                break;
+#endif
+                    /* Fall through */
                 default:
                     /*
                     * Anything else is a fatal error
@@ -388,34 +394,31 @@ static apr_status_t APR_THREAD_FUNC
 ssl_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
 {
     tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
-    int s, i, wr = (int)(*len);
-    apr_status_t rv = APR_SUCCESS;
+    int s, i, rd = (int)(*len);
+    apr_status_t rv;
+    apr_interval_time_t timeout;
     apr_int32_t nb;
 
+    *len = 0;
     if (con->reneg_state == RENEG_ABORT) {
-        *len = 0;
         con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
         return APR_ECONNABORTED;
     }
+    apr_socket_timeout_get(con->sock, &timeout);
     apr_socket_opt_get(con->sock, APR_SO_NONBLOCK, &nb);
     for (;;) {
-        if ((s = SSL_read(con->ssl, buf, wr)) <= 0) {
-            apr_status_t os = apr_get_netos_error();
+        ERR_clear_error();
+        if ((s = SSL_read(con->ssl, buf, rd)) <= 0) {
             if (!con->ssl)
-                return os == APR_SUCCESS ? APR_ENOTSOCK : os;
-
+                return APR_ENOTSOCK;
+            rv = apr_get_netos_error();
             i = SSL_get_error(con->ssl, s);
             /* Special case if the "close notify" alert send by peer */
             if (s == 0 && (SSL_get_shutdown(con->ssl) & 
SSL_RECEIVED_SHUTDOWN)) {
-                *len = 0;
+                con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
                 return APR_EOF;
             }
             switch (i) {
-                case SSL_ERROR_ZERO_RETURN:
-                    *len = 0;
-                    con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
-                    return APR_EOF;
-                break;
                 case SSL_ERROR_WANT_READ:
                 case SSL_ERROR_WANT_WRITE:
                     if (nb) {
@@ -427,22 +430,33 @@ ssl_socket_recv(apr_socket_t *sock, char
                             return rv;
                         }
                     }
-                    if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) {
+                    if ((rv = wait_for_io_or_timeout(con, i, timeout)) != 
APR_SUCCESS) {
                         con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
                         return rv;
                     }
                 break;
                 case SSL_ERROR_SYSCALL:
-                case SSL_ERROR_SSL:
-                    if (!APR_STATUS_IS_EAGAIN(os) &&
-                        !APR_STATUS_IS_EINTR(os)) {
-                        con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
-                        return os == APR_SUCCESS ? APR_EGENERAL : os;
+                    if (APR_STATUS_IS_EPIPE(rv) || 
APR_STATUS_IS_ECONNRESET(rv)) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+                        return APR_EOF;
                     }
-                break;
+#if !defined(_WIN32)
+                    else if (APR_STATUS_IS_EINTR(rv)) {
+                        /* Interrupted by signal
+                         */
+                        continue;
+                    }
+#endif
+                    /* Fall through */
+                case SSL_ERROR_ZERO_RETURN:
+                    if (s == 0) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+                        return APR_EOF;
+                    }
+                    /* Fall through */
                 default:
                     con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
-                    return os;
+                    return APR_EGENERAL;
                 break;
             }
         }
@@ -452,7 +466,7 @@ ssl_socket_recv(apr_socket_t *sock, char
             break;
         }
     }
-    return rv;
+    return APR_SUCCESS;
 }
 
 static apr_status_t APR_THREAD_FUNC
@@ -461,56 +475,66 @@ ssl_socket_send(apr_socket_t *sock, cons
 {
     tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
     int s, i, wr = (int)(*len);
-    apr_status_t rv = APR_SUCCESS;
-    apr_int32_t nb;
+    apr_status_t rv;
+    apr_interval_time_t timeout;
 
+    *len = 0;
     if (con->reneg_state == RENEG_ABORT) {
-        *len = 0;
         con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
         return APR_ECONNABORTED;
     }
-    apr_socket_opt_get(con->sock, APR_SO_NONBLOCK, &nb);
+    if (!SSL_is_init_finished(con->ssl)) {
+        /* XXX: Is this a correct retval ? */
+        return APR_EINPROGRESS;
+    }
+    if (wr == 0) {
+        /* According to docs calling SSL_write() with num=0 bytes
+         * to be sent the behaviour is undefined.
+         */
+        return APR_EINVAL;
+    }
+    apr_socket_timeout_get(con->sock, &timeout);
     for (;;) {
+        ERR_clear_error();
         if ((s = SSL_write(con->ssl, buf, wr)) <= 0) {
-            apr_status_t os = apr_get_netos_error();
             if (!con->ssl)
-                return os == APR_SUCCESS ? APR_ENOTSOCK : os;
-
+                return APR_ENOTSOCK;
+            rv  = apr_get_netos_error();
             i = SSL_get_error(con->ssl, s);
             switch (i) {
-                case SSL_ERROR_ZERO_RETURN:
-                    *len = 0;
-                    con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
-                    return APR_EOF;
-                break;
                 case SSL_ERROR_WANT_READ:
                 case SSL_ERROR_WANT_WRITE:
-                    if (nb) {
-                        if (i == SSL_ERROR_WANT_WRITE) {
-                            *len = 0;
-                            return APR_SUCCESS;
-                        } else {
-                            con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
-                            return rv;
-                        }
-                    }
-                    if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) {
+                    if ((rv = wait_for_io_or_timeout(con, i, timeout)) != 
APR_SUCCESS) {
                         con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
                         return rv;
                     }
                 break;
                 case SSL_ERROR_SYSCALL:
-                case SSL_ERROR_SSL:
-                    if (!APR_STATUS_IS_EAGAIN(os) &&
-                        !APR_STATUS_IS_EINTR(os)) {
-                        // EINTR/EAGAIN are returned to the caller
-                        con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
-                        return os == APR_SUCCESS ? APR_EGENERAL : os;
+                    if (s == -1) {
+                        if (APR_STATUS_IS_EPIPE(rv) || 
APR_STATUS_IS_ECONNRESET(rv)) {
+                            con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+                            return APR_EOF;
+                        }
+#if !defined(_WIN32)
+                        else if (APR_STATUS_IS_EINTR(rv)) {
+                            /* Interrupted by signal
+                             */
+                            continue;
+                        }
+#endif
                     }
+                    con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                    return rv;
                 break;
+                case SSL_ERROR_ZERO_RETURN:
+                    if (s == 0) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+                        return APR_EOF;
+                    }
+                    /* Fall through */
                 default:
                     con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
-                    return os;
+                    return rv;
                 break;
             }
         }
@@ -519,7 +543,7 @@ ssl_socket_send(apr_socket_t *sock, cons
             break;
         }
     }
-    return rv;
+    return APR_SUCCESS;
 }
 
 static apr_status_t APR_THREAD_FUNC
@@ -604,6 +628,8 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, rene
     tcn_ssl_conn_t *con;
     int retVal;
     int ecode = SSL_ERROR_WANT_READ;
+    apr_status_t rv;
+    apr_interval_time_t timeout;
 
     UNREFERENCED_STDARGS;
     TCN_ASSERT(sock != 0);
@@ -636,14 +662,15 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, rene
     }
     SSL_set_state(con->ssl, SSL_ST_ACCEPT);
 
+    apr_socket_timeout_get(con->sock, &timeout);
     ecode = SSL_ERROR_WANT_READ;
     while (ecode == SSL_ERROR_WANT_READ) {
         retVal = SSL_do_handshake(con->ssl);
         if (retVal <= 0) {
             ecode = SSL_get_error(con->ssl, retVal);
             if (ecode == SSL_ERROR_WANT_READ) {
-                if (wait_for_io_or_timeout(con, ecode) != APR_SUCCESS)
-                    return APR_EGENERAL; /* Can't wait */
+                if ((rv = wait_for_io_or_timeout(con, ecode, timeout)) != 
APR_SUCCESS)
+                    return rv; /* Can't wait */
                 continue; /* It should be ok now */
             }
             else



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to