Author: mturk
Date: Thu Nov 15 07:59:36 2012
New Revision: 1409681

URL: http://svn.apache.org/viewvc?rev=1409681&view=rev
Log:
Clean up SSL network layer. Ensure the behavior is similar to standard APR layer

Modified:
    tomcat/native/branches/1.1.x/native/src/sslnetwork.c

Modified: tomcat/native/branches/1.1.x/native/src/sslnetwork.c
URL: 
http://svn.apache.org/viewvc/tomcat/native/branches/1.1.x/native/src/sslnetwork.c?rev=1409681&r1=1409680&r2=1409681&view=diff
==============================================================================
--- tomcat/native/branches/1.1.x/native/src/sslnetwork.c (original)
+++ tomcat/native/branches/1.1.x/native/src/sslnetwork.c Thu Nov 15 07:59:36 
2012
@@ -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,12 +319,15 @@ 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;
-            i = SSL_get_error(con->ssl, s);
+                return APR_ENOTSOCK;
+            rv = apr_get_netos_error();
+            i  = SSL_get_error(con->ssl, s);
             switch (i) {
                 case SSL_ERROR_NONE:
                     con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
@@ -328,23 +335,23 @@ 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;
-                        return os == APR_SUCCESS ? APR_EGENERAL : os;
-                    }
-                break;
+#if !defined(_WIN32)
+                      if (APR_STATUS_IS_EINTR(rv)) {
+                          /* Interrupted by signal */
+                          continue;
+                      }
+#endif
+                    /* Fall trough */
                 default:
                     /*
-                    * Anything else is a fatal error
-                    */
+                     * Anything else is a fatal error
+                     */
                     con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
                     return SSL_TO_APR_ERROR(i);
                 break;
@@ -385,50 +392,58 @@ 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;
 
+    *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);
     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;
-
-            i = SSL_get_error(con->ssl, s);
+                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 && (con->ssl->shutdown & 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 ((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 trough */
+                case SSL_ERROR_ZERO_RETURN:
+                    if (s == 0) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+                        return APR_EOF;
+                    }
+                    /* Fall trough */
                 default:
                     con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
-                    return os;
+                    return APR_EGENERAL;
                 break;
             }
         }
@@ -438,7 +453,7 @@ ssl_socket_recv(apr_socket_t *sock, char
             break;
         }
     }
-    return rv;
+    return APR_SUCCESS;
 }
 
 static apr_status_t APR_THREAD_FUNC
@@ -447,50 +462,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;
-
-            i = SSL_get_error(con->ssl, s);
+                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 && i == SSL_ERROR_WANT_WRITE) {
-                        *len = 0;
-                        return APR_SUCCESS;
-                    }
-                    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 (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 trough */
                 default:
                     con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
-                    return os;
+                    return rv;
                 break;
             }
         }
@@ -499,7 +530,7 @@ ssl_socket_send(apr_socket_t *sock, cons
             break;
         }
     }
-    return rv;
+    return APR_SUCCESS;
 }
 
 static apr_status_t APR_THREAD_FUNC
@@ -584,6 +615,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);
@@ -613,14 +646,15 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, rene
     }
     con->ssl->state = 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