From 7ba694411c36c0fe416a61f736cd366a06333827 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Tue, 14 Jul 2026 01:16:29 +0800 Subject: [PATCH 1/2] CI: fix unstable test \ext\sockets\tests\socket_recvfrom_afpacket_no_port.phpt --- .../socket_recvfrom_afpacket_no_port.phpt | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt b/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt index a66398c3a0e1..4122d21b172a 100644 --- a/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt +++ b/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt @@ -29,11 +29,29 @@ $ethertype = pack("n", 0x9000); $payload = "no port test"; $frame = str_pad($dst_mac . $src_mac . $ethertype . $payload, 60, "\x00"); +// ETH_P_ALL sockets on loopback can observe unrelated localhost traffic from +// the parallel test runner. Read until we see our own frame, then validate the +// address returned by recvfrom() without the optional port argument. +function recv_matching(Socket $s, string $header, int $maxlen = 65536, ?string &$addr = null): string|false { + socket_set_nonblock($s); + $deadline = microtime(true) + 5.0; + while (microtime(true) < $deadline) { + $bytes = @socket_recvfrom($s, $buf, $maxlen, 0, $addr); + if ($bytes !== false && is_string($buf) && str_starts_with($buf, $header)) { + return $buf; + } + if ($bytes === false) { + usleep(1000); + } + } + return false; +} + socket_sendto($s_send, $frame, strlen($frame), 0, "lo", 1); // recvfrom without the optional 6th argument (port/ifindex). -$bytes = socket_recvfrom($s_recv, $buf, 65536, 0, $addr); -var_dump($bytes >= 60); +$buf = recv_matching($s_recv, $dst_mac . $src_mac . $ethertype, 65536, $addr); +var_dump($buf !== false && strlen($buf) >= 60); var_dump($addr === 'lo'); socket_close($s_send); From beac118ec540086b3b0f1018ac4ae2fe36df449a Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Tue, 14 Jul 2026 19:56:59 +0800 Subject: [PATCH 2/2] feedback --- .../tests/socket_recvfrom_afpacket_no_port.phpt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt b/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt index 4122d21b172a..fd6c4c3a4daf 100644 --- a/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt +++ b/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt @@ -32,15 +32,16 @@ $frame = str_pad($dst_mac . $src_mac . $ethertype . $payload, 60, "\x00"); // ETH_P_ALL sockets on loopback can observe unrelated localhost traffic from // the parallel test runner. Read until we see our own frame, then validate the // address returned by recvfrom() without the optional port argument. -function recv_matching(Socket $s, string $header, int $maxlen = 65536, ?string &$addr = null): string|false { +function recv_matching(Socket $s, string $header, int $maxlen = 65536, ?string &$addr = null, &$bytes = null): string|false { socket_set_nonblock($s); $deadline = microtime(true) + 5.0; while (microtime(true) < $deadline) { - $bytes = @socket_recvfrom($s, $buf, $maxlen, 0, $addr); - if ($bytes !== false && is_string($buf) && str_starts_with($buf, $header)) { + $recvBytes = @socket_recvfrom($s, $buf, $maxlen, 0, $addr); + if ($recvBytes !== false && is_string($buf) && str_starts_with($buf, $header)) { + $bytes = $recvBytes; return $buf; } - if ($bytes === false) { + if ($recvBytes === false) { usleep(1000); } } @@ -50,8 +51,9 @@ function recv_matching(Socket $s, string $header, int $maxlen = 65536, ?string & socket_sendto($s_send, $frame, strlen($frame), 0, "lo", 1); // recvfrom without the optional 6th argument (port/ifindex). -$buf = recv_matching($s_recv, $dst_mac . $src_mac . $ethertype, 65536, $addr); -var_dump($buf !== false && strlen($buf) >= 60); +$bytes = 0; +$buf = recv_matching($s_recv, $dst_mac . $src_mac . $ethertype, 65536, $addr, $bytes); +var_dump($bytes >= 60); var_dump($addr === 'lo'); socket_close($s_send);