diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-03-07 08:41:29 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-03-07 08:41:29 +0100 |
| commit | f085642d25c2f91095ce01d324a59b5cee23e8b0 (patch) | |
| tree | 663b6c7e56f1e561ae90275746eb12d1387cbab3 /src | |
| parent | 6fbf16b682fe6c399e5c7f5d5f4a8f96a5071093 (diff) | |
| parent | e878b14618f56b106f42df417582a7468f12c9b8 (diff) | |
| download | mullvadvpn-f085642d25c2f91095ce01d324a59b5cee23e8b0.tar.xz mullvadvpn-f085642d25c2f91095ce01d324a59b5cee23e8b0.zip | |
Merge branch 'openvpn-monitor'
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 2 | ||||
| -rw-r--r-- | src/process/openvpn.rs | 86 |
2 files changed, 86 insertions, 2 deletions
diff --git a/src/lib.rs b/src/lib.rs index f8e5e96a46..00c4061801 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,8 @@ extern crate clonablechild; #[macro_use] extern crate error_chain; +extern crate talpid_ipc; + /// Working with processes. pub mod process; diff --git a/src/process/openvpn.rs b/src/process/openvpn.rs index 65f87064ff..2d25deb965 100644 --- a/src/process/openvpn.rs +++ b/src/process/openvpn.rs @@ -1,14 +1,30 @@ -use super::monitor::ChildSpawner; +use super::monitor::{ChildSpawner, ChildMonitor}; use clonablechild::{ClonableChild, ChildExt}; use net::{RemoteAddr, ToRemoteAddrs}; +use std::collections::HashMap; use std::ffi::{OsString, OsStr}; use std::fmt; use std::io; +use std::ops::DerefMut; use std::path::{Path, PathBuf}; -use std::process::{Command, Child, Stdio}; +use std::process::{Command, Child, Stdio, ChildStdout, ChildStderr}; +use std::sync::{Arc, Mutex}; + +use talpid_ipc; + +error_chain!{ + errors { + /// Error while communicating with the OpenVPN plugin + PluginCommunicationError + } + links { + ChildMonitorError(::process::monitor::Error, ::process::monitor::ErrorKind) + #[doc="Something went wrong in the underlying ChildMonitor"]; + } +} /// An OpenVPN process builder, providing control over the different arguments that the OpenVPN /// binary accepts. @@ -141,6 +157,72 @@ impl ChildSpawner for OpenVpnCommand { } +/// Possible events from OpenVPN +pub enum OpenVpnEvent { + /// An event from the plugin loaded into OpenVPN. + PluginEvent(Result<HashMap<String, String>>), + /// The OpenVPN process exited. The bool indicates if the process exited cleanly. + Shutdown(bool), +} + +/// A struct able to start and monitor OpenVPN processes. +pub struct OpenVpnMonitor { + command: OpenVpnCommand, + monitor: ChildMonitor<OpenVpnCommand>, +} + +impl OpenVpnMonitor { + /// Creates a new `OpenVpnMonitor` based on the given command + pub fn new(command: OpenVpnCommand) -> Self { + OpenVpnMonitor { + command: command.clone(), + monitor: ChildMonitor::new(command), + } + } + + /// Starts OpenVPN and begins to monitor it. + pub fn start<L>(&mut self, listener: L) -> Result<(Option<ChildStdout>, Option<ChildStderr>)> + where L: FnMut(OpenVpnEvent) + Send + 'static + { + let shared_listener = Arc::new(Mutex::new(listener)); + self.start_plugin_listener(shared_listener.clone())?; + self.start_child_monitor(shared_listener) + } + + fn start_plugin_listener<L>(&mut self, shared_listener: Arc<Mutex<L>>) -> Result<()> + where L: FnMut(OpenVpnEvent) + Send + 'static + { + let server_id = talpid_ipc::start_new_server(move |msg| { + let chained_msg = msg.chain_err(|| ErrorKind::PluginCommunicationError); + let mut listener = shared_listener.lock().unwrap(); + (listener.deref_mut())(OpenVpnEvent::PluginEvent(chained_msg)); + }).chain_err(|| ErrorKind::PluginCommunicationError)?; + self.command.plugin("./target/debug/libtalpid_openvpn_plugin.so", + vec![server_id]); + Ok(()) + } + + fn start_child_monitor<L>(&mut self, + shared_listener: Arc<Mutex<L>>) + -> Result<(Option<ChildStdout>, Option<ChildStderr>)> + where L: FnMut(OpenVpnEvent) + Send + 'static + { + let callback = move |clean_exit| { + let mut listener = shared_listener.lock().unwrap(); + (listener.deref_mut())(OpenVpnEvent::Shutdown(clean_exit)); + }; + + self.monitor = ChildMonitor::new(self.command.clone()); + Ok(self.monitor.start(callback)?) + } + + /// Forwards a stop call to the underlying `ChildMonitor`. + pub fn stop(&self) -> Result<()> { + Ok(self.monitor.stop()?) + } +} + + #[cfg(test)] mod tests { use super::OpenVpnCommand; |
