From c9e7222fb0b6fb04d50a6b9336569883730a1ab7 Mon Sep 17 00:00:00 2001 From: Jose Quintana Date: Sun, 11 Jul 2021 21:56:02 +0200 Subject: [PATCH] refactor: cross-platform ctrl-c signal handling --- .gitignore | 1 + Cargo.lock | 70 ++++++++++++++++++++++++++++------------------------------------------ Cargo.toml | 5 +---- src/lib.rs | 5 +---- src/server.rs | 23 ++--------------------- src/signal_manager.rs | 56 -------------------------------------------------------- src/signals.rs | 18 ++++++++++++++++++ 7 files changed, 51 insertions(+), 127 deletions(-) delete mode 100644 src/signal_manager.rs create mode 100644 src/signals.rs diff --git a/.gitignore b/.gitignore index f2cf8f1..69030d7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ **/*.data* **/*.perf* **/*.out* +**/*.zst release .vscode TODO diff --git a/Cargo.lock b/Cargo.lock index ad8d21c..63de1e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,12 +56,6 @@ checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" [[package]] name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" @@ -121,7 +115,17 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", +] + +[[package]] +name = "ctrlc" +version = "3.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "232295399409a8b7ae41276757b5a1cc21032848d42bff2352261f958b3ca29a" +dependencies = [ + "nix", + "winapi", ] [[package]] @@ -139,7 +143,7 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crc32fast", "libc", "miniz_oxide", @@ -178,7 +182,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] @@ -328,9 +332,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.97" +version = "0.2.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" [[package]] name = "log" @@ -347,7 +351,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -413,15 +417,14 @@ dependencies = [ [[package]] name = "nix" -version = "0.14.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" dependencies = [ "bitflags", "cc", - "cfg-if 0.1.10", + "cfg-if", "libc", - "void", ] [[package]] @@ -466,7 +469,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -852,16 +855,6 @@ dependencies = [ ] [[package]] -name = "signal" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f6ce83b159ab6984d2419f495134972b48754d13ff2e3f8c998339942b56ed9" -dependencies = [ - "libc", - "nix", -] - -[[package]] name = "siphasher" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -872,6 +865,7 @@ name = "static-web-server" version = "1.17.1" dependencies = [ "chrono", + "ctrlc", "env_logger", "flate2", "humansize", @@ -884,10 +878,8 @@ dependencies = [ "log 0.4.14", "mime", "mime_guess", - "nix", "openssl", "percent-encoding 2.1.0", - "signal", "structopt", "tempfile", "time", @@ -896,9 +888,9 @@ dependencies = [ [[package]] name = "structopt" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" dependencies = [ "clap", "lazy_static", @@ -907,9 +899,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" dependencies = [ "heck", "proc-macro-error", @@ -935,7 +927,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "rand 0.8.4", "redox_syscall", @@ -1027,9 +1019,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" @@ -1091,12 +1083,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 1f5ffaf..baa400b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,11 +39,8 @@ structopt = { version = "0.3", default-features = false } time = "0.1" url = "1.4" percent-encoding = "2.1" +ctrlc = { version = "3.1", features = ["termination"] } -[target.'cfg(not(windows))'.dependencies.nix] -version = "0.14" -[target.'cfg(not(windows))'.dependencies.signal] -version = "0.7" [target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator] version = "0.3" diff --git a/src/lib.rs b/src/lib.rs index b0eea07..ee21821 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,10 +13,7 @@ pub mod gzip; pub mod helpers; pub mod logger; pub mod server; - -#[cfg(not(windows))] -pub mod signal_manager; - +pub mod signals; pub mod staticfile_middleware; pub mod staticfiles; diff --git a/src/server.rs b/src/server.rs index d9d94af..4fc435c 100644 --- a/src/server.rs +++ b/src/server.rs @@ -3,7 +3,7 @@ use iron::{Chain, Iron, Listening}; use crate::staticfile_middleware::HttpToHttpsRedirect; use crate::staticfiles::*; -use crate::{config::Options, logger}; +use crate::{config::Options, logger, signals}; /// Struct for holding a reference to a running iron server instance #[derive(Debug)] @@ -102,24 +102,5 @@ fn on_server_running(server_name: &str, running_servers: &[RunningServer]) { )) }); - handle_signals() -} - -#[cfg(not(windows))] -fn handle_signals() { - use crate::signal_manager; - - // Wait for incoming signals (E.g Ctrl+C (SIGINT), SIGTERM, etc - signal_manager::wait_for_signal(|sig: signal::Signal| { - let code = signal_manager::signal_to_int(sig); - - println!(); - warn!("Signal {} caught. Server execution exited.", code); - std::process::exit(code) - }) -} - -#[cfg(windows)] -fn handle_signals() { - // TODO: Windows signals... + signals::wait_for_ctrl_c() } diff --git a/src/signal_manager.rs b/src/signal_manager.rs deleted file mode 100644 index 06be40c..0000000 --- a/src/signal_manager.rs +++ /dev/null @@ -1,56 +0,0 @@ -use nix::errno::Errno; -use nix::libc::c_int; -use nix::sys::signal::{SIGCHLD, SIGINT, SIGTERM}; -use nix::sys::wait::WaitStatus::{Exited, Signaled, StillAlive}; -use nix::sys::wait::{waitpid, WaitPidFlag}; -use nix::Error; -use signal::trap::Trap; - -/// It waits for an incoming Termination Signal like Ctrl+C (SIGINT), SIGTERM, etc -pub fn wait_for_signal(f: F) -where - F: Fn(signal::Signal), -{ - let signal_trap = Trap::trap(&[SIGTERM, SIGINT, SIGCHLD]); - - for sig in signal_trap { - match sig { - SIGCHLD => { - // Current std::process::Command ip does not have a way to find - // process id, so we just wait until we have no children - loop { - match waitpid(None, Some(WaitPidFlag::WNOHANG)) { - Ok(Exited(pid, status)) => { - println!("{} exited with status {}", pid, status); - continue; - } - Ok(Signaled(pid, sig, _)) => { - println!("{} killed by {}", pid, sig as c_int); - continue; - } - Ok(StillAlive) => { - break; - } - Ok(status) => { - println!("Temporary status {:?}", status); - continue; - } - Err(Error::Sys(Errno::ECHILD)) => { - return; - } - Err(e) => { - panic!("Error {:?}", e); - } - } - } - } - - sig => f(sig), - } - } -} - -/// It casts a `signal::Signal` to `i32` -pub fn signal_to_int(sig: signal::Signal) -> i32 { - sig as c_int -} diff --git a/src/signals.rs b/src/signals.rs new file mode 100644 index 0000000..289b206 --- /dev/null +++ b/src/signals.rs @@ -0,0 +1,18 @@ +use ctrlc; +use std::{process, sync::mpsc::channel}; + +/// It waits for a `Ctrl-C` incoming signal. +pub fn wait_for_ctrl_c() { + let (tx, rx) = channel(); + + ctrlc::set_handler(move || tx.send(()).expect("could not send signal on channel")) + .expect("error setting Ctrl-C handler"); + + info!("press Ctrl+C to shutdown the server"); + + rx.recv().expect("could not receive signal from channel"); + + warn!("Ctrl+C signal caught, shutting down the server execution"); + + process::exit(1) +} -- libgit2 1.7.2