diff --git a/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt b/ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt index a66398c3a0e1..fd6c4c3a4daf 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 @@ $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, &$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');