diff options
| -rw-r--r-- | mullvad_daemon/Cargo.toml | 6 | ||||
| -rw-r--r-- | mullvad_daemon/src/main.rs | 52 | ||||
| -rw-r--r-- | mullvad_daemon/src/shutdown.rs | 42 |
3 files changed, 88 insertions, 12 deletions
diff --git a/mullvad_daemon/Cargo.toml b/mullvad_daemon/Cargo.toml index ce2ffafa98..2df00ca25e 100644 --- a/mullvad_daemon/Cargo.toml +++ b/mullvad_daemon/Cargo.toml @@ -20,5 +20,11 @@ lazy_static = "0.2" talpid_core = { path = "../talpid_core" } talpid_ipc = { path = "../talpid_ipc" } +[target.'cfg(unix)'.dependencies] +simple-signal = "1.1" + +[target.'cfg(windows)'.dependencies] +ctrlc = "3.0" + [dev-dependencies] assert_matches = "1.0" diff --git a/mullvad_daemon/src/main.rs b/mullvad_daemon/src/main.rs index 77540c7387..5295664a0c 100644 --- a/mullvad_daemon/src/main.rs +++ b/mullvad_daemon/src/main.rs @@ -23,6 +23,7 @@ extern crate talpid_ipc; mod management_interface; mod states; mod rpc_info; +mod shutdown; use management_interface::{ManagementInterfaceServer, TunnelCommand}; use states::{SecurityState, TargetState}; @@ -61,11 +62,13 @@ lazy_static! { ]; } + pub enum DaemonEvent { TunnelEvent(TunnelEvent), TunnelExit(tunnel::Result<()>), ManagementInterfaceEvent(TunnelCommand), ManagementInterfaceExit(talpid_ipc::Result<()>), + Shutdown, } impl From<TunnelEvent> for DaemonEvent { @@ -101,6 +104,7 @@ impl TunnelState { } } +struct Exit(bool); struct Daemon { state: TunnelState, @@ -170,43 +174,49 @@ impl Daemon { ); } - /// Consume the `Daemon` and run the main event loop. Blocks until an error happens. + /// Consume the `Daemon` and run the main event loop. Blocks until an error happens or a + /// shutdown event is received. pub fn run(mut self) -> Result<()> { while let Ok(event) = self.rx.recv() { - self.handle_event(event)?; + if let Exit(true) = self.handle_event(event)? { + break; + } } Ok(()) } - fn handle_event(&mut self, event: DaemonEvent) -> Result<()> { + fn handle_event(&mut self, event: DaemonEvent) -> Result<Exit> { use DaemonEvent::*; match event { - TunnelEvent(event) => Ok(self.handle_tunnel_event(event)), + TunnelEvent(event) => self.handle_tunnel_event(event), TunnelExit(result) => self.handle_tunnel_exit(result), ManagementInterfaceEvent(event) => self.handle_management_interface_event(event), ManagementInterfaceExit(result) => self.handle_management_interface_exit(result), + Shutdown => Ok(Exit(true)), } } - fn handle_tunnel_event(&mut self, tunnel_event: TunnelEvent) { + fn handle_tunnel_event(&mut self, tunnel_event: TunnelEvent) -> Result<Exit> { info!("Tunnel event: {:?}", tunnel_event); let new_state = match tunnel_event { TunnelEvent::Up => TunnelState::Up, TunnelEvent::Down => TunnelState::Down, }; self.set_state(new_state); + Ok(Exit(false)) } - fn handle_tunnel_exit(&mut self, result: tunnel::Result<()>) -> Result<()> { + fn handle_tunnel_exit(&mut self, result: tunnel::Result<()>) -> Result<Exit> { self.tunnel_close_handle = None; if let Err(e) = result.chain_err(|| "Tunnel exited in an unexpected way") { log_error(&e); } self.set_state(TunnelState::NotRunning); - self.apply_target_state() + self.apply_target_state()?; + Ok(Exit(false)) } - fn handle_management_interface_event(&mut self, event: TunnelCommand) -> Result<()> { + fn handle_management_interface_event(&mut self, event: TunnelCommand) -> Result<Exit> { match event { TunnelCommand::SetTargetState(state) => self.set_target_state(state)?, TunnelCommand::GetState(tx) => { @@ -215,14 +225,14 @@ impl Daemon { } } } - Ok(()) + Ok(Exit(false)) } - fn handle_management_interface_exit(&self, result: talpid_ipc::Result<()>) -> Result<()> { + fn handle_management_interface_exit(&self, result: talpid_ipc::Result<()>) -> Result<Exit> { let error = ErrorKind::ManagementInterfaceError("Server exited unexpectedly"); match result { Ok(()) => Err(error.into()), - e => e.chain_err(|| error), + Err(e) => Err(e).chain_err(|| error), } } @@ -255,7 +265,6 @@ impl Daemon { debug!("Triggering tunnel start"); if let Err(e) = self.start_tunnel().chain_err(|| "Failed to start tunnel") { log_error(&e); - self.management_interface_broadcaster.notify_error(&e); self.target_state = TargetState::Unsecured; } Ok(()) @@ -317,6 +326,20 @@ impl Daemon { }, ); } + + pub fn shutdown_handle(&self) -> DaemonShutdownHandle { + DaemonShutdownHandle { tx: self.tx.clone() } + } +} + +struct DaemonShutdownHandle { + tx: mpsc::Sender<DaemonEvent>, +} + +impl DaemonShutdownHandle { + pub fn shutdown(&self) { + let _ = self.tx.send(DaemonEvent::Shutdown); + } } impl Drop for Daemon { @@ -344,6 +367,11 @@ fn run() -> Result<()> { init_logger()?; let daemon = Daemon::new().chain_err(|| "Unable to initialize daemon")?; + + let shutdown_handle = daemon.shutdown_handle(); + shutdown::set_shutdown_signal_handler(move || shutdown_handle.shutdown()) + .chain_err(|| "Unable to attach shutdown signal handler")?; + daemon.run()?; debug!("Mullvad daemon is quitting"); diff --git a/mullvad_daemon/src/shutdown.rs b/mullvad_daemon/src/shutdown.rs new file mode 100644 index 0000000000..4da73c4d05 --- /dev/null +++ b/mullvad_daemon/src/shutdown.rs @@ -0,0 +1,42 @@ +error_chain!{} + +#[cfg(unix)] +mod platform { + extern crate simple_signal; + + use self::simple_signal::Signal; + use super::Result; + + pub fn set_shutdown_signal_handler<F>(f: F) -> Result<()> + where F: Fn() + 'static + Send + { + simple_signal::set_handler( + &[Signal::Term, Signal::Int], move |s| { + debug!("Process received signal: {:?}", s); + f(); + } + ); + Ok(()) + } +} + +#[cfg(windows)] +mod platform { + extern crate ctrlc; + + use super::{Result, ResultExt}; + + pub fn set_shutdown_signal_handler<F>(f: F) -> Result<()> + where F: Fn() + 'static + Send + { + ctrlc::set_handler( + move || { + debug!("Process received Ctrl-c"); + f(); + }, + ) + .chain_err(|| "Unable to attach ctrl-c handler") + } +} + +pub use self::platform::*; |
