fix: use socket connectivity alone instead combining it with PID check for daemon liveness (#879)

This commit is contained in:
Mateusz Burzyński
2026-03-17 11:29:01 -05:00
committed by GitHub
parent 60f3afcf61
commit f8eb38c7f1
2 changed files with 9 additions and 38 deletions
+4 -38
View File
@@ -150,42 +150,6 @@ fn get_port_for_session(session: &str) -> u16 {
49152 + ((hash.unsigned_abs() as u32 % 16383) as u16)
}
#[cfg(unix)]
fn is_daemon_running(session: &str) -> bool {
let pid_path = get_pid_path(session);
if !pid_path.exists() {
return false;
}
if let Ok(pid_str) = fs::read_to_string(&pid_path) {
if let Ok(pid) = pid_str.trim().parse::<i32>() {
unsafe {
if libc::kill(pid, 0) == 0 {
return true;
}
// EPERM means the process exists but we lack permission to
// signal it (e.g. inside a macOS sandbox). Only ESRCH means
// the process is genuinely gone.
return std::io::Error::last_os_error().raw_os_error() != Some(libc::ESRCH);
}
}
}
false
}
#[cfg(windows)]
fn is_daemon_running(session: &str) -> bool {
let pid_path = get_pid_path(session);
if !pid_path.exists() {
return false;
}
let port = get_port_for_session(session);
TcpStream::connect_timeout(
&format!("127.0.0.1:{}", port).parse().unwrap(),
Duration::from_millis(100),
)
.is_ok()
}
fn daemon_ready(session: &str) -> bool {
#[cfg(unix)]
{
@@ -315,8 +279,10 @@ fn apply_daemon_env(cmd: &mut Command, session: &str, opts: &DaemonOptions) {
}
pub fn ensure_daemon(session: &str, opts: &DaemonOptions) -> Result<DaemonResult, String> {
// Check if daemon is running AND responsive
if is_daemon_running(session) && daemon_ready(session) {
// Socket connectivity is the sole liveness check — no PID check — so
// callers in a different PID namespace (e.g. unshare) can still reuse
// an existing daemon they can reach over the socket.
if daemon_ready(session) {
// Double-check it's actually responsive by waiting and checking again
// This handles the race condition where daemon is shutting down
// (daemon has a 100ms shutdown delay, so we wait longer)