com php-src: Merge branch 'master' of https://github.com/bbroerman30/php-src: ext/openssl/xp_ssl. c
| From: | rdlowrey@php.net | Date: | Fri, 23 Jan 2015 06:03:39 +0000 |
| Subject: | com php-src: Merge branch 'master' of https://github.com/bbroerman30/php-src: ext/openssl/xp_ssl. c | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-84330@lists.php.net to get a copy of this message | ||
Commit: 459edceea93d92f13c35f650df626315be9b32b2
Author: Daniel Lowrey <rdlowrey@php.net> Fri, 23 Jan 2015 01:03:39 -0500
Parents: 16732dedfe84d16fa7ae11eff945672dc0214c7b ebb67cd6fead10588ee546def89628b2676f77bb
Branches: master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=459edceea93d92f13c35f650df626315be9b32b2
Log:
Merge branch 'master' of https://github.com/bbroerman30/php-src
Conflicts:
ext/openssl/xp_ssl.c
Changed paths:
MM ext/openssl/xp_ssl.c
diff --cc ext/openssl/xp_ssl.c index fd3112e,f9d6ff0..6fab13a --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@@ -1634,11 -1637,11 +1637,11 @@@ static int php_openssl_enable_crypto(ph if (has_timeout) { gettimeofday(&start_time, NULL); } - + do { struct timeval cur_time, - elapsed_time = {0}; - + elapsed_time; + if (sslsock->is_client) { n = SSL_connect(sslsock->ssl_handle); } else { @@@ -1670,14 -1666,9 +1666,9 @@@ * 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; - } + left_time = subtract_timeval( *timeout, elapsed_time ); } php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? (POLLIN|POLLPRI) : POLLOUT, has_timeout ? &left_time : NULL); @@@ -1742,66 -1733,147 +1733,147 @@@ return -1; } - static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size_t count) /* {{{ */ + static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ + { - return php_openssl_sockop_io( 0, stream, buf, count ); ++ return php_openssl_sockop_io( 0, stream, (char*)buf, count ); + } + /* }}} */ + + static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ + { + return php_openssl_sockop_io( 1, stream, buf, count ); + } + /* }}} */ + + /** + * Factored out common functionality (blocking, timeout, loop management) for read and write. + * Perform IO (read or write) to an SSL socket. If we have a timeout, we switch to non-blocking mode + * for the duration of the operation, using select to do our waits. If we time out, or we have an error + * report that back to PHP + * + */ + static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ { php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; - int didwrite; + int nr_bytes = 0; + /* Only do this if SSL is active. */ if (sslsock->ssl_active) { int retry = 1; + struct timeval start_time, + *timeout; + int blocked = sslsock->s.is_blocked, + has_timeout = 0; + + /* Begin by making the socket non-blocking. This allows us to check the timeout. */ + if (SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0 TSRMLS_CC)) { + sslsock->s.is_blocked = 0; + } + + /* Get the timeout value (and make sure we are to check it. */ + 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); + } + /* Main IO loop. */ do { - didwrite = SSL_write(sslsock->ssl_handle, buf, count); + struct timeval cur_time, + elapsed_time; + + /* If we have a timeout to check, figure out how much time has elapsed since we started. */ + if (has_timeout) { + gettimeofday(&cur_time, NULL); + + /* Determine how much time we've taken so far. */ + elapsed_time = subtract_timeval( cur_time, start_time ); + + /* and return an error if we've taken too long. */ + if (compare_timeval( elapsed_time, *timeout) > 0 ) { + /* If the socket was originally blocking, set it back. */ + if (blocked) { + php_set_sock_blocking(sslsock->s.socket, 1 TSRMLS_CC); + sslsock->s.is_blocked = 1; + } + return -1; + } + } - if (didwrite <= 0) { - retry = handle_ssl_error(stream, didwrite, 0); + /* Now, do the IO operation. Don't block if we can't complete... */ + if (read) { + nr_bytes = SSL_read(sslsock->ssl_handle, buf, count); + + if (sslsock->reneg && sslsock->reneg->should_close) { + /* renegotiation rate limiting triggered */ + php_stream_xport_shutdown(stream, (stream_shutdown_t)SHUT_RDWR); + nr_bytes = 0; + stream->eof = 1; + break; + } } else { - break; + nr_bytes = SSL_write(sslsock->ssl_handle, buf, count); } - } while(retry); - if (didwrite > 0) { - php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), didwrite, 0); - } - } else { - didwrite = php_stream_socket_ops.write(stream, buf, count); - } + /* Now, how much time until we time out? */ + struct timeval left_time; + if (has_timeout) { + left_time = subtract_timeval( *timeout, elapsed_time ); + } - if (didwrite < 0) { - didwrite = 0; - } + /* If we didn't do anything on the last loop (or an error) check to see if we should retry or exit. */ + if (nr_bytes <= 0) { - return didwrite; - } - /* }}} */ + /* Get the error code from SSL, and check to see if it's an error or not. */ + int err = SSL_get_error(sslsock->ssl_handle, nr_bytes ); + retry = handle_ssl_error(stream, nr_bytes, 0 TSRMLS_CC); - static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count) /* {{{ */ - { - php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; - int nr_bytes = 0; + /* If we get this (the above doesn't check) then we'll retry as well. */ + if (errno == EAGAIN && ( err == SSL_ERROR_WANT_READ || SSL_ERROR_WANT_WRITE ) ) { + retry = 1; + } - if (sslsock->ssl_active) { - int retry = 1; + /* Also, on reads, we may get this condition on an EOF. We should check properly. */ + if (read) { + stream->eof = (retry == 0 && errno != EAGAIN && !SSL_pending(sslsock->ssl_handle)); + } - do { - nr_bytes = SSL_read(sslsock->ssl_handle, buf, count); + /* Now, if we have to wait some time, and we're supposed to be blocking, wait for the socket to become + * available. Now, php_pollfd_for uses select to wait up to our time_left value only... + */ + if (retry && blocked) { + if (read) { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ? + (POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL); + } else { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? + (POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL); + } + } + } else { + /* Else, if we got bytes back, check for possible errors. */ + int err = SSL_get_error(sslsock->ssl_handle, nr_bytes ); - if (sslsock->reneg && sslsock->reneg->should_close) { - /* renegotiation rate limiting triggered */ - php_stream_xport_shutdown(stream, (stream_shutdown_t)SHUT_RDWR); - nr_bytes = 0; - stream->eof = 1; - break; - } else if (nr_bytes <= 0) { - retry = handle_ssl_error(stream, nr_bytes, 0); - stream->eof = (retry == 0 && errno != EAGAIN && !SSL_pending(sslsock->ssl_handle)); + /* If we didn't get any error, then let's return it to PHP. */ + if (err == SSL_ERROR_NONE) + break; - } else { - /* we got the data */ - break; + /* Otherwise, we need to wait again (up to time_left or we get an error) */ + if (blocked) + if (read) { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ? + (POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL); + } else { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? + (POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL); + } } + /* Finally, we keep going until we got data, and an SSL_ERROR_NONE, unless we had an error. */ } while (retry); + /* Tell PHP if we read / wrote bytes. */ if (nr_bytes > 0) { php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0); }
diff --cc ext/openssl/xp_ssl.c index fd3112e,f9d6ff0..6fab13a --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@@ -1634,11 -1637,11 +1637,11 @@@ static int php_openssl_enable_crypto(ph if (has_timeout) { gettimeofday(&start_time, NULL); } - + do { struct timeval cur_time, - elapsed_time = {0}; - + elapsed_time; + if (sslsock->is_client) { n = SSL_connect(sslsock->ssl_handle); } else { @@@ -1670,14 -1666,9 +1666,9 @@@ * 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; - } + left_time = subtract_timeval( *timeout, elapsed_time ); } php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? (POLLIN|POLLPRI) : POLLOUT, has_timeout ? &left_time : NULL); @@@ -1742,66 -1733,147 +1733,147 @@@ return -1; } - static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size_t count) /* {{{ */ + static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ + { - return php_openssl_sockop_io( 0, stream, buf, count ); ++ return php_openssl_sockop_io( 0, stream, (char*)buf, count ); + } + /* }}} */ + + static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ + { + return php_openssl_sockop_io( 1, stream, buf, count ); + } + /* }}} */ + + /** + * Factored out common functionality (blocking, timeout, loop management) for read and write. + * Perform IO (read or write) to an SSL socket. If we have a timeout, we switch to non-blocking mode + * for the duration of the operation, using select to do our waits. If we time out, or we have an error + * report that back to PHP + * + */ + static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ { php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; - int didwrite; + int nr_bytes = 0; + /* Only do this if SSL is active. */ if (sslsock->ssl_active) { int retry = 1; + struct timeval start_time, + *timeout; + int blocked = sslsock->s.is_blocked, + has_timeout = 0; + + /* Begin by making the socket non-blocking. This allows us to check the timeout. */ + if (SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0 TSRMLS_CC)) { + sslsock->s.is_blocked = 0; + } + + /* Get the timeout value (and make sure we are to check it. */ + 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); + } + /* Main IO loop. */ do { - didwrite = SSL_write(sslsock->ssl_handle, buf, count); + struct timeval cur_time, + elapsed_time; + + /* If we have a timeout to check, figure out how much time has elapsed since we started. */ + if (has_timeout) { + gettimeofday(&cur_time, NULL); + + /* Determine how much time we've taken so far. */ + elapsed_time = subtract_timeval( cur_time, start_time ); + + /* and return an error if we've taken too long. */ + if (compare_timeval( elapsed_time, *timeout) > 0 ) { + /* If the socket was originally blocking, set it back. */ + if (blocked) { + php_set_sock_blocking(sslsock->s.socket, 1 TSRMLS_CC); + sslsock->s.is_blocked = 1; + } + return -1; + } + } - if (didwrite <= 0) { - retry = handle_ssl_error(stream, didwrite, 0); + /* Now, do the IO operation. Don't block if we can't complete... */ + if (read) { + nr_bytes = SSL_read(sslsock->ssl_handle, buf, count); + + if (sslsock->reneg && sslsock->reneg->should_close) { + /* renegotiation rate limiting triggered */ + php_stream_xport_shutdown(stream, (stream_shutdown_t)SHUT_RDWR); + nr_bytes = 0; + stream->eof = 1; + break; + } } else { - break; + nr_bytes = SSL_write(sslsock->ssl_handle, buf, count); } - } while(retry); - if (didwrite > 0) { - php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), didwrite, 0); - } - } else { - didwrite = php_stream_socket_ops.write(stream, buf, count); - } + /* Now, how much time until we time out? */ + struct timeval left_time; + if (has_timeout) { + left_time = subtract_timeval( *timeout, elapsed_time ); + } - if (didwrite < 0) { - didwrite = 0; - } + /* If we didn't do anything on the last loop (or an error) check to see if we should retry or exit. */ + if (nr_bytes <= 0) { - return didwrite; - } - /* }}} */ + /* Get the error code from SSL, and check to see if it's an error or not. */ + int err = SSL_get_error(sslsock->ssl_handle, nr_bytes ); + retry = handle_ssl_error(stream, nr_bytes, 0 TSRMLS_CC); - static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count) /* {{{ */ - { - php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; - int nr_bytes = 0; + /* If we get this (the above doesn't check) then we'll retry as well. */ + if (errno == EAGAIN && ( err == SSL_ERROR_WANT_READ || SSL_ERROR_WANT_WRITE ) ) { + retry = 1; + } - if (sslsock->ssl_active) { - int retry = 1; + /* Also, on reads, we may get this condition on an EOF. We should check properly. */ + if (read) { + stream->eof = (retry == 0 && errno != EAGAIN && !SSL_pending(sslsock->ssl_handle)); + } - do { - nr_bytes = SSL_read(sslsock->ssl_handle, buf, count); + /* Now, if we have to wait some time, and we're supposed to be blocking, wait for the socket to become + * available. Now, php_pollfd_for uses select to wait up to our time_left value only... + */ + if (retry && blocked) { + if (read) { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ? + (POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL); + } else { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? + (POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL); + } + } + } else { + /* Else, if we got bytes back, check for possible errors. */ + int err = SSL_get_error(sslsock->ssl_handle, nr_bytes ); - if (sslsock->reneg && sslsock->reneg->should_close) { - /* renegotiation rate limiting triggered */ - php_stream_xport_shutdown(stream, (stream_shutdown_t)SHUT_RDWR); - nr_bytes = 0; - stream->eof = 1; - break; - } else if (nr_bytes <= 0) { - retry = handle_ssl_error(stream, nr_bytes, 0); - stream->eof = (retry == 0 && errno != EAGAIN && !SSL_pending(sslsock->ssl_handle)); + /* If we didn't get any error, then let's return it to PHP. */ + if (err == SSL_ERROR_NONE) + break; - } else { - /* we got the data */ - break; + /* Otherwise, we need to wait again (up to time_left or we get an error) */ + if (blocked) + if (read) { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ? + (POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL); + } else { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? + (POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL); + } } + /* Finally, we keep going until we got data, and an SSL_ERROR_NONE, unless we had an error. */ } while (retry); + /* Tell PHP if we read / wrote bytes. */ if (nr_bytes > 0) { php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0); }