From 09161fbda0af6d06e453f1ea034481d26485ad2f Mon Sep 17 00:00:00 2001 From: jrd Date: Sat, 28 Mar 2026 22:32:09 +0000 Subject: [PATCH 1/2] Retry UDP request on timeout before giving up Replace the single 1.5s socket timeout with a 500ms timeout and up to 3 attempts. If no data is received within the window, the same request is re-sent. This recovers from dropped UDP packets without increasing the worst-case wait time beyond the original 1.5s. --- servers.php | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/servers.php b/servers.php index 5a0d344..d0d261d 100644 --- a/servers.php +++ b/servers.php @@ -932,7 +932,8 @@ function process_received($sock, $data, $n, $fromip, $fromport) { } } -socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array('sec'=>1, 'usec'=>500000)); +$timeout_ms = 500; +socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array('sec'=>0, 'usec'=>$timeout_ms * 1000)); $name = isset($_GET['name']) ? $_GET['name'] : $host; @@ -957,12 +958,28 @@ function process_received($sock, $data, $n, $fromip, $fromport) { // $maxgap = 0; // $last = gettimeofday(true); -while (!$done && $n = socket_recvfrom($sock, $data, 32767, 0, $fromip, $fromport)) { - // printf("socket_recvfrom: %d bytes received from %s:%d\n", $n, $fromip, $fromport); +$attempts = 1; +$max_attempts = 3; - if ($n != strlen($data)) { - error_log("Returned data length does not match string from $fromip:$fromport"); - continue; +while (!$done) { + $n = socket_recvfrom($sock, $data, 32767, 0, $fromip, $fromport); + + if ($n === false) { + if (count($servers) <= 1 && $attempts < $max_attempts) { + // Timeout with no data yet — re-send and try again + $attempts++; + if (isset($_GET['directory'])) { + send_request($sock, CLM_REQ_SERVER_LIST, $ip, $port); + } else { + send_ping_with_num_clients($sock, $ip, $port); + } + continue; + } elseif (count($servers) <= 1) { + error_log("servers.php: no response from $ip after $max_attempts attempts"); + break; + } else { + break; // normal end-of-stream + } } // $now = gettimeofday(true); @@ -970,6 +987,11 @@ function process_received($sock, $data, $n, $fromip, $fromport) { // if ($now - $last > $maxgap) $maxgap = $now - $last; // $last = $now; + if ($n != strlen($data)) { + error_log("Returned data length does not match string from $fromip:$fromport"); + continue; + } + process_received($sock, $data, $n, $fromip, $fromport); } From c5040670daf6e51d890160f8bd7745fc05d440bc Mon Sep 17 00:00:00 2001 From: jrd Date: Tue, 31 Mar 2026 05:38:12 +0000 Subject: [PATCH 2/2] Fix retry condition to use $received_data flag instead of count($servers) The original count($servers) <= 1 heuristic fails for directory servers that legitimately have only one registered server: data is received successfully but the trailing timeout still triggers an unnecessary retry, adding ~500ms latency. Using an explicit $received_data flag correctly distinguishes "no response at all" (retry) from "stream ended normally" (stop). Co-Authored-By: Claude Sonnet 4.6 --- servers.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/servers.php b/servers.php index d0d261d..584966e 100644 --- a/servers.php +++ b/servers.php @@ -960,12 +960,13 @@ function process_received($sock, $data, $n, $fromip, $fromport) { $attempts = 1; $max_attempts = 3; +$received_data = false; while (!$done) { $n = socket_recvfrom($sock, $data, 32767, 0, $fromip, $fromport); if ($n === false) { - if (count($servers) <= 1 && $attempts < $max_attempts) { + if (!$received_data && $attempts < $max_attempts) { // Timeout with no data yet — re-send and try again $attempts++; if (isset($_GET['directory'])) { @@ -974,7 +975,7 @@ function process_received($sock, $data, $n, $fromip, $fromport) { send_ping_with_num_clients($sock, $ip, $port); } continue; - } elseif (count($servers) <= 1) { + } elseif (!$received_data) { error_log("servers.php: no response from $ip after $max_attempts attempts"); break; } else { @@ -992,6 +993,7 @@ function process_received($sock, $data, $n, $fromip, $fromport) { continue; } + $received_data = true; process_received($sock, $data, $n, $fromip, $fromport); }