From 629c00dc4af4fff9ab583f51054980d5e8a4e518 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Sat, 22 Aug 2026 03:35:45 +0800 Subject: [PATCH] fix(port): handle stale macOS wildcard guards Co-authored-by: wonfen --- src-tauri/src/core/listener.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src-tauri/src/core/listener.rs b/src-tauri/src/core/listener.rs index be3b42924..cd2f537c1 100644 --- a/src-tauri/src/core/listener.rs +++ b/src-tauri/src/core/listener.rs @@ -352,9 +352,8 @@ fn claims_overlap(left: &BindClaim, right: &BindClaim) -> bool { /// rebind it at once (measured on macOS 26). "Is anything answering?" survives that asymmetry; /// "can I bind?" does not. /// -/// Restrictions, both deliberate: a wildcard claim can be blocked by a listener on any address, so -/// one refused connection cannot clear it — leaving `allow-lan` setups exposed to the same false -/// positive. UDP has no lingering state, so a refused UDP bind is always a live socket. +/// Restrictions, both deliberate: every concrete guard for a wildcard claim must be checked before +/// it can be cleared. UDP has no lingering state, so a refused UDP bind is always a live socket. fn nothing_is_serving(claim: &BindClaim) -> bool { const ANSWER_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(200); @@ -477,12 +476,17 @@ fn bind_claim(claim: &BindClaim) -> io::Result> { } guard_addresses.sort_unstable(); guard_addresses.dedup(); + let mut stale_guard = false; for address in guard_addresses { - match bind_socket(&BindClaim::new(claim.name, address, claim.port, claim.transport)) { + let guard_claim = BindClaim::new(claim.name, address, claim.port, claim.transport); + match bind_socket(&guard_claim) { Ok(socket) => sockets.push(socket), // Only a conflict proves the port is taken; a vanished guard address proves nothing. Err(error) if is_bind_conflict(&error) => { - // The caller only sees the claim, so name the address that actually lost. + if nothing_is_serving(&guard_claim) { + stale_guard = true; + continue; + } logging!( warn, LogType::Network, @@ -497,6 +501,9 @@ fn bind_claim(claim: &BindClaim) -> io::Result> { Err(_) => {} } } + if stale_guard { + return Ok(sockets); + } } let socket = bind_socket(claim)?;