Commit 0fef3c3895f for php.net
commit 0fef3c3895fa80f8fc593164b2e1cb59e664d9a6
Author: Weilin Du <weilindu@php.net>
Date: Wed Jul 15 02:14:51 2026 +0800
CI: fix unstable test \ext\sockets\tests\socket_recvfrom_afpacket_no_port.phpt (#22724)
Fix flaky CI test:
\ext\sockets\tests\socket_recvfrom_afpacket_no_port.phpt
failed run example:
https://github.com/php/php-src/actions/runs/29266463698/job/86873055452
diff --git a/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt b/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt
index a66398c3a0e..fd6c4c3a4da 100644
--- a/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt
+++ b/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt
@@ -29,10 +29,30 @@
$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, &$bytes = null): string|false {
+ socket_set_nonblock($s);
+ $deadline = microtime(true) + 5.0;
+ while (microtime(true) < $deadline) {
+ $recvBytes = @socket_recvfrom($s, $buf, $maxlen, 0, $addr);
+ if ($recvBytes !== false && is_string($buf) && str_starts_with($buf, $header)) {
+ $bytes = $recvBytes;
+ return $buf;
+ }
+ if ($recvBytes === 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);
+$bytes = 0;
+$buf = recv_matching($s_recv, $dst_mac . $src_mac . $ethertype, 65536, $addr, $bytes);
var_dump($bytes >= 60);
var_dump($addr === 'lo');