summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2021-03-31 15:47:17 +0200
committerDavid Lönnhager <david.l@mullvad.net>2021-03-31 15:47:17 +0200
commitafa8cea611744de08125ac52215cc764f4a84eed (patch)
treece88cd605a6755c03b8d363502b558a09f3c93c2
parentad1070d5252ff06691667fecebf6a31451683616 (diff)
parent7333c583f5e7094bd8ff218c0115ca8f808cb36d (diff)
downloadmullvadvpn-afa8cea611744de08125ac52215cc764f4a84eed.tar.xz
mullvadvpn-afa8cea611744de08125ac52215cc764f4a84eed.zip
Merge branch 'async-fs-fix'
-rw-r--r--mullvad-daemon/src/lib.rs248
-rw-r--r--mullvad-daemon/src/settings.rs122
-rw-r--r--mullvad-daemon/src/version_check.rs18
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!(