Skip to content

Commit 14d7195

Browse files
committed
Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0: Re-fix GH-8409: SSL handshake timeout persistent connections hanging
2 parents 897ca85 + b8d0745 commit 14d7195

File tree

2 files changed

+63
-30
lines changed

2 files changed

+63
-30
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
GH-8409: Error in socket creation when error handler does not clean persistent connection
3+
--FILE--
4+
<?php
5+
set_error_handler(function (int $errno, string $errstring): never {
6+
trigger_error($errstring, E_USER_ERROR);
7+
});
8+
9+
register_shutdown_function(function (): void {
10+
foreach (get_resources() as $res) {
11+
if (get_resource_type($res) === 'persistent stream') {
12+
echo "ERROR: persistent stream not closed\n";
13+
return;
14+
}
15+
}
16+
echo "OK: persistent stream closed\n";
17+
});
18+
19+
stream_socket_client('tcp://9999.9999.9999.9999:9999', $error_code, $error_message, 0.2, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT);
20+
21+
echo "ERROR: this should not be visible\n";
22+
?>
23+
--EXPECTF--
24+
Fatal error: stream_socket_client(): %s in %sgh8409.php on line %d
25+
OK: persistent stream closed

main/streams/transports.c

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in
6161
php_stream_transport_factory factory = NULL;
6262
const char *p, *protocol = NULL;
6363
size_t n = 0;
64-
int failed = 0;
64+
bool failed = false;
65+
bool bailout = false;
6566
zend_string *error_text = NULL;
6667
struct timeval default_timeout = { 0, 0 };
6768

@@ -132,53 +133,60 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in
132133
context STREAMS_REL_CC);
133134

134135
if (stream) {
135-
php_stream_context_set(stream, context);
136+
zend_try {
137+
php_stream_context_set(stream, context);
136138

137-
if ((flags & STREAM_XPORT_SERVER) == 0) {
138-
/* client */
139+
if ((flags & STREAM_XPORT_SERVER) == 0) {
140+
/* client */
139141

140-
if (flags & (STREAM_XPORT_CONNECT|STREAM_XPORT_CONNECT_ASYNC)) {
141-
if (-1 == php_stream_xport_connect(stream, name, namelen,
142-
flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0,
143-
timeout, &error_text, error_code)) {
142+
if (flags & (STREAM_XPORT_CONNECT|STREAM_XPORT_CONNECT_ASYNC)) {
143+
if (-1 == php_stream_xport_connect(stream, name, namelen,
144+
flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0,
145+
timeout, &error_text, error_code)) {
144146

145-
ERR_RETURN(error_string, error_text, "connect() failed: %s");
147+
ERR_RETURN(error_string, error_text, "connect() failed: %s");
146148

147-
failed = 1;
148-
}
149-
}
150-
151-
} else {
152-
/* server */
153-
if (flags & STREAM_XPORT_BIND) {
154-
if (0 != php_stream_xport_bind(stream, name, namelen, &error_text)) {
155-
ERR_RETURN(error_string, error_text, "bind() failed: %s");
156-
failed = 1;
157-
} else if (flags & STREAM_XPORT_LISTEN) {
158-
zval *zbacklog = NULL;
159-
int backlog = 32;
160-
161-
if (PHP_STREAM_CONTEXT(stream) && (zbacklog = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "backlog")) != NULL) {
162-
backlog = zval_get_long(zbacklog);
149+
failed = true;
163150
}
151+
}
164152

165-
if (0 != php_stream_xport_listen(stream, backlog, &error_text)) {
166-
ERR_RETURN(error_string, error_text, "listen() failed: %s");
167-
failed = 1;
153+
} else {
154+
/* server */
155+
if (flags & STREAM_XPORT_BIND) {
156+
if (0 != php_stream_xport_bind(stream, name, namelen, &error_text)) {
157+
ERR_RETURN(error_string, error_text, "bind() failed: %s");
158+
failed = true;
159+
} else if (flags & STREAM_XPORT_LISTEN) {
160+
zval *zbacklog = NULL;
161+
int backlog = 32;
162+
163+
if (PHP_STREAM_CONTEXT(stream) && (zbacklog = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "backlog")) != NULL) {
164+
backlog = zval_get_long(zbacklog);
165+
}
166+
167+
if (0 != php_stream_xport_listen(stream, backlog, &error_text)) {
168+
ERR_RETURN(error_string, error_text, "listen() failed: %s");
169+
failed = true;
170+
}
168171
}
169172
}
170173
}
171-
}
174+
} zend_catch {
175+
bailout = true;
176+
} zend_end_try();
172177
}
173178

174-
if (failed) {
179+
if (failed || bailout) {
175180
/* failure means that they don't get a stream to play with */
176181
if (persistent_id) {
177182
php_stream_pclose(stream);
178183
} else {
179184
php_stream_close(stream);
180185
}
181186
stream = NULL;
187+
if (bailout) {
188+
zend_bailout();
189+
}
182190
}
183191

184192
return stream;

0 commit comments

Comments
 (0)