diff options
author | Gustavo André dos Santos Lopes <cataphract@php.net> | 2010-12-23 01:44:54 +0000 |
---|---|---|
committer | Gustavo André dos Santos Lopes <cataphract@php.net> | 2010-12-23 01:44:54 +0000 |
commit | cd34d68cddda0ab3e5d8b6ca3a641545dcff6bc6 (patch) | |
tree | ca6a3aa1d1dc05ae4e2a47b5b1ad1f3d3c6027ee | |
parent | a68864969e459013e8e9c83b8604277cf9d59b89 (diff) | |
download | php-git-cd34d68cddda0ab3e5d8b6ca3a641545dcff6bc6.tar.gz |
- Fixed bug #53592 (stream_socket_enable_crypto() busy-waits in client mode).
- Fixed stream_socket_enable_crypto() not honoring the socket timeout in
server mode.
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | ext/openssl/xp_ssl.c | 72 |
2 files changed, 58 insertions, 18 deletions
@@ -49,6 +49,10 @@ . Implemented FR #53447 (Cannot disable SessionTicket extension for servers that do not support it) by adding a no_ticket SSL context option. (Adam, Tony) + . Fixed bug #53592 (stream_socket_enable_crypto() busy-waits in client mode). + (Gustavo) + . Fixed stream_socket_enable_crypto() not honoring the socket timeout in + server mode. (Gustavo) - PDO Oracle driver: . Fixed bug #39199 (Cannot load Lob data with more than 4000 bytes on diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index d827c519f9..83e9c9a5ea 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -411,8 +411,10 @@ static inline int php_openssl_enable_crypto(php_stream *stream, int n, retry = 1; if (cparam->inputs.activate && !sslsock->ssl_active) { - float timeout = sslsock->connect_timeout.tv_sec + sslsock->connect_timeout.tv_usec / 1000000; - int blocked = sslsock->s.is_blocked; + struct timeval start_time, + *timeout; + int blocked = sslsock->s.is_blocked, + has_timeout = 0; #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) if (sslsock->is_client && sslsock->sni) { @@ -429,36 +431,70 @@ static inline int php_openssl_enable_crypto(php_stream *stream, sslsock->state_set = 1; } - if (sslsock->is_client && SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0 TSRMLS_CC)) { - sslsock->s.is_blocked = 0; + if (SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0 TSRMLS_CC)) { + sslsock->s.is_blocked = 0; } + + timeout = sslsock->is_client ? &sslsock->connect_timeout : &sslsock->s.timeout; + has_timeout = !sslsock->s.is_blocked && (timeout->tv_sec || timeout->tv_usec); + /* gettimeofday is not monotonic; using it here is not strictly correct */ + if (has_timeout) { + gettimeofday(&start_time, NULL); + } + do { + struct timeval cur_time, + elapsed_time; + if (sslsock->is_client) { - struct timeval tvs, tve; - struct timezone tz; - - gettimeofday(&tvs, &tz); n = SSL_connect(sslsock->ssl_handle); - gettimeofday(&tve, &tz); + } else { + n = SSL_accept(sslsock->ssl_handle); + } - timeout -= (tve.tv_sec + (float) tve.tv_usec / 1000000) - (tvs.tv_sec + (float) tvs.tv_usec / 1000000); - if (timeout < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL: connection timeout"); + if (has_timeout) { + gettimeofday(&cur_time, NULL); + elapsed_time.tv_sec = cur_time.tv_sec - start_time.tv_sec; + elapsed_time.tv_usec = cur_time.tv_usec - start_time.tv_usec; + if (cur_time.tv_usec < start_time.tv_usec) { + elapsed_time.tv_sec -= 1L; + elapsed_time.tv_usec += 1000000L; + } + + if (elapsed_time.tv_sec > timeout->tv_sec || + (elapsed_time.tv_sec == timeout->tv_sec && + elapsed_time.tv_usec > timeout->tv_usec)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL: crypto enabling timeout"); return -1; } - } else { - n = SSL_accept(sslsock->ssl_handle); } if (n <= 0) { - retry = handle_ssl_error(stream, n, sslsock->is_client || sslsock->s.is_blocked TSRMLS_CC); - + /* in case of SSL_ERROR_WANT_READ/WRITE, do not retry in non-blocking mode */ + retry = handle_ssl_error(stream, n, blocked TSRMLS_CC); + if (retry) { + /* wait until something interesting happens in the socket. It may be a + * timeout. Also consider the unlikely of possibility of a write block */ + int err = SSL_get_error(sslsock->ssl_handle, n); + struct timeval left_time; + + if (has_timeout) { + left_time.tv_sec = timeout->tv_sec - elapsed_time.tv_sec; + left_time.tv_usec = timeout->tv_usec - elapsed_time.tv_usec; + if (timeout->tv_usec < elapsed_time.tv_usec) { + left_time.tv_sec -= 1L; + left_time.tv_usec += 1000000L; + } + } + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? + (POLLIN|POLLPRI) : POLLOUT, has_timeout ? &left_time : NULL); + } } else { - break; + retry = 0; } } while (retry); - if (sslsock->is_client && sslsock->s.is_blocked != blocked && SUCCESS == php_set_sock_blocking(sslsock->s.socket, blocked TSRMLS_CC)) { + if (sslsock->s.is_blocked != blocked && SUCCESS == php_set_sock_blocking(sslsock->s.socket, blocked TSRMLS_CC)) { sslsock->s.is_blocked = blocked; } |