diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-03-06 15:41:22 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-03-07 07:20:24 +0100 |
| commit | 155ac3f2c35908f0071bb2ee7e3d8879a2cc8f66 (patch) | |
| tree | 19e7aa49718cb40e63aac2732326b7ea2c8127ff /src | |
| parent | 6fbf16b682fe6c399e5c7f5d5f4a8f96a5071093 (diff) | |
| download | mullvadvpn-155ac3f2c35908f0071bb2ee7e3d8879a2cc8f66.tar.xz mullvadvpn-155ac3f2c35908f0071bb2ee7e3d8879a2cc8f66.zip | |
Add initial OpenVpnMonitor
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 2 | ||||
| -rw-r--r-- | src/process/openvpn.rs | 81 |
2 files changed, 81 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..c02d6b5bf1 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,67 @@ 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 indicate if the process exited cleanly. + Shutdown(bool), +} + +/// A struct able to start and monitor OpenVPN procesess. +pub struct OpenVpnMonitor { + command: OpenVpnCommand, + monitor: Option<ChildMonitor<OpenVpnCommand>>, +} + +impl OpenVpnMonitor { + /// Creates a new `OpenVpnMonitor` based on the given command + pub fn new(command: OpenVpnCommand) -> Self { + OpenVpnMonitor { + command: command, + monitor: None, + } + } + + /// 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 = Some(ChildMonitor::new(self.command.clone())); + Ok(self.monitor.as_mut().unwrap().start(callback)?) + } +} + + #[cfg(test)] mod tests { use super::OpenVpnCommand; |
