1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 08:12:21 +01:00

Re-fix GH-8409: SSL handshake timeout persistent connections hanging

This fix is another solution to replace d0527427be, use zend_try and zend_catch to make sure persistent stream will be released when error occurred.

Closes GH-9332.
This commit is contained in:
twosee
2022-08-14 19:50:58 +08:00
parent cd1aed8edd
commit b8d07451d4
3 changed files with 65 additions and 30 deletions

2
NEWS
View File

@@ -29,6 +29,8 @@ PHP NEWS
- Streams:
. Fixed bug GH-8472 (The resource returned by stream_socket_accept may have
incorrect metadata). (Jakub Zelenka)
. Fixed bug GH-8409 (SSL handshake timeout leaves persistent connections
hanging). (Jakub Zelenka, Twosee)
04 Aug 2022, PHP 8.0.22

View File

@@ -0,0 +1,25 @@
--TEST--
GH-8409: Error in socket creation when error handler does not clean persistent connection
--FILE--
<?php
set_error_handler(function (int $errno, string $errstring): never {
trigger_error($errstring, E_USER_ERROR);
});
register_shutdown_function(function (): void {
foreach (get_resources() as $res) {
if (get_resource_type($res) === 'persistent stream') {
echo "ERROR: persistent stream not closed\n";
return;
}
}
echo "OK: persistent stream closed\n";
});
stream_socket_client('tcp://9999.9999.9999.9999:9999', $error_code, $error_message, 0.2, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT);
echo "ERROR: this should not be visible\n";
?>
--EXPECTF--
Fatal error: stream_socket_client(): %s in %sgh8409.php on line %d
OK: persistent stream closed

View File

@@ -61,7 +61,8 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in
php_stream_transport_factory factory = NULL;
const char *p, *protocol = NULL;
size_t n = 0;
int failed = 0;
bool failed = false;
bool bailout = false;
zend_string *error_text = NULL;
struct timeval default_timeout = { 0, 0 };
@@ -132,46 +133,50 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in
context STREAMS_REL_CC);
if (stream) {
php_stream_context_set(stream, context);
zend_try {
php_stream_context_set(stream, context);
if ((flags & STREAM_XPORT_SERVER) == 0) {
/* client */
if ((flags & STREAM_XPORT_SERVER) == 0) {
/* client */
if (flags & (STREAM_XPORT_CONNECT|STREAM_XPORT_CONNECT_ASYNC)) {
if (-1 == php_stream_xport_connect(stream, name, namelen,
flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0,
timeout, &error_text, error_code)) {
if (flags & (STREAM_XPORT_CONNECT|STREAM_XPORT_CONNECT_ASYNC)) {
if (-1 == php_stream_xport_connect(stream, name, namelen,
flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0,
timeout, &error_text, error_code)) {
ERR_RETURN(error_string, error_text, "connect() failed: %s");
ERR_RETURN(error_string, error_text, "connect() failed: %s");
failed = 1;
}
}
} else {
/* server */
if (flags & STREAM_XPORT_BIND) {
if (0 != php_stream_xport_bind(stream, name, namelen, &error_text)) {
ERR_RETURN(error_string, error_text, "bind() failed: %s");
failed = 1;
} else if (flags & STREAM_XPORT_LISTEN) {
zval *zbacklog = NULL;
int backlog = 32;
if (PHP_STREAM_CONTEXT(stream) && (zbacklog = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "backlog")) != NULL) {
backlog = zval_get_long(zbacklog);
failed = true;
}
}
if (0 != php_stream_xport_listen(stream, backlog, &error_text)) {
ERR_RETURN(error_string, error_text, "listen() failed: %s");
failed = 1;
} else {
/* server */
if (flags & STREAM_XPORT_BIND) {
if (0 != php_stream_xport_bind(stream, name, namelen, &error_text)) {
ERR_RETURN(error_string, error_text, "bind() failed: %s");
failed = true;
} else if (flags & STREAM_XPORT_LISTEN) {
zval *zbacklog = NULL;
int backlog = 32;
if (PHP_STREAM_CONTEXT(stream) && (zbacklog = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "backlog")) != NULL) {
backlog = zval_get_long(zbacklog);
}
if (0 != php_stream_xport_listen(stream, backlog, &error_text)) {
ERR_RETURN(error_string, error_text, "listen() failed: %s");
failed = true;
}
}
}
}
}
} zend_catch {
bailout = true;
} zend_end_try();
}
if (failed) {
if (failed || bailout) {
/* failure means that they don't get a stream to play with */
if (persistent_id) {
php_stream_pclose(stream);
@@ -179,6 +184,9 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in
php_stream_close(stream);
}
stream = NULL;
if (bailout) {
zend_bailout();
}
}
return stream;