cataphract Thu, 23 Dec 2010 01:44:54 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=306581
Log: - 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. Bug: http://bugs.php.net/53592 (Assigned) stream_socket_enable_crypto() uses NONBLOCK Changed paths: U php/php-src/branches/PHP_5_3/NEWS U php/php-src/branches/PHP_5_3/ext/openssl/xp_ssl.c U php/php-src/trunk/ext/openssl/xp_ssl.c
Modified: php/php-src/branches/PHP_5_3/NEWS =================================================================== --- php/php-src/branches/PHP_5_3/NEWS 2010-12-23 00:17:51 UTC (rev 306580) +++ php/php-src/branches/PHP_5_3/NEWS 2010-12-23 01:44:54 UTC (rev 306581) @@ -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 Modified: php/php-src/branches/PHP_5_3/ext/openssl/xp_ssl.c =================================================================== --- php/php-src/branches/PHP_5_3/ext/openssl/xp_ssl.c 2010-12-23 00:17:51 UTC (rev 306580) +++ php/php-src/branches/PHP_5_3/ext/openssl/xp_ssl.c 2010-12-23 01:44:54 UTC (rev 306581) @@ -411,8 +411,10 @@ 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 @@ 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; } Modified: php/php-src/trunk/ext/openssl/xp_ssl.c =================================================================== --- php/php-src/trunk/ext/openssl/xp_ssl.c 2010-12-23 00:17:51 UTC (rev 306580) +++ php/php-src/trunk/ext/openssl/xp_ssl.c 2010-12-23 01:44:54 UTC (rev 306581) @@ -411,8 +411,10 @@ 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 @@ 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; }
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php