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: [email protected]
For additional commands, e-mail: [email protected]