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