summaryrefslogtreecommitdiffhomepage
path: root/talpid_core
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2017-05-23 13:07:18 +0200
committerLinus Färnstrand <linus@mullvad.net>2017-05-23 13:07:18 +0200
commit54754e78fa41244f661bf76d921b35edeb6b9be8 (patch)
treedc1e0156f6019a2b7f2d37cc7325ac3794b1bef1 /talpid_core
parent649a0d5bae81ac6b1b1385fd9ad013f4c3134515 (diff)
parent26d77b11f01276023683ac0701ef2e190b367dc6 (diff)
downloadmullvadvpn-54754e78fa41244f661bf76d921b35edeb6b9be8.tar.xz
mullvadvpn-54754e78fa41244f661bf76d921b35edeb6b9be8.zip
Merge branch 'new-openvpn-monitor'
Diffstat (limited to 'talpid_core')
-rw-r--r--talpid_core/src/process/openvpn.rs79
-rw-r--r--talpid_core/src/tunnel/openvpn.rs117
2 files changed, 116 insertions, 80 deletions
diff --git a/talpid_core/src/process/openvpn.rs b/talpid_core/src/process/openvpn.rs
index 5d40d8e42c..df1e4c7682 100644
--- a/talpid_core/src/process/openvpn.rs
+++ b/talpid_core/src/process/openvpn.rs
@@ -1,7 +1,5 @@
extern crate openvpn_ffi;
-use super::monitor::ChildMonitor;
-
use duct;
use net::{RemoteAddr, ToRemoteAddrs};
@@ -9,25 +7,8 @@ use net::{RemoteAddr, ToRemoteAddrs};
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::io;
-use std::ops::DerefMut;
use std::path::{Path, PathBuf};
-use std::process;
-use std::sync::{Arc, Mutex};
-
-use talpid_ipc;
-error_chain!{
- errors {
- /// Error while communicating with the OpenVPN plugin.
- PluginCommunicationError {
- description("Error while communicating with the OpenVPN plugin")
- }
- /// Error while trying to spawn OpenVPN process.
- ChildSpawnError {
- description("Error while trying to spawn OpenVPN process")
- }
- }
-}
/// An OpenVPN process builder, providing control over the different arguments that the OpenVPN
/// binary accepts.
@@ -123,66 +104,8 @@ fn write_argument(fmt: &mut fmt::Formatter, arg: &str) -> fmt::Result {
}
-/// Possible events from OpenVPN
-pub enum OpenVpnEvent {
- /// An event from the plugin loaded into OpenVPN.
- PluginEvent(talpid_ipc::Result<(openvpn_ffi::OpenVpnPluginEvent, openvpn_ffi::OpenVpnEnv)>),
- /// The OpenVPN process exited. Containing the result of waiting for the process.
- Shutdown(io::Result<process::ExitStatus>),
-}
-
-/// A struct able to start and monitor OpenVPN processes.
-pub struct OpenVpnMonitor {
- child: ChildMonitor,
-}
-
-impl OpenVpnMonitor {
- /// Spawns a new OpenVPN process and monitors it for exit and events.
- pub fn start<P, L>(mut cmd: OpenVpnCommand, plugin_path: P, listener: L) -> Result<Self>
- where P: AsRef<Path>,
- L: FnMut(OpenVpnEvent) + Send + 'static
- {
- let shared_listener = Arc::new(Mutex::new(listener));
- let server_id = Self::start_plugin_listener(shared_listener.clone())?;
- cmd.plugin(plugin_path, vec![server_id]);
- let child = Self::start_child_monitor(&cmd, shared_listener)?;
- Ok(OpenVpnMonitor { child })
- }
-
- fn start_plugin_listener<L>(shared_listener: Arc<Mutex<L>>) -> Result<String>
- where L: FnMut(OpenVpnEvent) + Send + 'static
- {
- talpid_ipc::start_new_server(
- move |msg| {
- let mut listener = shared_listener.lock().unwrap();
- (listener.deref_mut())(OpenVpnEvent::PluginEvent(msg));
- },
- )
- .chain_err(|| ErrorKind::PluginCommunicationError)
- }
-
- fn start_child_monitor<L>(cmd: &OpenVpnCommand,
- shared_listener: Arc<Mutex<L>>)
- -> Result<ChildMonitor>
- where L: FnMut(OpenVpnEvent) + Send + 'static
- {
- let on_exit = move |result: io::Result<&process::Output>| {
- let status = result.map(|out: &process::Output| out.status.clone());
- let mut listener = shared_listener.lock().unwrap();
- (listener.deref_mut())(OpenVpnEvent::Shutdown(status));
- };
- ChildMonitor::start(&cmd.build(), on_exit).chain_err(|| ErrorKind::ChildSpawnError)
- }
-
- /// Send a kill signal to the OpenVPN process.
- pub fn kill(&self) -> io::Result<()> {
- self.child.kill()
- }
-}
-
-
#[cfg(test)]
-mod openvpn_command_tests {
+mod tests {
use super::OpenVpnCommand;
use net::RemoteAddr;
use std::ffi::OsString;
diff --git a/talpid_core/src/tunnel/openvpn.rs b/talpid_core/src/tunnel/openvpn.rs
index c0d65ce462..bcf89e3eb0 100644
--- a/talpid_core/src/tunnel/openvpn.rs
+++ b/talpid_core/src/tunnel/openvpn.rs
@@ -1,8 +1,121 @@
use jsonrpc_core::{Error, IoHandler};
use openvpn_ffi;
+use process::monitor::ChildMonitor;
+use process::openvpn::OpenVpnCommand;
+use std::io;
+
+use std::path::{Path, PathBuf};
+use std::process;
+use std::result::Result as StdResult;
+use std::sync::{Arc, Mutex};
use talpid_ipc;
+mod errors {
+ error_chain!{
+ errors {
+ /// The `OpenVpnMonitor` is in an invalid state for the requested operation.
+ InvalidState {
+ description("Invalid state. OpenVPN is already running")
+ }
+ /// Unable to start or kill the OpenVPN process.
+ ChildProcessError {
+ description("Unable to start or kill the OpenVPN process")
+ }
+ /// Unable to start or manage the IPC server listening for events from OpenVPN
+ IpcServerError {
+ description("Unable to start or manage the IPC server")
+ }
+ }
+ }
+}
+pub use self::errors::*;
+
+
+/// Possible events from OpenVPN
+pub enum OpenVpnEvent {
+ /// An event from the plugin loaded into OpenVPN.
+ PluginEvent(openvpn_ffi::OpenVpnPluginEvent, openvpn_ffi::OpenVpnEnv),
+ /// The OpenVPN process exited. Containing the result of waiting for the process.
+ Shutdown(io::Result<process::ExitStatus>),
+}
+
+/// Struct for monitoring OpenVPN processes.
+pub struct OpenVpnMonitor {
+ on_event: Arc<Fn(OpenVpnEvent) + Send + Sync + 'static>,
+ plugin_path: PathBuf,
+ child: Arc<Mutex<Option<ChildMonitor>>>,
+ event_dispatcher: OpenVpnEventDispatcher,
+}
+
+impl OpenVpnMonitor {
+ /// Creates a new `OpenVpnMonitor` with the given listener and using the plugin at the given
+ /// path.
+ pub fn new<L, P>(on_event: L, plugin_path: P) -> Result<Self>
+ where L: Fn(OpenVpnEvent) + Send + Sync + 'static,
+ P: AsRef<Path>
+ {
+ let on_event = Arc::new(on_event);
+ let event_dispatcher = Self::start_event_dispatcher(on_event.clone())?;
+ Ok(
+ OpenVpnMonitor {
+ on_event,
+ plugin_path: plugin_path.as_ref().to_owned(),
+ child: Arc::new(Mutex::new(None)),
+ event_dispatcher,
+ },
+ )
+ }
+
+ fn start_event_dispatcher(on_event: Arc<Fn(OpenVpnEvent) + Send + Sync + 'static>)
+ -> Result<OpenVpnEventDispatcher> {
+ let on_plugin_event = move |event, env| (*on_event)(OpenVpnEvent::PluginEvent(event, env));
+ OpenVpnEventDispatcher::start(on_plugin_event).chain_err(|| ErrorKind::IpcServerError)
+ }
+
+ /// Tries to start a new OpenVPN process if one is not already running.
+ /// If this `OpenVpnMonitor is already monitoring a running process it will return an
+ /// `InvalidState` error.
+ pub fn start(&self, cmd: OpenVpnCommand) -> Result<()> {
+ let mut child_lock = self.child.lock().unwrap();
+ if child_lock.is_some() {
+ bail!(ErrorKind::InvalidState);
+ }
+ *child_lock = Some(self.start_child_monitor(cmd)?);
+ Ok(())
+ }
+
+ fn start_child_monitor(&self, mut cmd: OpenVpnCommand) -> Result<ChildMonitor> {
+ self.set_plugin(&mut cmd);
+
+ let child = self.child.clone();
+ let on_event = self.on_event.clone();
+
+ let on_exit = move |exit_status: io::Result<&process::Output>| {
+ *child.lock().unwrap() = None;
+ (*on_event)(OpenVpnEvent::Shutdown(exit_status.map(|output| output.status)),)
+ };
+ ChildMonitor::start(&cmd.build(), on_exit).chain_err(|| ErrorKind::ChildProcessError)
+ }
+
+ fn set_plugin(&self, cmd: &mut OpenVpnCommand) {
+ let event_dispatcher_address = self.event_dispatcher.address().to_string();
+ cmd.plugin(&self.plugin_path, vec![event_dispatcher_address]);
+ }
+
+ /// Tries to kill the OpenVPN process if it is running. If it is already dead, this does
+ /// nothing.
+ pub fn kill(&self) -> Result<()> {
+ if let Some(ref child) = *self.child.lock().unwrap() {
+ child.kill().chain_err(|| ErrorKind::ChildProcessError)?;
+ }
+ Ok(())
+ }
+}
+
+
+
+
/// IPC server for listening to events coming from plugin loaded into OpenVPN.
pub struct OpenVpnEventDispatcher {
server: talpid_ipc::IpcServer,
@@ -41,7 +154,7 @@ mod api {
fn openvpn_event(&self,
openvpn_ffi::OpenVpnPluginEvent,
openvpn_ffi::OpenVpnEnv)
- -> Result<(), Error>;
+ -> StdResult<(), Error>;
}
}
}
@@ -59,7 +172,7 @@ impl<L> OpenVpnEventApi for OpenVpnEventApiImpl<L>
fn openvpn_event(&self,
event: openvpn_ffi::OpenVpnPluginEvent,
env: openvpn_ffi::OpenVpnEnv)
- -> Result<(), Error> {
+ -> StdResult<(), Error> {
debug!("OpenVPN event {:?}", event);
(self.on_event)(event, env);
Ok(())