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');