diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-01-28 13:28:44 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-01-28 13:28:44 +0100 |
| commit | e0b5655614cf2b65cffd136b22106e547b15fb7c (patch) | |
| tree | 64c9fde6bc58b6ee2294c6e49e5b288f8dcc5ba4 | |
| parent | 115099777c1ca93048cf46ef5cfbb253475bc573 (diff) | |
| parent | b0e5a1ec09dae40501c6ef4450852436020b86f8 (diff) | |
| download | mullvadvpn-e0b5655614cf2b65cffd136b22106e547b15fb7c.tar.xz mullvadvpn-e0b5655614cf2b65cffd136b22106e547b15fb7c.zip | |
Merge branch 'improve-ipc-errors'
| -rw-r--r-- | mullvad-cli/src/cmds/account.rs | 5 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/bridge.rs | 8 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/relay.rs | 10 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/reset.rs | 13 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/status.rs | 2 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/tunnel.rs | 8 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/version.rs | 14 | ||||
| -rw-r--r-- | mullvad-cli/src/main.rs | 25 | ||||
| -rw-r--r-- | mullvad-cli/src/state.rs | 4 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 410 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 277 | ||||
| -rw-r--r-- | mullvad-jni/src/daemon_interface.rs | 62 |
12 files changed, 540 insertions, 298 deletions
diff --git a/mullvad-cli/src/cmds/account.rs b/mullvad-cli/src/cmds/account.rs index f68e2a12eb..0dba7600ce 100644 --- a/mullvad-cli/src/cmds/account.rs +++ b/mullvad-cli/src/cmds/account.rs @@ -91,7 +91,8 @@ impl Account { println!("Mullvad account: {}", settings.account_token); let expiry = rpc .get_account_data(settings.account_token) - .await? + .await + .map_err(|error| Error::RpcFailedExt("Failed to fetch account data", error))? .into_inner(); println!( "Expires at : {}", @@ -132,7 +133,7 @@ impl Account { Code::NotFound | Code::ResourceExhausted => { eprintln!("Failed to submit voucher: {}", err.message()); } - _ => return Err(Error::GrpcClientError(err)), + _ => return Err(Error::RpcFailed(err)), } std::process::exit(1); } diff --git a/mullvad-cli/src/cmds/bridge.rs b/mullvad-cli/src/cmds/bridge.rs index 4bb85b4060..9a674069a8 100644 --- a/mullvad-cli/src/cmds/bridge.rs +++ b/mullvad-cli/src/cmds/bridge.rs @@ -1,4 +1,4 @@ -use crate::{location, new_rpc_client, Command, Result}; +use crate::{location, new_rpc_client, Command, Error, Result}; use clap::value_t; use mullvad_management_interface::types::{ @@ -404,7 +404,11 @@ impl Bridge { async fn list_bridge_relays() -> Result<()> { let mut rpc = new_rpc_client().await?; - let mut locations = rpc.get_relay_locations(()).await?.into_inner(); + let mut locations = rpc + .get_relay_locations(()) + .await + .map_err(|error| Error::RpcFailedExt("Failed to obtain relay locations", error))? + .into_inner(); let mut countries = Vec::new(); diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs index ab1ea41fe1..e8783e04f3 100644 --- a/mullvad-cli/src/cmds/relay.rs +++ b/mullvad-cli/src/cmds/relay.rs @@ -193,7 +193,9 @@ impl Command for Relay { impl Relay { async fn update_constraints(&self, update: RelaySettingsUpdate) -> Result<()> { let mut rpc = new_rpc_client().await?; - rpc.update_relay_settings(update).await?; + rpc.update_relay_settings(update) + .await + .map_err(|error| Error::RpcFailedExt("Failed to update relay settings", error))?; println!("Relay constraints updated"); Ok(()) } @@ -680,7 +682,11 @@ impl Relay { async fn get_filtered_relays() -> Result<Vec<RelayListCountry>> { let mut rpc = new_rpc_client().await?; - let mut locations = rpc.get_relay_locations(()).await?.into_inner(); + let mut locations = rpc + .get_relay_locations(()) + .await + .map_err(|error| Error::RpcFailedExt("Failed to obtain relay locations", error))? + .into_inner(); let mut countries = Vec::new(); diff --git a/mullvad-cli/src/cmds/reset.rs b/mullvad-cli/src/cmds/reset.rs index bb10a3f0fe..1be34a0ab0 100644 --- a/mullvad-cli/src/cmds/reset.rs +++ b/mullvad-cli/src/cmds/reset.rs @@ -1,4 +1,4 @@ -use crate::{new_rpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Error, Result}; use std::io::stdin; pub struct Reset; @@ -15,12 +15,11 @@ impl Command for Reset { async fn run(&self, _: &clap::ArgMatches<'_>) -> Result<()> { let mut rpc = new_rpc_client().await?; if Self::receive_confirmation() { - if rpc.factory_reset(()).await.is_err() { - eprintln!("FAILED TO PERFORM FACTORY RESET"); - } else { - #[cfg(target_os = "linux")] - println!("If you're running systemd, to remove all logs, you must use journalctl"); - } + rpc.factory_reset(()) + .await + .map_err(|error| Error::RpcFailedExt("FAILED TO PERFORM FACTORY RESET", error))?; + #[cfg(target_os = "linux")] + println!("If you're running systemd, to remove all logs, you must use journalctl"); } Ok(()) } diff --git a/mullvad-cli/src/cmds/status.rs b/mullvad-cli/src/cmds/status.rs index 76a4ed2e67..f4e943cb3c 100644 --- a/mullvad-cli/src/cmds/status.rs +++ b/mullvad-cli/src/cmds/status.rs @@ -97,7 +97,7 @@ async fn print_location(rpc: &mut ManagementServiceClient) -> Result<()> { println!("Location data unavailable"); return Ok(()); } else { - return Err(Error::GrpcClientError(status)); + return Err(Error::RpcFailed(status)); } } }; diff --git a/mullvad-cli/src/cmds/tunnel.rs b/mullvad-cli/src/cmds/tunnel.rs index 53a329af13..4af0864ddf 100644 --- a/mullvad-cli/src/cmds/tunnel.rs +++ b/mullvad-cli/src/cmds/tunnel.rs @@ -187,7 +187,7 @@ impl Tunnel { if status.code() == mullvad_management_interface::Code::NotFound { None } else { - return Err(Error::GrpcClientError(status)); + return Err(Error::RpcFailedExt("Failed to obtain key", status)); } } }; @@ -202,7 +202,11 @@ impl Tunnel { return Ok(()); } - let is_valid = rpc.verify_wireguard_key(()).await?.into_inner(); + let is_valid = rpc + .verify_wireguard_key(()) + .await + .map_err(|error| Error::RpcFailedExt("Failed to verify key", error))? + .into_inner(); println!("Key is valid for use with current account: {}", is_valid); Ok(()) } diff --git a/mullvad-cli/src/cmds/version.rs b/mullvad-cli/src/cmds/version.rs index 06855212bf..08944f921b 100644 --- a/mullvad-cli/src/cmds/version.rs +++ b/mullvad-cli/src/cmds/version.rs @@ -1,4 +1,4 @@ -use crate::{new_rpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Error, Result}; pub struct Version; @@ -15,9 +15,17 @@ impl Command for Version { async fn run(&self, _: &clap::ArgMatches<'_>) -> Result<()> { let mut rpc = new_rpc_client().await?; - let current_version = rpc.get_current_version(()).await?.into_inner(); + let current_version = rpc + .get_current_version(()) + .await + .map_err(|error| Error::RpcFailedExt("Failed to obtain current version", error))? + .into_inner(); println!("Current version: {}", current_version); - let version_info = rpc.get_version_info(()).await?.into_inner(); + let version_info = rpc + .get_version_info(()) + .await + .map_err(|error| Error::RpcFailedExt("Failed to obtain version info", error))? + .into_inner(); println!("\tIs supported: {}", version_info.supported); if !version_info.suggested_upgrade.is_empty() { diff --git a/mullvad-cli/src/main.rs b/mullvad-cli/src/main.rs index 7f93e17222..20dfae5fc9 100644 --- a/mullvad-cli/src/main.rs +++ b/mullvad-cli/src/main.rs @@ -25,8 +25,14 @@ pub enum Error { #[error(display = "Management interface error")] ManagementInterfaceError(#[error(source)] mullvad_management_interface::Error), - #[error(display = "Failed to communicate with mullvad-daemon over RPC")] - GrpcClientError(#[error(source)] mullvad_management_interface::Status), + #[error(display = "RPC failed")] + RpcFailed(#[error(source)] mullvad_management_interface::Status), + + #[error(display = "RPC failed: {}", _0)] + RpcFailedExt( + &'static str, + #[error(source)] mullvad_management_interface::Status, + ), /// The given command is not correct in some way #[error(display = "Invalid command: {}", _0)] @@ -44,7 +50,20 @@ async fn main() { let exit_code = match run().await { Ok(_) => 0, Err(error) => { - eprintln!("{}", error.display_chain()); + match &error { + Error::RpcFailed(status) => { + eprintln!("{}: {:?}: {}", error, status.code(), status.message()) + } + Error::RpcFailedExt(_message, status) => { + eprintln!( + "{}\nCaused by: {:?}: {}", + error, + status.code(), + status.message() + ) + } + error => eprintln!("{}", error.display_chain()), + } 1 } }; diff --git a/mullvad-cli/src/state.rs b/mullvad-cli/src/state.rs index 9890218545..4cf826214f 100644 --- a/mullvad-cli/src/state.rs +++ b/mullvad-cli/src/state.rs @@ -23,7 +23,7 @@ pub fn state_listen(mut rpc: ManagementServiceClient) -> Receiver<Result<TunnelS _ => continue, }, Ok(None) => break, - Err(status) => Err(Error::GrpcClientError(status)), + Err(status) => Err(Error::RpcFailed(status)), }; if let Err(_) = sender.send(forward).await { @@ -32,7 +32,7 @@ pub fn state_listen(mut rpc: ManagementServiceClient) -> Receiver<Result<TunnelS } } Err(status) => { - let _ = sender.send(Err(Error::GrpcClientError(status))).await; + let _ = sender.send(Err(Error::RpcFailed(status))).await; } } }); diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 42f067a4f3..691e96cd5b 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -82,6 +82,8 @@ const FIRST_KEY_PUSH_TIMEOUT: Duration = Duration::from_secs(5); /// Delay between generating a new WireGuard key and reconnecting const WG_RECONNECT_DELAY: Duration = Duration::from_secs(30); +pub type ResponseTx<T, E> = oneshot::Sender<Result<T, E>>; + #[derive(err_derive::Error, Debug)] #[error(no_from)] pub enum Error { @@ -94,6 +96,9 @@ pub enum Error { #[error(display = "Unable to create RPC client")] InitRpcFactory(#[error(source)] mullvad_rpc::Error), + #[error(display = "REST request failed")] + RestError(#[error(source)] mullvad_rpc::rest::Error), + #[error(display = "Unable to load account history with wireguard key cache")] LoadAccountHistory(#[error(source)] account_history::Error), @@ -107,9 +112,30 @@ pub enum Error { #[error(display = "No bridge available")] NoBridgeAvailable, - #[error(display = "Account history problems")] + #[error(display = "No account token is set")] + NoAccountToken, + + #[error(display = "No account history available for the token")] + NoAccountTokenHistory, + + #[error(display = "Settings error")] + SettingsError(#[error(source)] settings::Error), + + #[error(display = "Account history error")] AccountHistory(#[error(source)] account_history::Error), + #[error(display = "Failed to clear cache directory")] + ClearCacheError, + + #[error(display = "Failed to clear logs directory")] + ClearLogsError, + + #[error(display = "Failed to clear account history")] + ClearAccountHistoryError(#[error(source)] account_history::Error), + + #[error(display = "Failed to clear settings")] + ClearSettingsError(#[error(source)] settings::Error), + #[error(display = "Tunnel state machine error")] TunnelError(#[error(source)] tunnel_state_machine::Error), @@ -151,83 +177,80 @@ pub enum DaemonCommand { GetState(oneshot::Sender<TunnelState>), /// Get the current geographical location. GetCurrentLocation(oneshot::Sender<Option<GeoIpLocation>>), - CreateNewAccount(oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>), + CreateNewAccount(ResponseTx<String, Error>), /// Request the metadata for an account. GetAccountData( - oneshot::Sender<Result<AccountData, mullvad_rpc::rest::Error>>, + ResponseTx<AccountData, mullvad_rpc::rest::Error>, AccountToken, ), /// Request www auth token for an account - GetWwwAuthToken(oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>), + GetWwwAuthToken(ResponseTx<String, Error>), /// Submit voucher to add time to the current account. Returns time added in seconds - SubmitVoucher( - oneshot::Sender<Result<VoucherSubmission, mullvad_rpc::rest::Error>>, - String, - ), + SubmitVoucher(ResponseTx<VoucherSubmission, Error>, String), /// Request account history GetAccountHistory(oneshot::Sender<Vec<AccountToken>>), /// Request account history - RemoveAccountFromHistory(oneshot::Sender<()>, AccountToken), + RemoveAccountFromHistory(ResponseTx<(), Error>, AccountToken), /// Clear account history - ClearAccountHistory(oneshot::Sender<()>), + ClearAccountHistory(ResponseTx<(), Error>), /// Get the list of countries and cities where there are relays. GetRelayLocations(oneshot::Sender<RelayList>), /// Trigger an asynchronous relay list update. This returns before the relay list is actually /// updated. UpdateRelayLocations, /// Set which account token to use for subsequent connection attempts. - SetAccount(oneshot::Sender<()>, Option<AccountToken>), + SetAccount(ResponseTx<(), settings::Error>, Option<AccountToken>), /// Place constraints on the type of tunnel and relay - UpdateRelaySettings(oneshot::Sender<()>, RelaySettingsUpdate), + UpdateRelaySettings(ResponseTx<(), settings::Error>, RelaySettingsUpdate), /// Set the allow LAN setting. - SetAllowLan(oneshot::Sender<()>, bool), + SetAllowLan(ResponseTx<(), settings::Error>, bool), /// Set the beta program setting. - SetShowBetaReleases(oneshot::Sender<()>, bool), + SetShowBetaReleases(ResponseTx<(), settings::Error>, bool), /// Set the block_when_disconnected setting. - SetBlockWhenDisconnected(oneshot::Sender<()>, bool), + SetBlockWhenDisconnected(ResponseTx<(), settings::Error>, bool), /// Set the auto-connect setting. - SetAutoConnect(oneshot::Sender<()>, bool), + SetAutoConnect(ResponseTx<(), settings::Error>, bool), /// Set the mssfix argument for OpenVPN - SetOpenVpnMssfix(oneshot::Sender<()>, Option<u16>), + SetOpenVpnMssfix(ResponseTx<(), settings::Error>, Option<u16>), /// Set proxy details for OpenVPN - SetBridgeSettings(oneshot::Sender<Result<(), settings::Error>>, BridgeSettings), + SetBridgeSettings(ResponseTx<(), settings::Error>, BridgeSettings), /// Set proxy state - SetBridgeState(oneshot::Sender<Result<(), settings::Error>>, BridgeState), + SetBridgeState(ResponseTx<(), settings::Error>, BridgeState), /// Set if IPv6 should be enabled in the tunnel - SetEnableIpv6(oneshot::Sender<()>, bool), + SetEnableIpv6(ResponseTx<(), settings::Error>, bool), /// Set custom DNS servers to use instead of passing requests to the gateway - SetDnsOptions(oneshot::Sender<()>, DnsOptions), + SetDnsOptions(ResponseTx<(), settings::Error>, DnsOptions), /// Set MTU for wireguard tunnels - SetWireguardMtu(oneshot::Sender<()>, Option<u16>), + SetWireguardMtu(ResponseTx<(), settings::Error>, Option<u16>), /// Set automatic key rotation interval for wireguard tunnels - SetWireguardRotationInterval(oneshot::Sender<()>, Option<u32>), + SetWireguardRotationInterval(ResponseTx<(), settings::Error>, Option<u32>), /// Get the daemon settings GetSettings(oneshot::Sender<Settings>), /// Generate new wireguard key - GenerateWireguardKey(oneshot::Sender<wireguard::KeygenEvent>), + GenerateWireguardKey(ResponseTx<wireguard::KeygenEvent, Error>), /// Return a public key of the currently set wireguard private key, if there is one - GetWireguardKey(oneshot::Sender<Option<wireguard::PublicKey>>), + GetWireguardKey(ResponseTx<Option<wireguard::PublicKey>, Error>), /// Verify if the currently set wireguard key is valid. - VerifyWireguardKey(oneshot::Sender<bool>), + VerifyWireguardKey(ResponseTx<bool, Error>), /// Get information about the currently running and latest app versions GetVersionInfo(oneshot::Sender<Option<AppVersionInfo>>), /// Get current version of the app GetCurrentVersion(oneshot::Sender<AppVersion>), /// Remove settings and clear the cache #[cfg(not(target_os = "android"))] - FactoryReset(oneshot::Sender<()>), + FactoryReset(ResponseTx<(), Error>), /// Request list of processes excluded from the tunnel #[cfg(target_os = "linux")] - GetSplitTunnelProcesses(oneshot::Sender<Vec<i32>>), + GetSplitTunnelProcesses(ResponseTx<Vec<i32>, split_tunnel::Error>), /// Exclude traffic of a process (PID) from the tunnel #[cfg(target_os = "linux")] - AddSplitTunnelProcess(oneshot::Sender<()>, i32), + AddSplitTunnelProcess(ResponseTx<(), split_tunnel::Error>, i32), /// Remove process (PID) from list of processes excluded from the tunnel #[cfg(target_os = "linux")] - RemoveSplitTunnelProcess(oneshot::Sender<()>, i32), + RemoveSplitTunnelProcess(ResponseTx<(), split_tunnel::Error>, i32), /// Clear list of processes excluded from the tunnel #[cfg(target_os = "linux")] - ClearSplitTunnelProcesses(oneshot::Sender<()>), + ClearSplitTunnelProcesses(ResponseTx<(), split_tunnel::Error>), /// Makes the daemon exit the main loop and quit. Shutdown, /// Saves the target tunnel state and enters a blocking state. The state is restored @@ -258,10 +281,7 @@ pub(crate) enum InternalDaemonEvent { ), ), /// New Account created - NewAccountEvent( - AccountToken, - oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>, - ), + NewAccountEvent(AccountToken, oneshot::Sender<Result<String, Error>>), /// The background job fetching new `AppVersionInfo`s got a new info object. NewAppVersionInfo(AppVersionInfo), } @@ -1220,7 +1240,7 @@ where async fn handle_new_account_event( &mut self, new_token: AccountToken, - tx: oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>, + tx: ResponseTx<String, Error>, ) { match self.set_account(Some(new_token.clone())).await { Ok(_) => { @@ -1228,7 +1248,11 @@ where let _ = tx.send(Ok(new_token)); } Err(err) => { - log::error!("Failed to save new account - {}", err); + log::error!( + "{}", + err.display_chain_with_msg("Failed to save new account") + ); + let _ = tx.send(Err(Error::SettingsError(err))); } }; } @@ -1333,10 +1357,7 @@ where }) } - async fn on_create_new_account( - &mut self, - tx: oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>, - ) { + async fn on_create_new_account(&mut self, tx: ResponseTx<String, Error>) { let daemon_tx = self.tx.clone(); let future = self.accounts_proxy.create_account(); @@ -1346,7 +1367,7 @@ where let _ = daemon_tx.send(InternalDaemonEvent::NewAccountEvent(account_token, tx)); } Err(err) => { - let _ = tx.send(Err(err)); + let _ = tx.send(Err(Error::RestError(err))); } } }); @@ -1354,7 +1375,7 @@ where async fn on_get_account_data( &mut self, - tx: oneshot::Sender<Result<AccountData, mullvad_rpc::rest::Error>>, + tx: ResponseTx<AccountData, mullvad_rpc::rest::Error>, account_token: AccountToken, ) { let expiry_fut = self.accounts_proxy.get_expiry(account_token); @@ -1365,30 +1386,43 @@ where tokio::spawn(rpc_call); } - async fn on_get_www_auth_token( - &mut self, - tx: oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>, - ) { + async fn on_get_www_auth_token(&mut self, tx: ResponseTx<String, Error>) { if let Some(account_token) = self.settings.get_account_token() { let future = self.accounts_proxy.get_www_auth_token(account_token); let rpc_call = async { - Self::oneshot_send(tx, future.await, "get_www_auth_token response"); + Self::oneshot_send( + tx, + future.await.map_err(Error::RestError), + "get_www_auth_token response", + ); }; tokio::spawn(rpc_call); + } else { + Self::oneshot_send( + tx, + Err(Error::NoAccountToken), + "get_www_auth_token response", + ); } } async fn on_submit_voucher( &mut self, - tx: oneshot::Sender<Result<VoucherSubmission, mullvad_rpc::rest::Error>>, + tx: ResponseTx<VoucherSubmission, Error>, voucher: String, ) { if let Some(account_token) = self.settings.get_account_token() { let future = self.accounts_proxy.submit_voucher(account_token, voucher); let rpc_call = async { - Self::oneshot_send(tx, future.await, "submit_voucher response"); + Self::oneshot_send( + tx, + future.await.map_err(Error::RestError), + "submit_voucher response", + ); }; tokio::spawn(rpc_call); + } else { + Self::oneshot_send(tx, Err(Error::NoAccountToken), "submit_voucher response"); } } @@ -1400,7 +1434,11 @@ where self.relay_selector.update().await; } - async fn on_set_account(&mut self, tx: oneshot::Sender<()>, account_token: Option<String>) { + async fn on_set_account( + &mut self, + tx: ResponseTx<(), settings::Error>, + account_token: Option<String>, + ) { match self.set_account(account_token.clone()).await { Ok(account_changed) => { if account_changed { @@ -1415,10 +1453,11 @@ where } }; } - Self::oneshot_send(tx, (), "set_account response"); + Self::oneshot_send(tx, Ok(()), "set_account response"); } - Err(e) => { - log::error!("Failed to set account - {}", e); + Err(error) => { + log::error!("{}", error.display_chain_with_msg("Failed to set account")); + Self::oneshot_send(tx, Err(error), "set_account response"); } } } @@ -1454,29 +1493,34 @@ where async fn on_remove_account_from_history( &mut self, - tx: oneshot::Sender<()>, + tx: ResponseTx<(), Error>, account_token: AccountToken, ) { - if self + let result = self .account_history .remove_account(&account_token) .await - .is_ok() - { - Self::oneshot_send(tx, (), "remove_account_from_history response"); - } + .map_err(Error::AccountHistory); + Self::oneshot_send(tx, result, "remove_account_from_history response"); } - async fn on_clear_account_history(&mut self, tx: oneshot::Sender<()>) { + async fn on_clear_account_history(&mut self, tx: ResponseTx<(), Error>) { match self.account_history.clear().await { Ok(_) => { self.set_target_state(TargetState::Unsecured); - Self::oneshot_send(tx, (), "clear_account_history response"); + Self::oneshot_send(tx, Ok(()), "clear_account_history response"); + } + Err(err) => { + log::error!( + "{}", + err.display_chain_with_msg("Failed to clear account history") + ); + Self::oneshot_send( + tx, + Err(Error::AccountHistory(err)), + "clear_account_history response", + ); } - Err(err) => log::error!( - "{}", - err.display_chain_with_msg("Failed to clear account history") - ), } } @@ -1503,18 +1547,18 @@ where } #[cfg(not(target_os = "android"))] - async fn on_factory_reset(&mut self, tx: oneshot::Sender<()>) { - let mut failed = false; + async fn on_factory_reset(&mut self, tx: ResponseTx<(), Error>) { + let mut last_error = Ok(()); if let Err(e) = self.settings.reset() { log::error!("Failed to reset settings - {}", e); - failed = true; + last_error = Err(Error::ClearSettingsError(e)); } if let Err(e) = self.account_history.clear().await { log::error!("Failed to clear account history - {}", e); - failed = true; + last_error = Err(Error::ClearAccountHistoryError(e)); } // Shut the daemon down. @@ -1526,7 +1570,7 @@ where "{}", e.display_chain_with_msg("Failed to clear cache directory") ); - failed = true; + last_error = Err(Error::ClearCacheError); } if let Err(e) = Self::clear_log_directory() { @@ -1534,51 +1578,61 @@ where "{}", e.display_chain_with_msg("Failed to clear log directory") ); - failed = true; - } - if !failed { - Self::oneshot_send(tx, (), "factory_reset response"); + last_error = Err(Error::ClearLogsError); } + Self::oneshot_send(tx, last_error, "factory_reset response"); })); } #[cfg(target_os = "linux")] - fn on_get_split_tunnel_processes(&mut self, tx: oneshot::Sender<Vec<i32>>) { - match self.exclude_pids.list() { - Ok(pids) => Self::oneshot_send(tx, pids, "get_split_tunnel_processes response"), - Err(e) => error!("{}", e.display_chain_with_msg("Unable to obtain PIDs")), - } + fn on_get_split_tunnel_processes(&mut self, tx: ResponseTx<Vec<i32>, split_tunnel::Error>) { + let result = self.exclude_pids.list().map_err(|error| { + error!("{}", error.display_chain_with_msg("Unable to obtain PIDs")); + error + }); + Self::oneshot_send(tx, result, "get_split_tunnel_processes response"); } #[cfg(target_os = "linux")] - fn on_add_split_tunnel_process(&mut self, tx: oneshot::Sender<()>, pid: i32) { - match self.exclude_pids.add(pid) { - Ok(()) => Self::oneshot_send(tx, (), "add_split_tunnel_process response"), - Err(e) => error!("{}", e.display_chain_with_msg("Unable to add PID")), - } + fn on_add_split_tunnel_process(&mut self, tx: ResponseTx<(), split_tunnel::Error>, pid: i32) { + let result = self.exclude_pids.add(pid).map_err(|error| { + error!("{}", error.display_chain_with_msg("Unable to add PID")); + error + }); + Self::oneshot_send(tx, result, "add_split_tunnel_process response"); } #[cfg(target_os = "linux")] - fn on_remove_split_tunnel_process(&mut self, tx: oneshot::Sender<()>, pid: i32) { - match self.exclude_pids.remove(pid) { - Ok(()) => Self::oneshot_send(tx, (), "remove_split_tunnel_process response"), - Err(e) => error!("{}", e.display_chain_with_msg("Unable to remove PID")), - } + fn on_remove_split_tunnel_process( + &mut self, + tx: ResponseTx<(), split_tunnel::Error>, + pid: i32, + ) { + let result = self.exclude_pids.remove(pid).map_err(|error| { + error!("{}", error.display_chain_with_msg("Unable to remove PID")); + error + }); + Self::oneshot_send(tx, result, "remove_split_tunnel_process response"); } #[cfg(target_os = "linux")] - fn on_clear_split_tunnel_processes(&mut self, tx: oneshot::Sender<()>) { - match self.exclude_pids.clear() { - Ok(()) => Self::oneshot_send(tx, (), "clear_split_tunnel_processes response"), - Err(e) => error!("{}", e.display_chain_with_msg("Unable to clear PIDs")), - } + fn on_clear_split_tunnel_processes(&mut self, tx: ResponseTx<(), split_tunnel::Error>) { + let result = self.exclude_pids.clear().map_err(|error| { + error!("{}", error.display_chain_with_msg("Unable to clear PIDs")); + error + }); + Self::oneshot_send(tx, result, "clear_split_tunnel_processes response"); } - fn on_update_relay_settings(&mut self, tx: oneshot::Sender<()>, update: RelaySettingsUpdate) { + fn on_update_relay_settings( + &mut self, + tx: ResponseTx<(), settings::Error>, + update: RelaySettingsUpdate, + ) { let save_result = self.settings.update_relay_settings(update); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "update_relay_settings response"); + Self::oneshot_send(tx, Ok(()), "update_relay_settings response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1586,30 +1640,40 @@ where self.reconnect_tunnel(); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "update_relay_settings response"); + } } } - fn on_set_allow_lan(&mut self, tx: oneshot::Sender<()>, allow_lan: bool) { + fn on_set_allow_lan(&mut self, tx: ResponseTx<(), settings::Error>, allow_lan: bool) { let save_result = self.settings.set_allow_lan(allow_lan); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_allow_lan response"); + Self::oneshot_send(tx, Ok(()), "set_allow_lan response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); self.send_tunnel_command(TunnelCommand::AllowLan(allow_lan)); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_allow_lan response"); + } } } - async fn on_set_show_beta_releases(&mut self, tx: oneshot::Sender<()>, enabled: bool) { + async fn on_set_show_beta_releases( + &mut self, + tx: ResponseTx<(), settings::Error>, + enabled: bool, + ) { let save_result = self.settings.set_show_beta_releases(enabled); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_show_beta_releases response"); + Self::oneshot_send(tx, Ok(()), "set_show_beta_releases response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1617,13 +1681,16 @@ where handle.set_show_beta_releases(enabled).await; } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_show_beta_releases response"); + } } } fn on_set_block_when_disconnected( &mut self, - tx: oneshot::Sender<()>, + tx: ResponseTx<(), settings::Error>, block_when_disconnected: bool, ) { let save_result = self @@ -1631,7 +1698,7 @@ where .set_block_when_disconnected(block_when_disconnected); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_block_when_disconnected response"); + Self::oneshot_send(tx, Ok(()), "set_block_when_disconnected response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1640,29 +1707,39 @@ where )); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_block_when_disconnected response"); + } } } - fn on_set_auto_connect(&mut self, tx: oneshot::Sender<()>, auto_connect: bool) { + fn on_set_auto_connect(&mut self, tx: ResponseTx<(), settings::Error>, auto_connect: bool) { let save_result = self.settings.set_auto_connect(auto_connect); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set auto-connect response"); + Self::oneshot_send(tx, Ok(()), "set auto-connect response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set auto-connect response"); + } } } - fn on_set_openvpn_mssfix(&mut self, tx: oneshot::Sender<()>, mssfix_arg: Option<u16>) { + fn on_set_openvpn_mssfix( + &mut self, + tx: ResponseTx<(), settings::Error>, + mssfix_arg: Option<u16>, + ) { let save_result = self.settings.set_openvpn_mssfix(mssfix_arg); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_openvpn_mssfix response"); + Self::oneshot_send(tx, Ok(()), "set_openvpn_mssfix response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1674,13 +1751,16 @@ where } } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_openvpn_mssfix response"); + } } } fn on_set_bridge_settings( &mut self, - tx: oneshot::Sender<Result<(), settings::Error>>, + tx: ResponseTx<(), settings::Error>, new_settings: BridgeSettings, ) { match self.settings.set_bridge_settings(new_settings) { @@ -1705,7 +1785,7 @@ where fn on_set_bridge_state( &mut self, - tx: oneshot::Sender<Result<(), settings::Error>>, + tx: ResponseTx<(), settings::Error>, bridge_state: BridgeState, ) { let result = match self.settings.set_bridge_state(bridge_state) { @@ -1730,11 +1810,11 @@ where } - fn on_set_enable_ipv6(&mut self, tx: oneshot::Sender<()>, enable_ipv6: bool) { + fn on_set_enable_ipv6(&mut self, tx: ResponseTx<(), settings::Error>, enable_ipv6: bool) { let save_result = self.settings.set_enable_ipv6(enable_ipv6); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_enable_ipv6 response"); + Self::oneshot_send(tx, Ok(()), "set_enable_ipv6 response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1742,15 +1822,18 @@ where self.reconnect_tunnel(); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_enable_ipv6 response"); + } } } - fn on_set_dns_options(&mut self, tx: oneshot::Sender<()>, dns_options: DnsOptions) { + fn on_set_dns_options(&mut self, tx: ResponseTx<(), settings::Error>, dns_options: DnsOptions) { let save_result = self.settings.set_dns_options(dns_options.clone()); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_dns_options response"); + Self::oneshot_send(tx, Ok(()), "set_dns_options response"); if settings_changed { let settings = self.settings.to_settings(); let resolvers = @@ -1759,15 +1842,18 @@ where self.send_tunnel_command(TunnelCommand::CustomDns(resolvers)); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_dns_options response"); + } } } - fn on_set_wireguard_mtu(&mut self, tx: oneshot::Sender<()>, mtu: Option<u16>) { + fn on_set_wireguard_mtu(&mut self, tx: ResponseTx<(), settings::Error>, mtu: Option<u16>) { let save_result = self.settings.set_wireguard_mtu(mtu); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_wireguard_mtu response"); + Self::oneshot_send(tx, Ok(()), "set_wireguard_mtu response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1779,26 +1865,32 @@ where } } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_wireguard_mtu response"); + } } } async fn on_set_wireguard_rotation_interval( &mut self, - tx: oneshot::Sender<()>, + tx: ResponseTx<(), settings::Error>, interval: Option<u32>, ) { let save_result = self.settings.set_wireguard_rotation_interval(interval); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_wireguard_rotation_interval response"); + Self::oneshot_send(tx, Ok(()), "set_wireguard_rotation_interval response"); if settings_changed { self.ensure_key_rotation().await; self.event_listener .notify_settings(self.settings.to_settings()); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_wireguard_rotation_interval response"); + } } } @@ -1822,28 +1914,29 @@ where } } - async fn on_generate_wireguard_key(&mut self, tx: oneshot::Sender<KeygenEvent>) { + async fn on_generate_wireguard_key(&mut self, tx: ResponseTx<KeygenEvent, Error>) { match self.on_generate_wireguard_key_inner().await { Ok(key_event) => { - Self::oneshot_send(tx, key_event, "generate_wireguard_key response"); + Self::oneshot_send(tx, Ok(key_event), "generate_wireguard_key"); } Err(e) => { log::error!("Failed to generate new wireguard key - {}", e); + Self::oneshot_send(tx, Err(e), "generate_wireguard_key"); } } } - async fn on_generate_wireguard_key_inner(&mut self) -> Result<KeygenEvent, String> { + async fn on_generate_wireguard_key_inner(&mut self) -> Result<KeygenEvent, Error> { let account_token = self .settings .get_account_token() - .ok_or_else(|| "No account token set".to_owned())?; + .ok_or(Error::NoAccountToken)?; let mut account_entry = self .account_history .get(&account_token) .await - .map_err(|e| format!("Failed to read account entry from history: {}", e)) + .map_err(Error::AccountHistory) .map(|data| { data.unwrap_or_else(|| { log::error!("Account token set in settings but not in account history"); @@ -1874,9 +1967,7 @@ where self.account_history .insert(account_entry) .await - .map_err(|e| { - format!("Failed to add new wireguard key to account data: {}", e) - })?; + .map_err(Error::AccountHistory)?; if let Some(TunnelType::Wireguard) = self.get_target_tunnel_type() { self.reconnect_tunnel(); } @@ -1899,29 +1990,33 @@ where Ok(keygen_event) } Err(wireguard::Error::TooManyKeys) => Ok(KeygenEvent::TooManyKeys), - Err(e) => Err(format!( - "Failed to generate new key - {}", - e.display_chain_with_msg("Failed to generate new wireguard key:") - )), + Err(wireguard::Error::RestError(error)) => Err(Error::RestError(error)), } } - async fn on_get_wireguard_key(&mut self, tx: oneshot::Sender<Option<wireguard::PublicKey>>) { + async fn on_get_wireguard_key(&mut self, tx: ResponseTx<Option<wireguard::PublicKey>, Error>) { let token = self.settings.get_account_token(); - if let Some(token) = token { + let result = if let Some(token) = token { let entry = self.account_history.get(&token).await; - if let Ok(Some(entry)) = entry { - let key = entry.wireguard.map(|wg| wg.get_public_key()); - Self::oneshot_send(tx, key, "get_wireguard_key response"); + match entry { + Ok(Some(entry)) => { + let key = entry.wireguard.map(|wg| wg.get_public_key()); + Ok(key) + } + Ok(None) => Err(Error::NoAccountTokenHistory), + Err(error) => Err(Error::AccountHistory(error)), } - } + } else { + Err(Error::NoAccountToken) + }; + Self::oneshot_send(tx, result, "get_wireguard_key response"); } - async fn on_verify_wireguard_key(&mut self, tx: oneshot::Sender<bool>) { + async fn on_verify_wireguard_key(&mut self, tx: ResponseTx<bool, Error>) { let account = match self.settings.get_account_token() { Some(account) => account, None => { - Self::oneshot_send(tx, false, "verify_wireguard_key response"); + Self::oneshot_send(tx, Ok(false), "verify_wireguard_key response"); return; } }; @@ -1935,11 +2030,16 @@ where let public_key = match key { Ok(Some(public_key)) => public_key, Ok(None) => { - Self::oneshot_send(tx, false, "verify_wireguard_key response"); + Self::oneshot_send(tx, Ok(false), "verify_wireguard_key response"); return; } Err(e) => { log::error!("Failed to read key data: {}", e); + Self::oneshot_send( + tx, + Err(Error::AccountHistory(e)), + "verify_wireguard_key response", + ); return; } }; @@ -1949,14 +2049,12 @@ where .verify_wireguard_key(account, public_key); tokio::spawn(async move { - match verification_rpc.await { - Ok(is_valid) => { - Self::oneshot_send(tx, is_valid, "verify_wireguard_key response"); - } - Err(err) => { - log::error!("Failed to verify wireguard key - {}", err); - } - } + let result = match verification_rpc.await { + Ok(is_valid) => Ok(is_valid), + Err(wireguard::Error::RestError(error)) => Err(Error::RestError(error)), + Err(wireguard::Error::TooManyKeys) => return, + }; + Self::oneshot_send(tx, result, "verify_wireguard_key response"); }); } diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index ccde44ba8f..7faa0eee14 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -1,4 +1,4 @@ -use crate::{DaemonCommand, DaemonCommandSender, EventListener}; +use crate::{account_history, settings, DaemonCommand, DaemonCommandSender, EventListener}; use futures::channel::oneshot; use mullvad_management_interface::{ types::{self, daemon_event, management_service_server::ManagementService}, @@ -67,7 +67,7 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetTargetState(tx, TargetState::Secured))?; - let connect_issued = rx.await.map_err(|_| Status::internal("internal error"))?; + let connect_issued = self.wait_for_result(rx).await?; Ok(Response::new(connect_issued)) } @@ -76,7 +76,7 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetTargetState(tx, TargetState::Unsecured))?; - let disconnect_issued = rx.await.map_err(|_| Status::internal("internal error"))?; + let disconnect_issued = self.wait_for_result(rx).await?; Ok(Response::new(disconnect_issued)) } @@ -84,7 +84,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("reconnect_tunnel"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::Reconnect(tx))?; - let reconnect_issued = rx.await.map_err(|_| Status::internal("internal error"))?; + let reconnect_issued = self.wait_for_result(rx).await?; Ok(Response::new(reconnect_issued)) } @@ -92,7 +92,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("get_tunnel_state"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetState(tx))?; - let state = rx.await.map_err(|_| Status::internal("internal error"))?; + let state = self.wait_for_result(rx).await?; Ok(Response::new(convert_state(state))) } @@ -126,13 +126,14 @@ impl ManagementService for ManagementServiceImpl { log::debug!("factory_reset"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::FactoryReset(tx))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_daemon_error) } #[cfg(target_os = "android")] { - Response::new(()) + Ok(Response::new(())) } } @@ -140,9 +141,8 @@ impl ManagementService for ManagementServiceImpl { log::debug!("get_current_version"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetCurrentVersion(tx))?; - rx.await - .map(Response::new) - .map_err(|_| Status::internal("internal error")) + let version = self.wait_for_result(rx).await?; + Ok(Response::new(version)) } async fn get_version_info(&self, _: Request<()>) -> ServiceResult<types::AppVersionInfo> { @@ -150,8 +150,8 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetVersionInfo(tx))?; - let version_info = rx.await.map_err(|_| Status::internal("internal error"))?; - version_info + self.wait_for_result(rx) + .await? .ok_or(Status::not_found("no version cache")) .map(|version_info| convert_version_info(&version_info)) .map(Response::new) @@ -176,9 +176,10 @@ impl ManagementService for ManagementServiceImpl { let message = DaemonCommand::UpdateRelaySettings(tx, constraints_update); self.send_command_to_daemon(message)?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } async fn get_relay_locations( @@ -189,7 +190,7 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetRelayLocations(tx))?; - let locations = rx.await.map_err(|_| Status::internal("internal error"))?; + let locations = self.wait_for_result(rx).await?; let (mut stream_tx, stream_rx) = tokio::sync::mpsc::channel(cmp::max(1, locations.countries.len())); @@ -215,7 +216,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("get_current_location"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetCurrentLocation(tx))?; - let result = rx.await.map_err(|_| Status::internal("internal error"))?; + let result = self.wait_for_result(rx).await?; match result { Some(geoip) => Ok(Response::new(convert_geoip_location(geoip))), None => Err(Status::not_found("no location was found")), @@ -295,10 +296,10 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetBridgeSettings(tx, settings))?; - let settings_result = rx.await.map_err(|_| Status::internal("internal error"))?; + let settings_result = self.wait_for_result(rx).await?; settings_result .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } async fn set_bridge_state(&self, request: Request<types::BridgeState>) -> ServiceResult<()> { @@ -314,10 +315,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_bridge_state({:?})", bridge_state); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetBridgeState(tx, bridge_state))?; - let settings_result = rx.await.map_err(|_| Status::internal("internal error"))?; + let settings_result = self.wait_for_result(rx).await?; settings_result .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } // Settings @@ -327,9 +328,9 @@ impl ManagementService for ManagementServiceImpl { log::debug!("get_settings"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetSettings(tx))?; - rx.await + self.wait_for_result(rx) + .await .map(|settings| Response::new(convert_settings(&settings))) - .map_err(|_| Status::internal("internal error")) } async fn set_allow_lan(&self, request: Request<bool>) -> ServiceResult<()> { @@ -337,9 +338,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_allow_lan({})", allow_lan); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetAllowLan(tx, allow_lan))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } async fn set_show_beta_releases(&self, request: Request<bool>) -> ServiceResult<()> { @@ -347,9 +349,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_show_beta_releases({})", enabled); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetShowBetaReleases(tx, enabled))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } async fn set_block_when_disconnected(&self, request: Request<bool>) -> ServiceResult<()> { @@ -360,9 +363,10 @@ impl ManagementService for ManagementServiceImpl { tx, block_when_disconnected, ))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } async fn set_auto_connect(&self, request: Request<bool>) -> ServiceResult<()> { @@ -370,9 +374,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_auto_connect({})", auto_connect); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetAutoConnect(tx, auto_connect))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } async fn set_openvpn_mssfix(&self, request: Request<u32>) -> ServiceResult<()> { @@ -385,9 +390,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_openvpn_mssfix({:?})", mssfix); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetOpenVpnMssfix(tx, mssfix))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } async fn set_wireguard_mtu(&self, request: Request<u32>) -> ServiceResult<()> { @@ -396,9 +402,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_wireguard_mtu({:?})", mtu); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetWireguardMtu(tx, mtu))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } async fn set_enable_ipv6(&self, request: Request<bool>) -> ServiceResult<()> { @@ -406,9 +413,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_enable_ipv6({})", enable_ipv6); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetEnableIpv6(tx, enable_ipv6))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } #[cfg(not(target_os = "android"))] @@ -438,9 +446,10 @@ impl ManagementService for ManagementServiceImpl { addresses: servers_ip, }, ))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } #[cfg(target_os = "android")] async fn set_dns_options(&self, _: Request<types::DnsOptions>) -> ServiceResult<()> { @@ -453,11 +462,10 @@ impl ManagementService for ManagementServiceImpl { async fn create_new_account(&self, _: Request<()>) -> ServiceResult<String> { let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::CreateNewAccount(tx))?; - let result = rx.await.map_err(|_| Status::internal("internal error"))?; - match result { - Ok(account_token) => Ok(Response::new(account_token)), - Err(_) => Err(Status::internal("internal error")), - } + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_daemon_error) } async fn set_account(&self, request: Request<AccountToken>) -> ServiceResult<()> { @@ -470,9 +478,10 @@ impl ManagementService for ManagementServiceImpl { }; let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetAccount(tx, account_token))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_settings_error) } async fn get_account_data( @@ -483,7 +492,7 @@ impl ManagementService for ManagementServiceImpl { let account_token = request.into_inner(); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetAccountData(tx, account_token))?; - let result = rx.await.map_err(|_| Status::internal("internal error"))?; + let result = self.wait_for_result(rx).await?; result .map(|account_data| { Response::new(types::AccountData { @@ -498,7 +507,7 @@ impl ManagementService for ManagementServiceImpl { "Unable to get account data from API: {}", error.display_chain() ); - map_rest_account_error(error) + map_rest_error(error) }) } @@ -507,8 +516,8 @@ impl ManagementService for ManagementServiceImpl { log::debug!("get_account_history"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetAccountHistory(tx))?; - rx.await - .map_err(|_| Status::internal("internal error")) + self.wait_for_result(rx) + .await .map(|history| Response::new(types::AccountHistory { token: history })) } @@ -520,34 +529,34 @@ impl ManagementService for ManagementServiceImpl { let account_token = request.into_inner(); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::RemoveAccountFromHistory(tx, account_token))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_daemon_error) } async fn clear_account_history(&self, _: Request<()>) -> ServiceResult<()> { log::debug!("clear_account_history"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::ClearAccountHistory(tx))?; - rx.await + self.wait_for_result(rx) + .await? .map(Response::new) - .map_err(|_| Status::internal("internal error")) + .map_err(map_daemon_error) } async fn get_www_auth_token(&self, _: Request<()>) -> ServiceResult<String> { log::debug!("get_www_auth_token"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetWwwAuthToken(tx))?; - let result = rx.await.map_err(|_| Status::internal("internal error"))?; - result - .map(Response::new) - .map_err(|error: mullvad_rpc::rest::Error| { - log::error!( - "Unable to get account data from API: {}", - error.display_chain() - ); - map_rest_account_error(error) - }) + let result = self.wait_for_result(rx).await?; + result.map(Response::new).map_err(|error| { + log::error!( + "Unable to get account data from API: {}", + error.display_chain() + ); + map_daemon_error(error) + }) } async fn submit_voucher( @@ -558,7 +567,7 @@ impl ManagementService for ManagementServiceImpl { let voucher = request.into_inner(); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SubmitVoucher(tx, voucher))?; - let result = rx.await.map_err(|_| Status::internal("internal error"))?; + let result = self.wait_for_result(rx).await?; result .map(|submission| { Response::new(types::VoucherSubmission { @@ -569,19 +578,9 @@ impl ManagementService for ManagementServiceImpl { }), }) }) - .map_err(|e| match e { - RestError::ApiError(StatusCode::BAD_REQUEST, message) => match &message.as_str() { - &mullvad_rpc::INVALID_VOUCHER => { - Status::new(Code::NotFound, INVALID_VOUCHER_MESSAGE) - } - - &mullvad_rpc::VOUCHER_USED => { - Status::new(Code::ResourceExhausted, USED_VOUCHER_MESSAGE) - } - - _ => Status::internal("internal error"), - }, - _ => Status::internal("internal error"), + .map_err(|error| match error { + crate::Error::RestError(error) => map_rest_voucher_error(error), + error => map_daemon_error(error), }) } @@ -597,18 +596,20 @@ impl ManagementService for ManagementServiceImpl { tx, Some(interval), ))?; - rx.await - .map_err(|_| Status::internal("internal error")) + self.wait_for_result(rx) + .await? .map(Response::new) + .map_err(map_settings_error) } async fn reset_wireguard_rotation_interval(&self, _: Request<()>) -> ServiceResult<()> { log::debug!("reset_wireguard_rotation_interval"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetWireguardRotationInterval(tx, None))?; - rx.await - .map_err(|_| Status::internal("internal error")) + self.wait_for_result(rx) + .await? .map(Response::new) + .map_err(map_settings_error) } async fn generate_wireguard_key(&self, _: Request<()>) -> ServiceResult<types::KeygenEvent> { @@ -617,20 +618,20 @@ impl ManagementService for ManagementServiceImpl { log::debug!("generate_wireguard_key"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GenerateWireguardKey(tx))?; - rx.await - .map_err(|_| Status::internal("internal error")) + self.wait_for_result(rx) + .await? .map(|event| Response::new(convert_wireguard_key_event(&event))) + .map_err(map_daemon_error) } async fn get_wireguard_key(&self, _: Request<()>) -> ServiceResult<types::PublicKey> { log::debug!("get_wireguard_key"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetWireguardKey(tx))?; - let response = rx.await.map_err(|_| Status::internal("internal error")); - match response { - Ok(Some(key)) => Ok(Response::new(convert_public_key(&key))), - Ok(None) => Err(Status::not_found("no WireGuard key was found")), - Err(e) => Err(e), + let key = self.wait_for_result(rx).await?.map_err(map_daemon_error)?; + match key { + Some(key) => Ok(Response::new(convert_public_key(&key))), + None => Err(Status::not_found("no WireGuard key was found")), } } @@ -638,9 +639,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("verify_wireguard_key"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::VerifyWireguardKey(tx))?; - rx.await - .map_err(|_| Status::internal("internal error")) + self.wait_for_result(rx) + .await? .map(Response::new) + .map_err(map_daemon_error) } // Split tunneling @@ -655,7 +657,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("get_split_tunnel_processes"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetSplitTunnelProcesses(tx))?; - let pids = rx.await.map_err(|_| Status::internal("internal error"))?; + let pids = self + .wait_for_result(rx) + .await? + .map_err(|error| Status::failed_precondition(error.to_string()))?; let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); tokio::spawn(async move { @@ -679,9 +684,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("add_split_tunnel_process"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::AddSplitTunnelProcess(tx, pid))?; - rx.await - .map_err(|_| Status::internal("internal error")) - .map(Response::new) + self.wait_for_result(rx) + .await? + .map_err(|error| Status::failed_precondition(error.to_string()))?; + Ok(Response::new(())) } #[cfg(not(target_os = "linux"))] async fn add_split_tunnel_process(&self, _: Request<i32>) -> ServiceResult<()> { @@ -694,9 +700,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("remove_split_tunnel_process"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::RemoveSplitTunnelProcess(tx, pid))?; - rx.await - .map_err(|_| Status::internal("internal error")) - .map(Response::new) + self.wait_for_result(rx) + .await? + .map_err(|error| Status::failed_precondition(error.to_string()))?; + Ok(Response::new(())) } #[cfg(not(target_os = "linux"))] async fn remove_split_tunnel_process(&self, _: Request<i32>) -> ServiceResult<()> { @@ -709,9 +716,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("clear_split_tunnel_processes"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::ClearSplitTunnelProcesses(tx))?; - rx.await - .map_err(|_| Status::internal("internal error")) - .map(Response::new) + self.wait_for_result(rx) + .await? + .map_err(|error| Status::failed_precondition(error.to_string()))?; + Ok(Response::new(())) } #[cfg(not(target_os = "linux"))] { @@ -725,7 +733,11 @@ impl ManagementServiceImpl { fn send_command_to_daemon(&self, command: DaemonCommand) -> Result<(), Status> { self.daemon_tx .send(command) - .map_err(|_| Status::internal("internal error")) + .map_err(|_| Status::internal("the daemon channel receiver has been dropped")) + } + + async fn wait_for_result<T>(&self, rx: oneshot::Receiver<T>) -> Result<T, Status> { + rx.await.map_err(|_| Status::internal("sender was dropped")) } } @@ -1618,14 +1630,69 @@ impl Drop for ManagementInterfaceEventBroadcaster { } } -// Converts a REST API error for an account into a tonic status. -fn map_rest_account_error(error: RestError) -> Status { +/// Converts [`mullvad_daemon::Error`] into a tonic status. +fn map_daemon_error(error: crate::Error) -> Status { + use crate::Error as DaemonError; + + match error { + DaemonError::RestError(error) => map_rest_error(error), + DaemonError::SettingsError(error) => map_settings_error(error), + DaemonError::AccountHistory(error) => map_account_history_error(error), + DaemonError::NoAccountToken | DaemonError::NoAccountTokenHistory => { + Status::unauthenticated(error.to_string()) + } + error => Status::unknown(error.to_string()), + } +} + +/// Converts a REST API voucher error into a tonic status. +fn map_rest_voucher_error(error: RestError) -> Status { + match error { + RestError::ApiError(StatusCode::BAD_REQUEST, message) => match &message.as_str() { + &mullvad_rpc::INVALID_VOUCHER => Status::new(Code::NotFound, INVALID_VOUCHER_MESSAGE), + + &mullvad_rpc::VOUCHER_USED => { + Status::new(Code::ResourceExhausted, USED_VOUCHER_MESSAGE) + } + + error => Status::unknown(format!("Voucher error: {}", error)), + }, + error => map_rest_error(error), + } +} + +/// Converts a REST API error into a tonic status. +fn map_rest_error(error: RestError) -> Status { match error { RestError::ApiError(status, message) if status == StatusCode::UNAUTHORIZED || status == StatusCode::FORBIDDEN => { Status::new(Code::Unauthenticated, message) } - _ => Status::internal("internal error"), + RestError::TimeoutError(_elapsed) => Status::deadline_exceeded("API request timed out"), + RestError::HyperError(_) => Status::unavailable("Cannot reach the API"), + error => Status::unknown(format!("REST error: {}", error)), + } +} + +/// Converts an instance of [`mullvad_daemon::settings::Error`] into a tonic status. +fn map_settings_error(error: settings::Error) -> Status { + match error { + settings::Error::DeleteError(..) | settings::Error::WriteError(..) => { + Status::new(Code::FailedPrecondition, error.to_string()) + } + settings::Error::SerializeError(..) => Status::new(Code::Internal, error.to_string()), + } +} + +/// Converts an instance of [`mullvad_daemon::account_history::Error`] into a tonic status. +fn map_account_history_error(error: account_history::Error) -> Status { + match error { + account_history::Error::Read(..) | account_history::Error::Write(..) => { + Status::new(Code::FailedPrecondition, error.to_string()) + } + account_history::Error::Serialize(..) | account_history::Error::WriteCancelled(..) => { + Status::new(Code::Internal, error.to_string()) + } } } diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs index 4b54ca4c58..777cee99c2 100644 --- a/mullvad-jni/src/daemon_interface.rs +++ b/mullvad-jni/src/daemon_interface.rs @@ -12,6 +12,7 @@ use mullvad_types::{ }; #[derive(Debug, err_derive::Error)] +#[error(no_from)] pub enum Error { #[error(display = "Can't send command to daemon because it is not running")] NoDaemon(#[error(source)] mullvad_daemon::Error), @@ -24,6 +25,21 @@ pub enum Error { #[error(display = "Error performing RPC with the remote API")] RpcError(#[error(source)] mullvad_rpc::rest::Error), + + #[error(display = "Failed to update settings")] + SettingsError, + + #[error(display = "Daemon returned an error")] + OtherError(#[error(source)] mullvad_daemon::Error), +} + +impl From<mullvad_daemon::Error> for Error { + fn from(error: mullvad_daemon::Error) -> Error { + match error { + mullvad_daemon::Error::RestError(error) => Error::RpcError(error), + error => Error::OtherError(error), + } + } } type Result<T> = std::result::Result<T, Error>; @@ -52,7 +68,7 @@ impl DaemonInterface { block_on(rx) .map_err(|_| Error::NoResponse)? - .map_err(Error::RpcError) + .map_err(Error::from) } pub fn disconnect(&self) -> Result<()> { @@ -68,7 +84,9 @@ impl DaemonInterface { self.send_command(DaemonCommand::GenerateWireguardKey(tx))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(Error::from) } pub fn get_account_data(&self, account_token: String) -> Result<AccountData> { @@ -96,7 +114,7 @@ impl DaemonInterface { block_on(rx) .map_err(|_| Error::NoResponse)? - .map_err(Error::RpcError) + .map_err(Error::from) } pub fn get_current_location(&self) -> Result<Option<GeoIpLocation>> { @@ -162,7 +180,9 @@ impl DaemonInterface { self.send_command(DaemonCommand::RemoveAccountFromHistory(tx, account_token))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(Error::from) } pub fn get_wireguard_key(&self) -> Result<Option<wireguard::PublicKey>> { @@ -170,14 +190,18 @@ impl DaemonInterface { self.send_command(DaemonCommand::GetWireguardKey(tx))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(Error::from) } pub fn verify_wireguard_key(&self) -> Result<bool> { let (tx, rx) = oneshot::channel(); self.send_command(DaemonCommand::VerifyWireguardKey(tx))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(Error::from) } pub fn set_account(&self, account_token: Option<String>) -> Result<()> { @@ -185,7 +209,9 @@ impl DaemonInterface { self.send_command(DaemonCommand::SetAccount(tx, account_token))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(|_| Error::SettingsError) } pub fn set_allow_lan(&self, allow_lan: bool) -> Result<()> { @@ -193,7 +219,9 @@ impl DaemonInterface { self.send_command(DaemonCommand::SetAllowLan(tx, allow_lan))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(|_| Error::SettingsError) } pub fn set_auto_connect(&self, auto_connect: bool) -> Result<()> { @@ -201,7 +229,9 @@ impl DaemonInterface { self.send_command(DaemonCommand::SetAutoConnect(tx, auto_connect))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(|_| Error::SettingsError) } pub fn set_dns_options(&self, dns_options: DnsOptions) -> Result<()> { @@ -209,7 +239,9 @@ impl DaemonInterface { self.send_command(DaemonCommand::SetDnsOptions(tx, dns_options))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(|_| Error::SettingsError) } pub fn set_wireguard_mtu(&self, wireguard_mtu: Option<u16>) -> Result<()> { @@ -217,7 +249,9 @@ impl DaemonInterface { self.send_command(DaemonCommand::SetWireguardMtu(tx, wireguard_mtu))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(|_| Error::SettingsError) } pub fn shutdown(&self) -> Result<()> { @@ -231,7 +265,7 @@ impl DaemonInterface { block_on(rx) .map_err(|_| Error::NoResponse)? - .map_err(Error::RpcError) + .map_err(Error::from) } pub fn update_relay_settings(&self, update: RelaySettingsUpdate) -> Result<()> { @@ -239,7 +273,9 @@ impl DaemonInterface { self.send_command(DaemonCommand::UpdateRelaySettings(tx, update))?; - block_on(rx).map_err(|_| Error::NoResponse) + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(|_| Error::SettingsError) } fn send_command(&self, command: DaemonCommand) -> Result<()> { |
