diff --git a/Cargo.lock b/Cargo.lock index 04b76d2d..897a2876 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,6 +215,14 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-channel" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.7.2" @@ -1085,6 +1093,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "daemonize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1105,6 +1114,7 @@ dependencies = [ "rpki 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "syslog 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1240,6 +1250,24 @@ dependencies = [ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "signal-hook" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook-registry 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "signal-hook-registry" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slab" version = "0.4.2" @@ -1781,6 +1809,7 @@ dependencies = [ "checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" "checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" "checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" "checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" @@ -1889,6 +1918,8 @@ dependencies = [ "checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" +"checksum signal-hook 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cb543aecec4ba8b867f41284729ddfdb7e8fcd70ec3d7d37fca3007a4b53675f" +"checksum signal-hook-registry 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1797d48f38f91643908bb14e35e79928f9f4b3cefb2420a564dde0991b4358dc" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum socks 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e6a64cfa9346d26e836a49fcc1ddfcb4d3df666b6787b6864db61d4918e1cbc2" diff --git a/Cargo.toml b/Cargo.toml index 0d93effc..e98bd358 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ build = "build.rs" bytes = "^0.4" chrono = "^0.4" clap = "^2.0" +crossbeam-channel = "^0.4" crossbeam-queue = "^0.1" crossbeam-utils = "^0.6" derive_more = "^0.15" @@ -32,6 +33,7 @@ reqwest = { version = "^0.9.19", default-features = false, features = [ "rustls ring = "^0.14" rpki = "^0.8.0" serde = "^1.0" +signal-hook = "^0.1.11" slab = "^0.4" tempfile = "^3.1" tokio = "^0.1" diff --git a/src/lib.rs b/src/lib.rs index 98f07d0f..18a03fa6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,3 +44,6 @@ pub mod slurm; pub mod utils; pub mod validity; +#[cfg(not(windows))] +#[macro_use] +extern crate crossbeam_channel; diff --git a/src/operation.rs b/src/operation.rs index 79535213..13d00a62 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -30,7 +30,6 @@ use crate::rtr::rtr_listener; use crate::slurm::LocalExceptions; use crate::validity::RouteValidity; - //------------ Operation ----------------------------------------------------- /// The command to execute. @@ -356,7 +355,6 @@ impl Server { /// Runs the command. pub fn run(self, mut config: Config) -> Result<(), ExitError> { let mut repo = Repository::new(&config, false, true)?; - let idle = IdleWait::new()?; // Create early to fail early. config.switch_logging(self.detach)?; let history = OriginsHistory::new(config.history_size, config.refresh); @@ -375,6 +373,7 @@ impl Server { } }; runtime.spawn(rtr).spawn(http); + let signal = SignalWait::new(&mut runtime)?; loop { history.mark_update_start(); @@ -404,8 +403,19 @@ impl Server { info!("Sending out notifications."); notify.notify(); } - if !idle.wait(history.refresh_wait()) { - break; + match signal.wait(history.refresh_wait()) { + UserSignal::NoSignal => {}, + UserSignal::ReloadTALs => { + match repo.reload_tals(&config) { + Ok(_) => { + info!("Reloaded TALs at user request."); + }, + Err(_) => { + error!("Reloading TALs failed, shutting down."); + break; + } + } + } } } @@ -951,28 +961,84 @@ impl Man { } -//------------ IdleWait ------------------------------------------------------ +//------------ SignalWait ------------------------------------------------------ -/// Wait for the next validation run or a user telling us to quit. +#[allow(dead_code)] +enum UserSignal { + NoSignal, + ReloadTALs, +} + +/// Wait for the next validation run or a user telling us to quit or reload. /// /// This is going to receive a proper impl on Unix and possibly Windows. -struct IdleWait; +#[cfg(not(windows))] +struct SignalWait { + chan: crossbeam_channel::Receiver +} + +#[cfg(not(windows))] +impl SignalWait { + pub fn new(mut runtime: &mut tokio::runtime::Runtime) -> Result { + let chan = Self::create_signal_notifier(&mut runtime)?; + Ok(SignalWait{chan}) + } + + fn create_signal_notifier( + runtime: &mut tokio::runtime::Runtime + ) -> Result, Error> { + let (s, r) = crossbeam_channel::bounded(100); + let signals = match signal_hook::iterator::Signals::new(&[signal_hook::SIGUSR1]) { + Ok(r) => r, + Err(err) => { + error!("Attaching signals failed: {}", err); + return Err(Error) + } + }; + runtime.spawn(futures::future::lazy(move || { + for signal in signals.forever() { + if s.send(signal).is_err() { + break; + } + } + Ok(()) + })); + Ok(r) + } -impl IdleWait { - pub fn new() -> Result { - Ok(IdleWait) + /// Waits for the next thing to do. + /// + /// Returns what to do. + // Clippy seems to have problems understanding the select! macro + #[allow(clippy::needless_return)] + pub fn wait(&self, timeout: Duration) -> UserSignal { + select! { + recv(self.chan) -> _ => { + return UserSignal::ReloadTALs; + }, + recv(crossbeam_channel::after(timeout)) -> _ => { return UserSignal::NoSignal; } + }; + } +} + +#[cfg(windows)] +struct SignalWait; + +#[cfg(windows)] +impl SignalWait { + pub fn new(_runtime: &mut tokio::runtime::Runtime) -> Result { + Ok(SignalWait) } /// Waits for the next thing to do. /// /// Returns whether to continue working. - pub fn wait(&self, timeout: Duration) -> bool { + pub fn wait(&self, timeout: Duration) -> UserSignal { std::thread::sleep(timeout); - true + UserSignal::NoSignal } } - //------------ Error --------------------------------------------------------- /// An error has occurred during operation. diff --git a/src/repository.rs b/src/repository.rs index c8d8ab2a..6725ea92 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -127,6 +127,12 @@ impl Repository { }) } + /// Reloads the TAL files based on the config object. + pub fn reload_tals(&mut self, config: &Config) -> Result<(), Error> { + self.tals = Self::load_tals(&config.tal_dir)?; + Ok(()) + } + /// Loads the TAL files from the given directory. fn load_tals(tal_dir: &Path) -> Result, Error> { let mut res = Vec::new();