Skip to content

Commit d835cdf

Browse files
committed
Fix flaky stream_socket_get_crypto_status handshake test
The test could intermittently fail because a non-blocking TLS handshake can complete in a single stream_socket_enable_crypto() call, so WANT_READ/WANT_WRITE was never observed and $sawWant stayed false. Route the connection through a plain TCP proxy that forwards the server handshake flight in fragments, forcing the client to see a partial TLS record and report WANT_READ at least once.
1 parent 8613e0e commit d835cdf

1 file changed

Lines changed: 46 additions & 2 deletions

File tree

ext/openssl/tests/stream_socket_get_crypto_status_handshake.phpt

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,46 @@ $serverCode = <<<'CODE'
2727
CODE;
2828
$serverCode = sprintf($serverCode, $certFile);
2929

30+
/* Plain TCP proxy that forwards the server handshake flight in fragments, so the client's
31+
* non-blocking handshake sees a partial TLS record and reports WANT_READ instead of completing
32+
* in a single call (which can otherwise happen depending on timing). */
33+
$proxyCode = <<<'CODE'
34+
$upstream = stream_socket_client("tcp://{{ ADDR }}", $errno, $errstr, 30, STREAM_CLIENT_CONNECT);
35+
stream_set_blocking($upstream, false);
36+
37+
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
38+
$server = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr, $flags);
39+
phpt_notify_server_start($server);
40+
41+
$conn = stream_socket_accept($server);
42+
stream_set_blocking($conn, false);
43+
44+
$read = [$upstream, $conn];
45+
while (stream_select($read, $write, $except, 1)) {
46+
foreach ($read as $fp) {
47+
$data = stream_get_contents($fp);
48+
if ($data === '') {
49+
continue;
50+
}
51+
if ($fp === $conn) {
52+
fwrite($upstream, $data);
53+
} else {
54+
/* Fragment server -> client to force a partial TLS record. */
55+
foreach (str_split($data, (int) ceil(strlen($data) / 3)) as $part) {
56+
fwrite($conn, $part);
57+
usleep(50000);
58+
}
59+
}
60+
}
61+
if (feof($upstream) || feof($conn)) {
62+
break;
63+
}
64+
$read = [$upstream, $conn];
65+
}
66+
67+
phpt_wait();
68+
CODE;
69+
3070
/* Client connects over plain TCP, then completes the TLS handshake in non-blocking mode, using
3171
* the reported crypto status to select the right direction to wait on. */
3272
$clientCode = <<<'CODE'
@@ -73,7 +113,8 @@ $clientCode = <<<'CODE'
73113
74114
stream_set_blocking($client, true);
75115
echo trim(fgets($client)), "\n";
76-
phpt_notify();
116+
phpt_notify('server');
117+
phpt_notify('proxy');
77118
fclose($client);
78119
CODE;
79120
$clientCode = sprintf($clientCode, $peerName);
@@ -83,7 +124,10 @@ $certificateGenerator = new CertificateGenerator();
83124
$certificateGenerator->saveNewCertAsFileWithKey($peerName, $certFile);
84125

85126
include 'ServerClientTestCase.inc';
86-
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
127+
ServerClientTestCase::getInstance()->run($clientCode, [
128+
'server' => $serverCode,
129+
'proxy' => $proxyCode,
130+
]);
87131
?>
88132
--CLEAN--
89133
<?php

0 commit comments

Comments
 (0)