diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-03-05 18:53:44 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-03-09 10:44:48 -0300 |
| commit | deefd4c50fe7e9eeab0c024bc2bfba9ae0c485b8 (patch) | |
| tree | 98257f88e6d0a94e004faa8d14eb0277f65cda73 | |
| parent | 19c201146b2f22db13123f47d7bb042991051583 (diff) | |
| download | mullvadvpn-deefd4c50fe7e9eeab0c024bc2bfba9ae0c485b8.tar.xz mullvadvpn-deefd4c50fe7e9eeab0c024bc2bfba9ae0c485b8.zip | |
Only run one instance of daemon
Before the RPC server is started, check if there is already another
instance of the daemon running. If there is, and it appears to be
responding correctly, don't start the daemon again.
| -rw-r--r-- | mullvad-daemon/src/main.rs | 8 | ||||
| -rw-r--r-- | mullvad-daemon/src/rpc_info.rs | 49 |
2 files changed, 56 insertions, 1 deletions
diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs index 50fc5d1991..f07138b8ff 100644 --- a/mullvad-daemon/src/main.rs +++ b/mullvad-daemon/src/main.rs @@ -84,6 +84,9 @@ use std::fs; error_chain!{ errors { + DaemonIsAlreadyRunning { + description("Another instance of the daemon is already running") + } /// The client is in the wrong state for the requested operation. Optimally the code should /// be written in such a way so such states can't exist. InvalidState { @@ -284,6 +287,11 @@ impl Daemon { event_tx: IntoSender<TunnelCommand, DaemonEvent>, require_auth: bool, ) -> Result<ManagementInterfaceServer> { + ensure!( + !rpc_info::is_another_instance_running(), + ErrorKind::DaemonIsAlreadyRunning + ); + let shared_secret = if require_auth { Some(uuid::Uuid::new_v4().to_string()) } else { diff --git a/mullvad-daemon/src/rpc_info.rs b/mullvad-daemon/src/rpc_info.rs index b5b35fa8f7..71c551d0db 100644 --- a/mullvad-daemon/src/rpc_info.rs +++ b/mullvad-daemon/src/rpc_info.rs @@ -1,6 +1,10 @@ use std::fs::{self, File, OpenOptions}; -use std::io::{self, Write}; +use std::io::{self, BufRead, BufReader, Write}; use std::path::{Path, PathBuf}; +use std::result; + +use mullvad_types::states::DaemonState; +use talpid_ipc::WsIpcClient; error_chain! { errors { @@ -28,8 +32,21 @@ lazy_static! { } +/// Checks if there is another instance of the daemon running. +/// +/// Tries to connect to another daemon and perform a simple RPC call. If it fails, assumes the +/// other daemon has stopped. +pub fn is_another_instance_running() -> bool { + let rpc_file_exists = RPC_ADDRESS_FILE_PATH.as_path().exists(); + + rpc_file_exists && other_daemon_responds() +} + /// Writes down the RPC connection info to some API to a file. pub fn write(rpc_address: &str, shared_secret: &str) -> Result<()> { + // Remove any existent RPC address file first + let _ = remove(); + open_file(RPC_ADDRESS_FILE_PATH.as_path()) .and_then(|mut file| write!(file, "{}\n{}\n", rpc_address, shared_secret)) .chain_err(|| ErrorKind::WriteFailed(RPC_ADDRESS_FILE_PATH.to_owned()))?; @@ -46,6 +63,36 @@ pub fn remove() -> Result<()> { .chain_err(|| ErrorKind::RemoveFailed(RPC_ADDRESS_FILE_PATH.to_owned())) } +fn other_daemon_responds() -> bool { + if let Err(message) = call_other_daemon() { + info!("{}; assuming it has stopped", message); + false + } else { + true + } +} + +fn call_other_daemon() -> result::Result<(), String> { + let method = "get_state"; + let args: [u8; 0] = []; + let address = read_rpc_file().map_err(|_| "Failed to read RPC address file of other daemon")?; + // TODO: Authenticate with server + let mut rpc_client = + WsIpcClient::new(address).map_err(|_| "Failed to connect to other daemon")?; + let _: DaemonState = rpc_client + .call(method, &args) + .map_err(|_| "Failed to execute RPC call to other daemon")?; + Ok(()) +} + +fn read_rpc_file() -> io::Result<String> { + let file = File::open(RPC_ADDRESS_FILE_PATH.as_path())?; + let mut reader = BufReader::new(file); + let mut address = String::new(); + reader.read_line(&mut address)?; + Ok(address) +} + fn open_file(path: &Path) -> io::Result<File> { let file = OpenOptions::new() .write(true) |
