diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-06-09 14:49:46 +0200 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-06-09 14:49:46 +0200 |
| commit | 3ef19119bfd03d0f3d12f8586dfd6a0569972e53 (patch) | |
| tree | ad15d5f163e699fa0fb692b6cc5273f56c110f8c | |
| parent | c850ba6d06010f3c0d528a750659707ac48fd2ae (diff) | |
| parent | c5b1d6841245ba4fe3689549fb5ca229bac9dd47 (diff) | |
| download | mullvadvpn-3ef19119bfd03d0f3d12f8586dfd6a0569972e53.tar.xz mullvadvpn-3ef19119bfd03d0f3d12f8586dfd6a0569972e53.zip | |
Merge branch 'tunnel-manager-close-handle' into master-new-daemon
| -rw-r--r-- | talpid_core/src/process/openvpn.rs | 2 | ||||
| -rw-r--r-- | talpid_core/src/tunnel/mod.rs | 70 |
2 files changed, 41 insertions, 31 deletions
diff --git a/talpid_core/src/process/openvpn.rs b/talpid_core/src/process/openvpn.rs index df1e4c7682..97c88a99c0 100644 --- a/talpid_core/src/process/openvpn.rs +++ b/talpid_core/src/process/openvpn.rs @@ -54,7 +54,7 @@ impl OpenVpnCommand { /// Build a runnable expression from the current state of the command. pub fn build(&self) -> duct::Expression { debug!("Building expression: {}", &self); - duct::cmd(&self.openvpn_bin, self.get_arguments()) + duct::cmd(&self.openvpn_bin, self.get_arguments()).unchecked() } /// Returns all arguments that the subprocess would be spawned with. diff --git a/talpid_core/src/tunnel/mod.rs b/talpid_core/src/tunnel/mod.rs index c453c52056..3c955c563d 100644 --- a/talpid_core/src/tunnel/mod.rs +++ b/talpid_core/src/tunnel/mod.rs @@ -1,11 +1,12 @@ use net; use openvpn_ffi::OpenVpnPluginEvent; use process::openvpn::OpenVpnCommand; +use std::io; /// A module for all OpenVPN related tunnel management. pub mod openvpn; -use self::openvpn::{OpenVpnEvent, OpenVpnMonitor}; +use self::openvpn::{OpenVpnCloseHandle, OpenVpnMonitor}; mod errors { error_chain!{ @@ -14,10 +15,6 @@ mod errors { TunnelMonitoringError { description("Error while setting up or processing events from the VPN tunnel") } - /// An error indicating that there was an error when trying to start up a VPN tunnel. - TunnelStartError { - description("Error while trying to start the tunnel") - } } } } @@ -25,26 +22,18 @@ pub use self::errors::*; /// Possible events from the VPN tunnel and the child process managing it. +#[derive(Debug)] pub enum TunnelEvent { /// Sent when the tunnel comes up and is ready for traffic. Up, /// Sent when the tunnel goes down. Down, - /// Sent when the process managing the tunnel exits. - Shutdown, } impl TunnelEvent { - /// Converts an `OpenVpnEvent` to a `TunnelEvent`. + /// Converts an `OpenVpnPluginEvent` to a `TunnelEvent`. /// Returns `None` if there is no corresponding `TunnelEvent`. - pub fn from_openvpn_event(event: &OpenVpnEvent) -> Option<TunnelEvent> { - match *event { - OpenVpnEvent::PluginEvent(ref event, _) => Self::from_openvpn_plugin_event(event), - OpenVpnEvent::Shutdown(_) => Some(TunnelEvent::Shutdown), - } - } - - fn from_openvpn_plugin_event(event: &OpenVpnPluginEvent) -> Option<TunnelEvent> { + fn from_openvpn_event(event: &OpenVpnPluginEvent) -> Option<TunnelEvent> { match *event { OpenVpnPluginEvent::Up => Some(TunnelEvent::Up), OpenVpnPluginEvent::RoutePredown => Some(TunnelEvent::Down), @@ -60,28 +49,49 @@ pub struct TunnelMonitor { } impl TunnelMonitor { - /// Creates a new `TunnelMonitor` with the given event callback. - pub fn new<L>(on_event: L) -> Result<Self> + /// Creates a new `TunnelMonitor` that connects to the given remote and notifies `on_event` + /// on tunnel state changes. + pub fn new<L>(remote: net::RemoteAddr, on_event: L) -> Result<Self> where L: Fn(TunnelEvent) + Send + Sync + 'static { - let on_openvpn_event = move |openvpn_event| { - // FIXME: This comment must be here to make rustfmt 0.8.3 not screw up. - match TunnelEvent::from_openvpn_event(&openvpn_event) { - Some(tunnel_event) => on_event(tunnel_event), - None => debug!("Ignoring OpenVpnEvent {:?}", openvpn_event), - } + let on_openvpn_event = move |event, _env| match TunnelEvent::from_openvpn_event(&event) { + Some(tunnel_event) => on_event(tunnel_event), + None => debug!("Ignoring OpenVpnEvent {:?}", event), }; - let monitor = openvpn::OpenVpnMonitor::new(on_openvpn_event, get_plugin_path()) + let cmd = Self::create_openvpn_cmd(remote); + let monitor = openvpn::OpenVpnMonitor::new(cmd, on_openvpn_event, get_plugin_path()) .chain_err(|| ErrorKind::TunnelMonitoringError)?; Ok(TunnelMonitor { monitor }) } - /// Tries to start a VPN tunnel towards the given address. Will fail if there is a tunnel - /// running already. - pub fn start(&self, remote: net::RemoteAddr) -> Result<()> { + fn create_openvpn_cmd(remote: net::RemoteAddr) -> OpenVpnCommand { let mut cmd = OpenVpnCommand::new("openvpn"); - cmd.config(get_config_path()).remotes(remote).unwrap(); - self.monitor.start(cmd).chain_err(|| ErrorKind::TunnelStartError) + cmd.config(get_config_path()) + .remotes(remote) + .unwrap(); + cmd + } + + /// Creates a handle to this monitor, allowing the tunnel to be closed while some other thread + /// is blocked in `wait`. + pub fn close_handle(&self) -> CloseHandle { + CloseHandle(self.monitor.close_handle()) + } + + /// Consumes the monitor and block until the tunnel exits or there is an error. + pub fn wait(self) -> Result<()> { + self.monitor.wait().chain_err(|| ErrorKind::TunnelMonitoringError) + } +} + + +/// A handle to a `TunnelMonitor` +pub struct CloseHandle(OpenVpnCloseHandle); + +impl CloseHandle { + /// Closes the underlying tunnel, making the `TunnelMonitor::wait` method return. + pub fn close(&self) -> io::Result<()> { + self.0.close() } } |
