fix(sync): recover hidden server listeners

This commit is contained in:
Brad Stein 2026-04-28 02:04:29 -03:00
parent a9aefd470c
commit b69513f088
6 changed files with 75 additions and 6 deletions

6
Cargo.lock generated
View File

@ -1642,7 +1642,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "lesavka_client"
version = "0.14.36"
version = "0.14.37"
dependencies = [
"anyhow",
"async-stream",
@ -1676,7 +1676,7 @@ dependencies = [
[[package]]
name = "lesavka_common"
version = "0.14.36"
version = "0.14.37"
dependencies = [
"anyhow",
"base64",
@ -1688,7 +1688,7 @@ dependencies = [
[[package]]
name = "lesavka_server"
version = "0.14.36"
version = "0.14.37"
dependencies = [
"anyhow",
"base64",

View File

@ -4,7 +4,7 @@ path = "src/main.rs"
[package]
name = "lesavka_client"
version = "0.14.36"
version = "0.14.37"
edition = "2024"
[dependencies]

View File

@ -1,6 +1,6 @@
[package]
name = "lesavka_common"
version = "0.14.36"
version = "0.14.37"
edition = "2024"
build = "build.rs"

View File

@ -134,6 +134,11 @@ list_server_listener_pids() {
} | sed '/^$/d' | sort -u
}
list_server_bound_inactive_lines() {
local port=$1
sudo ss -H -B -tn "sport = :$port" 2>/dev/null | sed '/^$/d' || true
}
list_server_listener_inodes_proc() {
local port=$1 hex_port
hex_port=$(printf '%04X' "$port")
@ -183,6 +188,39 @@ server_listener_presence_detail() {
printf 'listener inodes on :%s => %s' "$port" "${inodes[*]}"
}
server_bound_inactive_detail() {
local port=$1
local detail
detail=$(list_server_bound_inactive_lines "$port" | paste -sd ';' -)
if [[ -z $detail ]]; then
printf 'no bound-inactive tcp sockets for :%s' "$port"
return 0
fi
printf 'bound-inactive tcp sockets on :%s => %s' "$port" "$detail"
}
destroy_hidden_server_listener() {
local port=$1
echo "⚠️ TCP :$port is listening without a visible owning PID; asking the kernel to drop the stale socket state."
sudo ss -K state connected "sport = :$port or dport = :$port" >/dev/null 2>&1 || true
sudo ss -K state listening "sport = :$port" >/dev/null 2>&1 || true
for _ in {1..30}; do
if ! list_server_listener_inodes_proc "$port" | grep -q .; then
if list_server_bound_inactive_lines "$port" | grep -q .; then
echo "❌ TCP :$port stopped listening but remains bound after kernel cleanup; $(server_bound_inactive_detail "$port")." >&2
return 1
fi
echo "✅ kernel dropped the hidden TCP :$port socket state."
return 0
fi
sleep 0.1
done
echo "❌ TCP :$port still appears to be listening after kernel socket cleanup; $(server_listener_presence_detail "$port")." >&2
return 1
}
clear_stale_server_listener() {
local port pid cmdline found=0 unexpected=0
port=$(server_bind_port) || {
@ -208,9 +246,16 @@ clear_stale_server_listener() {
fi
if [[ "$found" == "0" ]]; then
if list_server_listener_inodes_proc "$port" | grep -q .; then
if destroy_hidden_server_listener "$port"; then
return 0
fi
echo "❌ TCP :$port is listening but no owning PID could be identified; $(server_listener_presence_detail "$port")." >&2
return 1
fi
if list_server_bound_inactive_lines "$port" | grep -q .; then
echo "❌ TCP :$port is not listening but remains bound; $(server_bound_inactive_detail "$port")." >&2
return 1
fi
return 0
fi
@ -246,6 +291,10 @@ clear_stale_server_listener() {
echo "❌ TCP :$port still appears to be listening after cleanup; $(server_listener_presence_detail "$port")." >&2
return 1
fi
if list_server_bound_inactive_lines "$port" | grep -q .; then
echo "❌ TCP :$port stopped listening but remains bound after cleanup; $(server_bound_inactive_detail "$port")." >&2
return 1
fi
echo "❌ lesavka-server listener on :$port survived cleanup; refusing to start a duplicate server." >&2
return 1

View File

@ -10,7 +10,7 @@ bench = false
[package]
name = "lesavka_server"
version = "0.14.36"
version = "0.14.37"
edition = "2024"
autobins = false

View File

@ -122,10 +122,30 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
SERVER_INSTALL.contains("socket:["),
"install script should map listening socket inodes back to owning PIDs"
);
assert!(
SERVER_INSTALL.contains("ss -K state connected"),
"install script should clear hidden connected socket state before retrying the server port"
);
assert!(
SERVER_INSTALL.contains("ss -K state listening"),
"install script should ask the kernel to drop a hidden listening socket when no PID is visible"
);
assert!(
SERVER_INSTALL.contains("list_server_bound_inactive_lines"),
"install script should check for sockets that remain bound after listener teardown"
);
assert!(
SERVER_INSTALL.contains("bound-inactive tcp sockets"),
"install script should explain when a hidden socket stops listening but still blocks the port"
);
assert!(
SERVER_INSTALL.contains("unexpected process"),
"install script should fail loud instead of killing an unrelated process on the server port"
);
assert!(
SERVER_INSTALL.contains("kernel dropped the hidden TCP"),
"install script should report when kernel-level stale-socket cleanup succeeds"
);
assert!(
SERVER_INSTALL.contains("no owning PID could be identified"),
"install script should fail loud when a port is listening but procfs cannot identify the owner"