summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-03-05 18:53:44 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-03-09 10:44:48 -0300
commitdeefd4c50fe7e9eeab0c024bc2bfba9ae0c485b8 (patch)
tree98257f88e6d0a94e004faa8d14eb0277f65cda73
parent19c201146b2f22db13123f47d7bb042991051583 (diff)
downloadmullvadvpn-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.rs8
-rw-r--r--mullvad-daemon/src/rpc_info.rs49
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)