diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-03-31 15:47:17 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-03-31 15:47:17 +0200 |
| commit | afa8cea611744de08125ac52215cc764f4a84eed (patch) | |
| tree | ce88cd605a6755c03b8d363502b558a09f3c93c2 | |
| parent | ad1070d5252ff06691667fecebf6a31451683616 (diff) | |
| parent | 7333c583f5e7094bd8ff218c0115ca8f808cb36d (diff) | |
| download | mullvadvpn-afa8cea611744de08125ac52215cc764f4a84eed.tar.xz mullvadvpn-afa8cea611744de08125ac52215cc764f4a84eed.zip | |
Merge branch 'async-fs-fix'
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 248 | ||||
| -rw-r--r-- | mullvad-daemon/src/settings.rs | 122 | ||||
| -rw-r--r-- | mullvad-daemon/src/version_check.rs | 18 |
3 files changed, 222 insertions, 166 deletions
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 866bf7131c..8c35b82443 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -44,12 +44,11 @@ use settings::SettingsPersister; #[cfg(target_os = "android")] use std::os::unix::io::RawFd; use std::{ - fs::{self, File}, - io, marker::PhantomData, mem, net::IpAddr, path::{Path, PathBuf}, + pin::Pin, sync::{mpsc as sync_mpsc, Arc, Weak}, time::Duration, }; @@ -66,6 +65,7 @@ use talpid_types::{ tunnel::{ErrorStateCause, ParameterGenerationError, TunnelStateTransition}, ErrorExt, }; +use tokio::{fs, io}; #[path = "wireguard.rs"] mod wireguard; @@ -490,7 +490,7 @@ pub struct Daemon<L: EventListener> { last_generated_relay: Option<Relay>, last_generated_bridge_relay: Option<Relay>, app_version_info: Option<AppVersionInfo>, - shutdown_callbacks: Vec<Box<dyn FnOnce()>>, + shutdown_tasks: Vec<Pin<Box<dyn Future<Output = ()>>>>, /// oneshot channel that completes once the tunnel state machine has been shut down tunnel_state_machine_shutdown_signal: oneshot::Receiver<()>, cache_dir: PathBuf, @@ -555,13 +555,13 @@ where ); - let mut settings = SettingsPersister::load(&settings_dir); + let mut settings = SettingsPersister::load(&settings_dir).await; if version::is_beta_version() { - let _ = settings.set_show_beta_releases(true); + let _ = settings.set_show_beta_releases(true).await; } - let app_version_info = version_check::load_cache(&cache_dir); + let app_version_info = version_check::load_cache(&cache_dir).await; let (version_updater, version_updater_handle) = version_check::VersionUpdater::new( rpc_handle.clone(), cache_dir.clone(), @@ -577,23 +577,24 @@ where // Restore the tunnel to a previous state let target_cache = cache_dir.join(TARGET_START_STATE_FILE); - let cached_target_state: Option<TargetState> = match File::open(&target_cache) { - Ok(handle) => serde_json::from_reader(io::BufReader::new(handle)) - .map(Some) - .map_err(Error::ReadCachedTargetState), - Err(e) => { - if e.kind() == io::ErrorKind::NotFound { - debug!("No cached target state to load"); - Ok(None) - } else { - Err(Error::OpenCachedTargetState(e)) + let cached_target_state: Option<TargetState> = + match fs::read_to_string(&target_cache).await { + Ok(content) => serde_json::from_str(&content) + .map(Some) + .map_err(Error::ReadCachedTargetState), + Err(e) => { + if e.kind() == io::ErrorKind::NotFound { + debug!("No cached target state to load"); + Ok(None) + } else { + Err(Error::OpenCachedTargetState(e)) + } } } - } - .unwrap_or_else(|error| { - error!("{}", error.display_chain()); - Some(TargetState::Secured) - }); + .unwrap_or_else(|error| { + error!("{}", error.display_chain()); + Some(TargetState::Secured) + }); if let Some(cached_target_state) = &cached_target_state { info!( "Loaded cached target state \"{}\" from {}", @@ -618,7 +619,7 @@ where } else { TargetState::Unsecured }; - Self::cache_target_state(&cache_dir, initial_target_state); + Self::cache_target_state(&cache_dir, initial_target_state).await; let initial_api_endpoint = Endpoint::from_socket_address( rpc_runtime.address_cache.peek_address(), @@ -683,7 +684,7 @@ where last_generated_relay: None, last_generated_bridge_relay: None, app_version_info, - shutdown_callbacks: vec![], + shutdown_tasks: vec![], tunnel_state_machine_shutdown_signal, cache_dir, }; @@ -729,14 +730,14 @@ where async fn finalize(self) { let ( event_listener, - shutdown_callbacks, + shutdown_tasks, rpc_runtime, tunnel_state_machine_shutdown_signal, cache_dir, lock_target_cache, ) = self.shutdown(); - for cb in shutdown_callbacks { - cb(); + for future in shutdown_tasks { + future.await; } let shutdown_signal = tokio::time::timeout( @@ -752,7 +753,7 @@ where mem::drop(rpc_runtime); #[cfg(any(target_os = "macos", target_os = "linux"))] - if let Err(err) = fs::remove_file(mullvad_paths::get_rpc_socket_path()) { + if let Err(err) = fs::remove_file(mullvad_paths::get_rpc_socket_path()).await { if err.kind() != std::io::ErrorKind::NotFound { log::error!("Failed to remove old RPC socket: {}", err); } @@ -760,7 +761,7 @@ where if !lock_target_cache { let target_cache = cache_dir.join(TARGET_START_STATE_FILE); - let _ = fs::remove_file(target_cache).map_err(|e| { + let _ = fs::remove_file(target_cache).await.map_err(|e| { error!("Cannot delete target tunnel state cache: {}", e); }); } @@ -772,7 +773,7 @@ where self, ) -> ( L, - Vec<Box<dyn FnOnce()>>, + Vec<Pin<Box<dyn Future<Output = ()>>>>, mullvad_rpc::MullvadRpcRuntime, oneshot::Receiver<()>, PathBuf, @@ -780,7 +781,7 @@ where ) { let Daemon { event_listener, - shutdown_callbacks, + shutdown_tasks, rpc_runtime, tunnel_state_machine_shutdown_signal, cache_dir, @@ -789,7 +790,7 @@ where } = self; ( event_listener, - shutdown_callbacks, + shutdown_tasks, rpc_runtime, tunnel_state_machine_shutdown_signal, cache_dir, @@ -1094,7 +1095,7 @@ where return; } match command { - SetTargetState(tx, state) => self.on_set_target_state(tx, state), + SetTargetState(tx, state) => self.on_set_target_state(tx, state).await, Reconnect(tx) => self.on_reconnect(tx), GetState(tx) => self.on_get_state(tx), GetCurrentLocation(tx) => self.on_get_current_location(tx).await, @@ -1110,21 +1111,22 @@ where self.on_remove_account_from_history(tx, account_token).await } ClearAccountHistory(tx) => self.on_clear_account_history(tx).await, - UpdateRelaySettings(tx, update) => self.on_update_relay_settings(tx, update), - SetAllowLan(tx, allow_lan) => self.on_set_allow_lan(tx, allow_lan), + UpdateRelaySettings(tx, update) => self.on_update_relay_settings(tx, update).await, + SetAllowLan(tx, allow_lan) => self.on_set_allow_lan(tx, allow_lan).await, SetShowBetaReleases(tx, enabled) => self.on_set_show_beta_releases(tx, enabled).await, SetBlockWhenDisconnected(tx, block_when_disconnected) => { self.on_set_block_when_disconnected(tx, block_when_disconnected) + .await } - SetAutoConnect(tx, auto_connect) => self.on_set_auto_connect(tx, auto_connect), - SetOpenVpnMssfix(tx, mssfix_arg) => self.on_set_openvpn_mssfix(tx, mssfix_arg), + SetAutoConnect(tx, auto_connect) => self.on_set_auto_connect(tx, auto_connect).await, + SetOpenVpnMssfix(tx, mssfix_arg) => self.on_set_openvpn_mssfix(tx, mssfix_arg).await, SetBridgeSettings(tx, bridge_settings) => { - self.on_set_bridge_settings(tx, bridge_settings) + self.on_set_bridge_settings(tx, bridge_settings).await } - SetBridgeState(tx, bridge_state) => self.on_set_bridge_state(tx, bridge_state), - SetEnableIpv6(tx, enable_ipv6) => self.on_set_enable_ipv6(tx, enable_ipv6), - SetDnsOptions(tx, dns_servers) => self.on_set_dns_options(tx, dns_servers), - SetWireguardMtu(tx, mtu) => self.on_set_wireguard_mtu(tx, mtu), + SetBridgeState(tx, bridge_state) => self.on_set_bridge_state(tx, bridge_state).await, + SetEnableIpv6(tx, enable_ipv6) => self.on_set_enable_ipv6(tx, enable_ipv6).await, + SetDnsOptions(tx, dns_servers) => self.on_set_dns_options(tx, dns_servers).await, + SetWireguardMtu(tx, mtu) => self.on_set_wireguard_mtu(tx, mtu).await, SetWireguardRotationInterval(tx, interval) => { self.on_set_wireguard_rotation_interval(tx, interval).await } @@ -1244,7 +1246,7 @@ where ) { match self.set_account(Some(new_token.clone())).await { Ok(_) => { - self.set_target_state(TargetState::Unsecured); + self.set_target_state(TargetState::Unsecured).await; let _ = tx.send(Ok(new_token)); } Err(err) => { @@ -1262,9 +1264,13 @@ where self.event_listener.notify_app_version(app_version_info); } - fn on_set_target_state(&mut self, tx: oneshot::Sender<bool>, new_target_state: TargetState) { + async fn on_set_target_state( + &mut self, + tx: oneshot::Sender<bool>, + new_target_state: TargetState, + ) { if self.state.is_running() { - let state_change_initated = self.set_target_state(new_target_state); + let state_change_initated = self.set_target_state(new_target_state).await; Self::oneshot_send(tx, state_change_initated, "state change initiated"); } else { warn!("Ignoring target state change request due to shutdown"); @@ -1449,7 +1455,7 @@ where } None => { info!("Disconnecting because account token was cleared"); - self.set_target_state(TargetState::Unsecured); + self.set_target_state(TargetState::Unsecured).await; } }; } @@ -1466,7 +1472,10 @@ where &mut self, account_token: Option<String>, ) -> Result<bool, settings::Error> { - let account_changed = self.settings.set_account_token(account_token.clone())?; + let account_changed = self + .settings + .set_account_token(account_token.clone()) + .await?; if account_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1507,7 +1516,7 @@ where 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.set_target_state(TargetState::Unsecured).await; Self::oneshot_send(tx, Ok(()), "clear_account_history response"); } Err(err) => { @@ -1551,7 +1560,7 @@ where let mut last_error = Ok(()); - if let Err(e) = self.settings.reset() { + if let Err(e) = self.settings.reset().await { log::error!("Failed to reset settings - {}", e); last_error = Err(Error::ClearSettingsError(e)); } @@ -1564,8 +1573,8 @@ where // Shut the daemon down. self.trigger_shutdown_event(); - self.shutdown_callbacks.push(Box::new(move || { - if let Err(e) = Self::clear_cache_directory() { + self.shutdown_tasks.push(Box::pin(async move { + if let Err(e) = Self::clear_cache_directory().await { log::error!( "{}", e.display_chain_with_msg("Failed to clear cache directory") @@ -1573,7 +1582,7 @@ where last_error = Err(Error::ClearCacheError); } - if let Err(e) = Self::clear_log_directory() { + if let Err(e) = Self::clear_log_directory().await { log::error!( "{}", e.display_chain_with_msg("Failed to clear log directory") @@ -1624,12 +1633,12 @@ where Self::oneshot_send(tx, result, "clear_split_tunnel_processes response"); } - fn on_update_relay_settings( + async fn on_update_relay_settings( &mut self, tx: ResponseTx<(), settings::Error>, update: RelaySettingsUpdate, ) { - let save_result = self.settings.update_relay_settings(update); + let save_result = self.settings.update_relay_settings(update).await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "update_relay_settings response"); @@ -1647,8 +1656,8 @@ where } } - fn on_set_allow_lan(&mut self, tx: ResponseTx<(), settings::Error>, allow_lan: bool) { - let save_result = self.settings.set_allow_lan(allow_lan); + async fn on_set_allow_lan(&mut self, tx: ResponseTx<(), settings::Error>, allow_lan: bool) { + let save_result = self.settings.set_allow_lan(allow_lan).await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "set_allow_lan response"); @@ -1670,7 +1679,7 @@ where tx: ResponseTx<(), settings::Error>, enabled: bool, ) { - let save_result = self.settings.set_show_beta_releases(enabled); + let save_result = self.settings.set_show_beta_releases(enabled).await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "set_show_beta_releases response"); @@ -1688,14 +1697,15 @@ where } } - fn on_set_block_when_disconnected( + async fn on_set_block_when_disconnected( &mut self, tx: ResponseTx<(), settings::Error>, block_when_disconnected: bool, ) { let save_result = self .settings - .set_block_when_disconnected(block_when_disconnected); + .set_block_when_disconnected(block_when_disconnected) + .await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "set_block_when_disconnected response"); @@ -1714,8 +1724,12 @@ where } } - fn on_set_auto_connect(&mut self, tx: ResponseTx<(), settings::Error>, auto_connect: bool) { - let save_result = self.settings.set_auto_connect(auto_connect); + async fn on_set_auto_connect( + &mut self, + tx: ResponseTx<(), settings::Error>, + auto_connect: bool, + ) { + let save_result = self.settings.set_auto_connect(auto_connect).await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "set auto-connect response"); @@ -1731,12 +1745,12 @@ where } } - fn on_set_openvpn_mssfix( + async 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); + let save_result = self.settings.set_openvpn_mssfix(mssfix_arg).await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "set_openvpn_mssfix response"); @@ -1758,12 +1772,12 @@ where } } - fn on_set_bridge_settings( + async fn on_set_bridge_settings( &mut self, tx: ResponseTx<(), settings::Error>, new_settings: BridgeSettings, ) { - match self.settings.set_bridge_settings(new_settings) { + match self.settings.set_bridge_settings(new_settings).await { Ok(settings_changes) => { if settings_changes { self.event_listener @@ -1783,12 +1797,12 @@ where } } - fn on_set_bridge_state( + async fn on_set_bridge_state( &mut self, tx: ResponseTx<(), settings::Error>, bridge_state: BridgeState, ) { - let result = match self.settings.set_bridge_state(bridge_state) { + let result = match self.settings.set_bridge_state(bridge_state).await { Ok(settings_changed) => { if settings_changed { self.event_listener @@ -1810,8 +1824,8 @@ where } - fn on_set_enable_ipv6(&mut self, tx: ResponseTx<(), settings::Error>, enable_ipv6: bool) { - let save_result = self.settings.set_enable_ipv6(enable_ipv6); + async fn on_set_enable_ipv6(&mut self, tx: ResponseTx<(), settings::Error>, enable_ipv6: bool) { + let save_result = self.settings.set_enable_ipv6(enable_ipv6).await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "set_enable_ipv6 response"); @@ -1829,8 +1843,12 @@ where } } - 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()); + async 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()).await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "set_dns_options response"); @@ -1849,8 +1867,12 @@ where } } - fn on_set_wireguard_mtu(&mut self, tx: ResponseTx<(), settings::Error>, mtu: Option<u16>) { - let save_result = self.settings.set_wireguard_mtu(mtu); + async fn on_set_wireguard_mtu( + &mut self, + tx: ResponseTx<(), settings::Error>, + mtu: Option<u16>, + ) { + let save_result = self.settings.set_wireguard_mtu(mtu).await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "set_wireguard_mtu response"); @@ -1877,7 +1899,10 @@ where tx: ResponseTx<(), settings::Error>, interval: Option<RotationInterval>, ) { - let save_result = self.settings.set_wireguard_rotation_interval(interval); + let save_result = self + .settings + .set_wireguard_rotation_interval(interval) + .await; match save_result { Ok(settings_changed) => { Self::oneshot_send(tx, Ok(()), "set_wireguard_rotation_interval response"); @@ -2114,14 +2139,14 @@ where /// Set the target state of the client. If it changed trigger the operations needed to /// progress towards that state. /// Returns a bool representing whether or not a state change was initiated. - fn set_target_state(&mut self, new_state: TargetState) -> bool { + async fn set_target_state(&mut self, new_state: TargetState) -> bool { if new_state != self.target_state || self.tunnel_state.is_in_error_state() { debug!("Target state {:?} => {:?}", self.target_state, new_state); if new_state != self.target_state { self.target_state = new_state; if !self.lock_target_cache { - Self::cache_target_state(&self.cache_dir, self.target_state); + Self::cache_target_state(&self.cache_dir, self.target_state).await; } } @@ -2135,17 +2160,23 @@ where } } - fn cache_target_state(cache_dir: &Path, target_state: TargetState) { + async fn cache_target_state(cache_dir: &Path, target_state: TargetState) { let cache_file = cache_dir.join(TARGET_START_STATE_FILE); log::trace!("Saving tunnel target state to {}", cache_file.display()); - match File::create(&cache_file) { - Ok(handle) => { - if let Err(e) = serde_json::to_writer(io::BufWriter::new(handle), &target_state) { - log::error!("Failed to cache target state: {}", e); + match serde_json::to_string(&target_state) { + Ok(data) => { + if let Err(error) = fs::write(cache_file, data).await { + log::error!( + "{}", + error.display_chain_with_msg("Failed to write cache target state") + ); } } - Err(e) => { - log::error!("Failed to cache target state: {}", e); + Err(error) => { + log::error!( + "{}", + error.display_chain_with_msg("Failed to serialize cache target state") + ) } } } @@ -2197,49 +2228,54 @@ where } #[cfg(not(target_os = "android"))] - fn clear_log_directory() -> Result<(), Error> { + async fn clear_log_directory() -> Result<(), Error> { let log_dir = mullvad_paths::get_log_dir().map_err(Error::PathError)?; - Self::clear_directory(&log_dir) + Self::clear_directory(&log_dir).await } #[cfg(not(target_os = "android"))] - fn clear_cache_directory() -> Result<(), Error> { + async fn clear_cache_directory() -> Result<(), Error> { let cache_dir = mullvad_paths::cache_dir().map_err(Error::PathError)?; - Self::clear_directory(&cache_dir) + Self::clear_directory(&cache_dir).await } #[cfg(not(target_os = "android"))] - fn clear_directory(path: &Path) -> Result<(), Error> { + async fn clear_directory(path: &Path) -> Result<(), Error> { #[cfg(not(target_os = "windows"))] { fs::remove_dir_all(path) + .await .map_err(|e| Error::RemoveDirError(path.display().to_string(), e))?; fs::create_dir_all(path) + .await .map_err(|e| Error::CreateDirError(path.display().to_string(), e)) } #[cfg(target_os = "windows")] { - fs::read_dir(&path) - .map_err(Error::ReadDirError) - .and_then(|dir_entries| { - dir_entries - .into_iter() - .map(|entry| { - let entry = entry.map_err(Error::FileEntryError)?; - let entry_type = entry.file_type().map_err(Error::FileTypeError)?; + let mut dir = fs::read_dir(&path).await.map_err(Error::ReadDirError)?; + let mut result = Ok(()); - let removal = if entry_type.is_file() || entry_type.is_symlink() { - fs::remove_file(entry.path()) - } else { - fs::remove_dir_all(entry.path()) - }; - removal.map_err(|e| { - Error::RemoveDirError(entry.path().display().to_string(), e) - }) - }) - .collect::<Result<(), Error>>() - }) + while let Some(entry) = dir.next_entry().await.map_err(Error::FileEntryError)? { + let entry_type = match entry.file_type().await { + Ok(entry_type) => entry_type, + Err(error) => { + result = result.and(Err(Error::FileTypeError(error))); + continue; + } + }; + + let removal = if entry_type.is_file() || entry_type.is_symlink() { + fs::remove_file(entry.path()).await + } else { + fs::remove_dir_all(entry.path()).await + }; + result = result.and( + removal + .map_err(|e| Error::RemoveDirError(entry.path().display().to_string(), e)), + ); + } + result } } diff --git a/mullvad-daemon/src/settings.rs b/mullvad-daemon/src/settings.rs index abdd06127c..7862e21cd6 100644 --- a/mullvad-daemon/src/settings.rs +++ b/mullvad-daemon/src/settings.rs @@ -1,3 +1,5 @@ +#[cfg(not(target_os = "android"))] +use futures::TryFutureExt; use log::{debug, error, info}; use mullvad_types::{ relay_constraints::{BridgeSettings, BridgeState, RelaySettingsUpdate}, @@ -5,12 +7,11 @@ use mullvad_types::{ wireguard::RotationInterval, }; use std::{ - fs::{self, File}, - io, ops::Deref, path::{Path, PathBuf}, }; use talpid_types::ErrorExt; +use tokio::{fs, io}; const SETTINGS_FILE: &str = "settings.json"; @@ -54,9 +55,9 @@ pub struct SettingsPersister { impl SettingsPersister { /// Loads user settings from file. If no file is present it returns the defaults. - pub fn load(settings_dir: &Path) -> Self { + pub async fn load(settings_dir: &Path) -> Self { let path = settings_dir.join(SETTINGS_FILE); - let (mut settings, mut should_save) = Self::load_settings(&path); + let (mut settings, mut should_save) = Self::load_settings(&path).await; // Force IPv6 to be enabled on Android if cfg!(target_os = "android") { @@ -67,7 +68,7 @@ impl SettingsPersister { let mut persister = SettingsPersister { settings, path }; if should_save { - if let Err(error) = persister.save() { + if let Err(error) = persister.save().await { error!( "{}", error.display_chain_with_msg("Failed to save updated settings") @@ -78,8 +79,8 @@ impl SettingsPersister { persister } - fn load_settings(path: &Path) -> (Settings, bool) { - let error = match Self::load_settings_from_file(path) { + async fn load_settings(path: &Path) -> (Settings, bool) { + let error = match Self::load_settings_from_file(path).await { Ok(value) => return value, Err(error) => error, }; @@ -90,7 +91,7 @@ impl SettingsPersister { "No settings file found. Attempting migration from Windows update backup location" ); match windows::migrate_after_windows_update() { - Ok(Some(())) => match Self::load_settings_from_file(path) { + Ok(Some(())) => match Self::load_settings_from_file(path).await { Ok(value) => return value, Err(error) => error, }, @@ -113,10 +114,10 @@ impl SettingsPersister { (Settings::default(), true) } - fn load_settings_from_file(path: &Path) -> Result<(Settings, bool), LoadSettingsError> { + async fn load_settings_from_file(path: &Path) -> Result<(Settings, bool), LoadSettingsError> { info!("Loading settings from {}", path.display()); - let settings_bytes = fs::read(path).map_err(|error| { + let settings_bytes = fs::read(path).await.map_err(|error| { if error.kind() == io::ErrorKind::NotFound { LoadSettingsError::FileNotFound } else { @@ -133,29 +134,32 @@ impl SettingsPersister { } /// Serializes the settings and saves them to the file it was loaded from. - fn save(&mut self) -> Result<(), Error> { + async fn save(&mut self) -> Result<(), Error> { debug!("Writing settings to {}", self.path.display()); - let mut file = File::create(&self.path) - .map_err(|e| Error::WriteError(self.path.display().to_string(), e))?; - serde_json::to_writer_pretty(&mut file, &self.settings).map_err(Error::SerializeError)?; - file.sync_all() + let buffer = serde_json::to_string_pretty(&self.settings).map_err(Error::SerializeError)?; + fs::write(&self.path, &buffer) + .await .map_err(|e| Error::WriteError(self.path.display().to_string(), e)) } /// Resets default settings #[cfg(not(target_os = "android"))] - pub fn reset(&mut self) -> Result<(), Error> { + pub async fn reset(&mut self) -> Result<(), Error> { self.settings = Settings::default(); - self.save().or_else(|e| { - log::error!( - "{}", - e.display_chain_with_msg("Unable to save default settings") - ); - log::info!("Will attempt to remove settings file"); - fs::remove_file(&self.path) - .map_err(|e| Error::DeleteError(self.path.display().to_string(), e)) - }) + let path = self.path.clone(); + self.save() + .or_else(|e| async move { + log::error!( + "{}", + e.display_chain_with_msg("Unable to save default settings") + ); + log::info!("Will attempt to remove settings file"); + fs::remove_file(&path) + .map_err(|e| Error::DeleteError(path.display().to_string(), e)) + .await + }) + .await } pub fn to_settings(&self) -> Settings { @@ -164,22 +168,28 @@ impl SettingsPersister { /// Changes account number to the one given. Also saves the new settings to disk. /// The boolean in the Result indicates if the account token changed or not - pub fn set_account_token(&mut self, account_token: Option<String>) -> Result<bool, Error> { + pub async fn set_account_token( + &mut self, + account_token: Option<String>, + ) -> Result<bool, Error> { let should_save = self.settings.set_account_token(account_token); - self.update(should_save) + self.update(should_save).await } - pub fn update_relay_settings(&mut self, update: RelaySettingsUpdate) -> Result<bool, Error> { + pub async fn update_relay_settings( + &mut self, + update: RelaySettingsUpdate, + ) -> Result<bool, Error> { let should_save = self.settings.update_relay_settings(update); - self.update(should_save) + self.update(should_save).await } - pub fn set_allow_lan(&mut self, allow_lan: bool) -> Result<bool, Error> { + pub async fn set_allow_lan(&mut self, allow_lan: bool) -> Result<bool, Error> { let should_save = Self::update_field(&mut self.settings.allow_lan, allow_lan); - self.update(should_save) + self.update(should_save).await } - pub fn set_block_when_disconnected( + pub async fn set_block_when_disconnected( &mut self, block_when_disconnected: bool, ) -> Result<bool, Error> { @@ -187,43 +197,43 @@ impl SettingsPersister { &mut self.settings.block_when_disconnected, block_when_disconnected, ); - self.update(should_save) + self.update(should_save).await } - pub fn set_auto_connect(&mut self, auto_connect: bool) -> Result<bool, Error> { + pub async fn set_auto_connect(&mut self, auto_connect: bool) -> Result<bool, Error> { let should_save = Self::update_field(&mut self.settings.auto_connect, auto_connect); - self.update(should_save) + self.update(should_save).await } - pub fn set_openvpn_mssfix(&mut self, openvpn_mssfix: Option<u16>) -> Result<bool, Error> { + pub async fn set_openvpn_mssfix(&mut self, openvpn_mssfix: Option<u16>) -> Result<bool, Error> { let should_save = Self::update_field( &mut self.settings.tunnel_options.openvpn.mssfix, openvpn_mssfix, ); - self.update(should_save) + self.update(should_save).await } - pub fn set_enable_ipv6(&mut self, enable_ipv6: bool) -> Result<bool, Error> { + pub async fn set_enable_ipv6(&mut self, enable_ipv6: bool) -> Result<bool, Error> { let should_save = Self::update_field( &mut self.settings.tunnel_options.generic.enable_ipv6, enable_ipv6, ); - self.update(should_save) + self.update(should_save).await } - pub fn set_dns_options(&mut self, options: DnsOptions) -> Result<bool, Error> { + pub async fn set_dns_options(&mut self, options: DnsOptions) -> Result<bool, Error> { let should_save = Self::update_field(&mut self.settings.tunnel_options.dns_options, options); - self.update(should_save) + self.update(should_save).await } - pub fn set_wireguard_mtu(&mut self, mtu: Option<u16>) -> Result<bool, Error> { + pub async fn set_wireguard_mtu(&mut self, mtu: Option<u16>) -> Result<bool, Error> { let should_save = Self::update_field(&mut self.settings.tunnel_options.wireguard.options.mtu, mtu); - self.update(should_save) + self.update(should_save).await } - pub fn set_wireguard_rotation_interval( + pub async fn set_wireguard_rotation_interval( &mut self, interval: Option<RotationInterval>, ) -> Result<bool, Error> { @@ -231,23 +241,29 @@ impl SettingsPersister { &mut self.settings.tunnel_options.wireguard.rotation_interval, interval, ); - self.update(should_save) + self.update(should_save).await } - pub fn set_show_beta_releases(&mut self, show_beta_releases: bool) -> Result<bool, Error> { + pub async fn set_show_beta_releases( + &mut self, + show_beta_releases: bool, + ) -> Result<bool, Error> { let should_save = Self::update_field(&mut self.settings.show_beta_releases, show_beta_releases); - self.update(should_save) + self.update(should_save).await } - pub fn set_bridge_settings(&mut self, bridge_settings: BridgeSettings) -> Result<bool, Error> { + pub async fn set_bridge_settings( + &mut self, + bridge_settings: BridgeSettings, + ) -> Result<bool, Error> { let should_save = Self::update_field(&mut self.settings.bridge_settings, bridge_settings); - self.update(should_save) + self.update(should_save).await } - pub fn set_bridge_state(&mut self, bridge_state: BridgeState) -> Result<bool, Error> { + pub async fn set_bridge_state(&mut self, bridge_state: BridgeState) -> Result<bool, Error> { let should_save = self.settings.set_bridge_state(bridge_state); - self.update(should_save) + self.update(should_save).await } fn update_field<T: Eq>(field: &mut T, new_value: T) -> bool { @@ -259,9 +275,9 @@ impl SettingsPersister { } } - fn update(&mut self, should_save: bool) -> Result<bool, Error> { + async fn update(&mut self, should_save: bool) -> Result<bool, Error> { if should_save { - self.save().map(|_| true) + self.save().await.map(|_| true) } else { Ok(false) } diff --git a/mullvad-daemon/src/version_check.rs b/mullvad-daemon/src/version_check.rs index 6432fb9737..4d7be8ad38 100644 --- a/mullvad-daemon/src/version_check.rs +++ b/mullvad-daemon/src/version_check.rs @@ -7,7 +7,6 @@ use mullvad_rpc::{rest::MullvadRestHandle, AppVersionProxy}; use mullvad_types::version::{AppVersionInfo, ParsedAppVersion}; use serde::{Deserialize, Serialize}; use std::{ - fs, future::Future, io, path::{Path, PathBuf}, @@ -15,7 +14,7 @@ use std::{ }; use talpid_core::mpsc::Sender; use talpid_types::ErrorExt; -use tokio::fs::File; +use tokio::fs::{self, File}; const VERSION_INFO_FILENAME: &str = "version-info.json"; @@ -73,6 +72,9 @@ pub enum Error { #[error(display = "Failure in serialization of the version info")] Serialize(#[error(source)] serde_json::Error), + #[error(display = "Failure in deserialization of the version info")] + Deserialize(#[error(source)] serde_json::Error), + #[error(display = "Failed to check the latest app version")] Download(#[error(source)] mullvad_rpc::rest::Error), @@ -356,12 +358,14 @@ impl VersionUpdater { } } -fn try_load_cache(cache_dir: &Path) -> Result<AppVersionInfo, Error> { +async fn try_load_cache(cache_dir: &Path) -> Result<AppVersionInfo, Error> { let path = cache_dir.join(VERSION_INFO_FILENAME); log::debug!("Loading version check cache from {}", path.display()); - let file = fs::File::open(&path).map_err(Error::ReadVersionCache)?; + let content = fs::read_to_string(&path) + .map_err(Error::ReadVersionCache) + .await?; let version_info: CachedAppVersionInfo = - serde_json::from_reader(io::BufReader::new(file)).map_err(Error::Serialize)?; + serde_json::from_str(&content).map_err(Error::Deserialize)?; if version_info.cached_from_version == PRODUCT_VERSION { Ok(version_info.version_info) @@ -370,8 +374,8 @@ fn try_load_cache(cache_dir: &Path) -> Result<AppVersionInfo, Error> { } } -pub fn load_cache(cache_dir: &Path) -> Option<AppVersionInfo> { - match try_load_cache(cache_dir) { +pub async fn load_cache(cache_dir: &Path) -> Option<AppVersionInfo> { + match try_load_cache(cache_dir).await { Ok(app_version_info) => Some(app_version_info), Err(error) => { log::warn!( |
