summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--talpid_core/src/process/openvpn.rs2
-rw-r--r--talpid_core/src/tunnel/mod.rs70
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()
}
}