From 488f043226678111449f379741aed730316930ec Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Thu, 9 Feb 2023 17:42:50 +0100 Subject: [PATCH] node: Properly reap git-daemon process --- Cargo.lock | 1 + radicle-node/Cargo.toml | 1 + radicle-node/src/runtime.rs | 19 ++++++++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index d4d49b25..7c301855 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1991,6 +1991,7 @@ dependencies = [ "git-ref-format", "io-reactor", "lexopt", + "libc", "localtime", "log", "netservices", diff --git a/radicle-node/Cargo.toml b/radicle-node/Cargo.toml index e0f4e95c..3632028a 100644 --- a/radicle-node/Cargo.toml +++ b/radicle-node/Cargo.toml @@ -20,6 +20,7 @@ cyphernet = { version = "0.1.0", features = ["tor", "dns", "ed25519", "p2p-ed255 fastrand = { version = "1.8.0" } git-ref-format = { version = "0", features = ["serde", "macro"] } lexopt = { version = "0.2.1" } +libc = { version = "0.2.137" } log = { version = "0.4.17", features = ["std"] } localtime = { version = "1" } netservices = { version = "0.1.0", features = ["io-reactor", "socket2"] } diff --git a/radicle-node/src/runtime.rs b/radicle-node/src/runtime.rs index 01674959..6a1251e1 100644 --- a/radicle-node/src/runtime.rs +++ b/radicle-node/src/runtime.rs @@ -218,7 +218,7 @@ impl Runtime { self.reactor.join().unwrap(); control.join().unwrap()?; - daemon.kill().ok(); // Ignore error if daemon has already exited, for whatever reason. + daemon::kill(&daemon).ok(); // Ignore error if daemon has already exited, for whatever reason. daemon.wait()?; fs::remove_file(home.socket()).ok(); @@ -234,6 +234,20 @@ pub mod daemon { use std::process::{Child, Command, Stdio}; use std::{env, io, net}; + /// Kill the daemon process. + pub fn kill(child: &Child) -> io::Result<()> { + // SAFETY: We use `libc::kill` because `Child::kill` always sends a `SIGKILL` and that doesn't + // work for us. We need to send a `SIGTERM` to fully reap the child process. This is because + // `git-daemon` spawns its own children, and isn't able to reap them if it receives + // a `SIGKILL`. + let result = unsafe { libc::kill(child.id() as libc::c_int, libc::SIGTERM) }; + match result { + 0 => Ok(()), + _ => Err(io::Error::last_os_error()), + } + } + + /// Spawn the daemon process. pub fn spawn(storage: &Path, addr: net::SocketAddr) -> io::Result { let storage = storage.canonicalize()?; let listen = format!("--listen={}", addr.ip()); @@ -247,6 +261,9 @@ pub mod daemon { .arg("daemon") // Make all git directories available. .arg("--export-all") + .arg("--reuseaddr") + .arg("--max-connections=32") + .arg("--informative-errors") .arg("--verbose") // The git "root". Should be our storage path. .arg("--base-path=.")