diff options
| author | Markus Pettersson <markus.pettersson@mullvad.net> | 2024-02-02 16:14:53 +0100 |
|---|---|---|
| committer | Markus Pettersson <markus.pettersson@mullvad.net> | 2024-02-09 13:04:06 +0100 |
| commit | a6a26bf92ddd690c85e7cefbca1c8e5bb7fe7683 (patch) | |
| tree | ea5b784ceca66b772e8065ce6686a9cefdc3faeb /talpid-core | |
| parent | 7fe5f5fe63621a448623ee53c651ed2dd50b9d4a (diff) | |
| download | mullvadvpn-a6a26bf92ddd690c85e7cefbca1c8e5bb7fe7683.tar.xz mullvadvpn-a6a26bf92ddd690c85e7cefbca1c8e5bb7fe7683.zip | |
Detect available IP versions
Try to detect available IP versions by looking at the available routes
on the host. On Linux, we check if there exists IPv4 and/or IPv6 routes
to some public IP addresses. On macOS and Windows, we check if there
exists default routes for IPv4 and/or IPv6. On Android, we check if
there is any connectivity at all.
The intention is to be able to generate better default constraints for
tunnel endpoints. If we can detect "working" IPv4 and/or IPv6 and
forward this information to a `TunnelParametersGenerator`, we may choose
to connect to a Wireguard relay using IPv6 as part of our
retry-strategy. This has not been possible before.
Diffstat (limited to 'talpid-core')
| -rw-r--r-- | talpid-core/src/offline/android.rs | 47 | ||||
| -rw-r--r-- | talpid-core/src/offline/linux.rs | 48 | ||||
| -rw-r--r-- | talpid-core/src/offline/macos.rs | 83 | ||||
| -rw-r--r-- | talpid-core/src/offline/mod.rs | 34 | ||||
| -rw-r--r-- | talpid-core/src/offline/windows.rs | 83 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connected_state.rs | 6 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connecting_state.rs | 8 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/disconnected_state.rs | 4 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/disconnecting_state.rs | 16 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/error_state.rs | 8 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/mod.rs | 22 |
11 files changed, 212 insertions, 147 deletions
diff --git a/talpid-core/src/offline/android.rs b/talpid-core/src/offline/android.rs index de9708f096..936da896bd 100644 --- a/talpid-core/src/offline/android.rs +++ b/talpid-core/src/offline/android.rs @@ -4,13 +4,13 @@ use jnix::{ self, objects::{GlobalRef, JObject, JValue}, signature::{JavaType, Primitive}, - sys::{jboolean, jlong, JNI_FALSE}, + sys::{jboolean, jlong, JNI_TRUE}, JNIEnv, JavaVM, }, JnixEnv, }; use std::sync::{Arc, Weak}; -use talpid_types::{android::AndroidContext, ErrorExt}; +use talpid_types::{android::AndroidContext, net::Connectivity, ErrorExt}; #[derive(err_derive::Error, Debug)] #[error(no_from)] @@ -43,13 +43,13 @@ pub struct MonitorHandle { jvm: Arc<JavaVM>, class: GlobalRef, object: GlobalRef, - _sender: Arc<UnboundedSender<bool>>, + _sender: Arc<UnboundedSender<Connectivity>>, } impl MonitorHandle { pub fn new( android_context: AndroidContext, - sender: Arc<UnboundedSender<bool>>, + sender: Arc<UnboundedSender<Connectivity>>, ) -> Result<Self, Error> { let env = JnixEnv::from( android_context @@ -101,30 +101,29 @@ impl MonitorHandle { } #[allow(clippy::unused_async)] - pub async fn host_is_offline(&self) -> bool { - match self.get_is_connected() { - Ok(is_connected) => !is_connected, - Err(error) => { + pub async fn connectivity(&self) -> Connectivity { + self.get_is_connected() + .map(|connected| Connectivity::Status { connected }) + .unwrap_or_else(|error| { log::error!( "{}", error.display_chain_with_msg("Failed to check connectivity status") ); - false - } - } + Connectivity::PresumeOnline + }) } fn get_is_connected(&self) -> Result<bool, Error> { - let result = self.call_method( + let is_connected = self.call_method( "isConnected", "()Z", &[], JavaType::Primitive(Primitive::Boolean), )?; - match result { - JValue::Bool(JNI_FALSE) => Ok(false), - JValue::Bool(_) => Ok(true), + match is_connected { + JValue::Bool(JNI_TRUE) => Ok(true), + JValue::Bool(_) => Ok(false), value => Err(Error::InvalidMethodResult( "ConnectivityListener", "isConnected", @@ -133,7 +132,7 @@ impl MonitorHandle { } } - fn set_sender(&self, sender: Weak<UnboundedSender<bool>>) -> Result<(), Error> { + fn set_sender(&self, sender: Weak<UnboundedSender<Connectivity>>) -> Result<(), Error> { let sender_ptr = Box::new(sender); let sender_address = Box::into_raw(sender_ptr) as jlong; @@ -182,14 +181,16 @@ impl MonitorHandle { pub extern "system" fn Java_net_mullvad_talpid_ConnectivityListener_notifyConnectivityChange( _: JNIEnv<'_>, _: JObject<'_>, - is_connected: jboolean, + connected: jboolean, sender_address: jlong, ) { + let connected = JNI_TRUE == connected; let sender_ref = Box::leak(unsafe { get_sender_from_address(sender_address) }); - let is_offline = is_connected == JNI_FALSE; - if let Some(sender) = sender_ref.upgrade() { - if sender.unbounded_send(is_offline).is_err() { + if sender + .unbounded_send(Connectivity::Status { connected }) + .is_err() + { log::warn!("Failed to send offline change event"); } } @@ -206,13 +207,13 @@ pub extern "system" fn Java_net_mullvad_talpid_ConnectivityListener_destroySende let _ = unsafe { get_sender_from_address(sender_address) }; } -unsafe fn get_sender_from_address(address: jlong) -> Box<Weak<UnboundedSender<bool>>> { - Box::from_raw(address as *mut Weak<UnboundedSender<bool>>) +unsafe fn get_sender_from_address(address: jlong) -> Box<Weak<UnboundedSender<Connectivity>>> { + Box::from_raw(address as *mut Weak<UnboundedSender<Connectivity>>) } #[allow(clippy::unused_async)] pub async fn spawn_monitor( - sender: UnboundedSender<bool>, + sender: UnboundedSender<Connectivity>, android_context: AndroidContext, ) -> Result<MonitorHandle, Error> { let sender = Arc::new(sender); diff --git a/talpid-core/src/offline/linux.rs b/talpid-core/src/offline/linux.rs index 09db30e359..9f76a19591 100644 --- a/talpid-core/src/offline/linux.rs +++ b/talpid-core/src/offline/linux.rs @@ -4,7 +4,7 @@ use std::{ sync::Arc, }; use talpid_routing::{self, RouteManagerHandle}; -use talpid_types::ErrorExt; +use talpid_types::{net::Connectivity, ErrorExt}; pub type Result<T> = std::result::Result<T, Error>; @@ -18,30 +18,31 @@ pub enum Error { pub struct MonitorHandle { route_manager: RouteManagerHandle, fwmark: Option<u32>, - _notify_tx: Arc<UnboundedSender<bool>>, + _notify_tx: Arc<UnboundedSender<Connectivity>>, } +/// A non-local IPv4 address. const PUBLIC_INTERNET_ADDRESS_V4: IpAddr = IpAddr::V4(Ipv4Addr::new(193, 138, 218, 78)); +/// A non-local IPv6 address. const PUBLIC_INTERNET_ADDRESS_V6: IpAddr = IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6)); impl MonitorHandle { - pub async fn host_is_offline(&self) -> bool { - match public_ip_unreachable(&self.route_manager, self.fwmark).await { - Ok(is_offline) => is_offline, - Err(err) => { + pub async fn connectivity(&self) -> Connectivity { + public_ip_unreachable(&self.route_manager, self.fwmark) + .await + .unwrap_or_else(|err| { log::error!( "Failed to verify offline state: {}. Presuming connectivity", err ); - false - } - } + Connectivity::PresumeOnline + }) } } pub async fn spawn_monitor( - notify_tx: UnboundedSender<bool>, + notify_tx: UnboundedSender<Connectivity>, route_manager: RouteManagerHandle, fwmark: Option<u32>, ) -> Result<MonitorHandle> { @@ -71,7 +72,7 @@ pub async fn spawn_monitor( "{}", err.display_chain_with_msg("Failed to infer offline state") ); - false + Connectivity::PresumeOnline }); if new_offline_state != is_offline { is_offline = new_offline_state; @@ -86,15 +87,20 @@ pub async fn spawn_monitor( Ok(monitor_handle) } -async fn public_ip_unreachable(handle: &RouteManagerHandle, fwmark: Option<u32>) -> Result<bool> { - Ok(handle - .get_destination_route(PUBLIC_INTERNET_ADDRESS_V4, fwmark) - .await - .map_err(Error::RouteManagerError)? - .is_none() - && handle - .get_destination_route(PUBLIC_INTERNET_ADDRESS_V6, fwmark) +async fn public_ip_unreachable( + handle: &RouteManagerHandle, + fwmark: Option<u32>, +) -> Result<Connectivity> { + let route_exists = |destination| async move { + handle + .get_destination_route(destination, fwmark) .await - .unwrap_or(None) - .is_none()) + .map_err(Error::RouteManagerError) + .map(|route| route.is_some()) + }; + let connectivity = Connectivity::Status { + ipv4: route_exists(PUBLIC_INTERNET_ADDRESS_V4).await?, + ipv6: route_exists(PUBLIC_INTERNET_ADDRESS_V6).await?, + }; + Ok(connectivity) } diff --git a/talpid-core/src/offline/macos.rs b/talpid-core/src/offline/macos.rs index 926d68918c..dff62a975d 100644 --- a/talpid-core/src/offline/macos.rs +++ b/talpid-core/src/offline/macos.rs @@ -18,6 +18,7 @@ use std::{ time::Duration, }; use talpid_routing::{DefaultRouteEvent, RouteManagerHandle}; +use talpid_types::net::Connectivity; const SYNTHETIC_OFFLINE_DURATION: Duration = Duration::from_secs(1); @@ -28,33 +29,42 @@ pub enum Error { } pub struct MonitorHandle { - state: Arc<Mutex<ConnectivityState>>, - _notify_tx: Arc<UnboundedSender<bool>>, -} - -#[derive(Clone)] -struct ConnectivityState { - v4_connectivity: bool, - v6_connectivity: bool, -} - -impl ConnectivityState { - fn get_connectivity(&self) -> bool { - self.v4_connectivity || self.v6_connectivity - } + state: Arc<Mutex<ConnectivityInner>>, + _notify_tx: Arc<UnboundedSender<Connectivity>>, } impl MonitorHandle { /// Return whether the host is offline #[allow(clippy::unused_async)] - pub async fn host_is_offline(&self) -> bool { + pub async fn connectivity(&self) -> Connectivity { let state = self.state.lock().unwrap(); - !state.get_connectivity() + state.into_connectivity() + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +struct ConnectivityInner { + /// Whether IPv4 connectivity seems to be available on the host. + ipv4: bool, + /// Whether IPv6 connectivity seems to be available on the host. + ipv6: bool, +} + +impl ConnectivityInner { + fn into_connectivity(self) -> Connectivity { + Connectivity::Status { + ipv4: self.ipv4, + ipv6: self.ipv6, + } + } + + fn is_online(&self) -> bool { + self.into_connectivity().is_online() } } pub async fn spawn_monitor( - notify_tx: UnboundedSender<bool>, + notify_tx: UnboundedSender<Connectivity>, route_manager_handle: RouteManagerHandle, ) -> Result<MonitorHandle, Error> { let notify_tx = Arc::new(notify_tx); @@ -62,7 +72,7 @@ pub async fn spawn_monitor( // note: begin observing before initializing the state let route_listener = route_manager_handle.default_route_listener().await?; - let (v4_connectivity, v6_connectivity) = match route_manager_handle.get_default_routes().await { + let (ipv4, ipv6) = match route_manager_handle.get_default_routes().await { Ok((v4_route, v6_route)) => (v4_route.is_some(), v6_route.is_some()), Err(error) => { log::warn!("Failed to initialize offline monitor: {error}"); @@ -72,11 +82,8 @@ pub async fn spawn_monitor( } }; - let state = ConnectivityState { - v4_connectivity, - v6_connectivity, - }; - let mut real_state = state.clone(); + let state = ConnectivityInner { ipv4, ipv6 }; + let mut real_state = state; let state = Arc::new(Mutex::new(state)); @@ -95,16 +102,17 @@ pub async fn spawn_monitor( let Some(state) = weak_state.upgrade() else { break; }; - let mut state = state.lock().unwrap(); - *state = real_state.clone(); - if state.get_connectivity() { + let mut state = state.lock().unwrap(); + if real_state.is_online() { log::info!("Connectivity changed: Connected"); let Some(tx) = weak_notify_tx.upgrade() else { break; }; - let _ = tx.unbounded_send(false); + let _ = tx.unbounded_send(real_state.into_connectivity()); } + + *state = real_state; } route_event = route_listener.next() => { @@ -115,16 +123,16 @@ pub async fn spawn_monitor( // Update real state match event { DefaultRouteEvent::AddedOrChangedV4 => { - real_state.v4_connectivity = true; + real_state.ipv4 = true; } DefaultRouteEvent::AddedOrChangedV6 => { - real_state.v6_connectivity = true; + real_state.ipv6 = true; } DefaultRouteEvent::RemovedV4 => { - real_state.v4_connectivity = false; + real_state.ipv4 = false; } DefaultRouteEvent::RemovedV6 => { - real_state.v6_connectivity = false; + real_state.ipv6 = false; } } @@ -134,18 +142,19 @@ pub async fn spawn_monitor( break; }; let mut state = state.lock().unwrap(); - let previous_connectivity = state.get_connectivity(); - state.v4_connectivity = false; - state.v6_connectivity = false; + let previous_connectivity = *state; + state.ipv4 = false; + state.ipv6 = false; - if previous_connectivity { + if previous_connectivity.is_online() { let Some(tx) = weak_notify_tx.upgrade() else { break; }; - let _ = tx.unbounded_send(true); + let _ = tx.unbounded_send(state.into_connectivity()); log::info!("Connectivity changed: Offline"); } - if real_state.get_connectivity() { + + if real_state.is_online() { timeout = Box::pin(tokio::time::sleep(SYNTHETIC_OFFLINE_DURATION)).fuse(); } } diff --git a/talpid-core/src/offline/mod.rs b/talpid-core/src/offline/mod.rs index ca99c61774..1a9a17e788 100644 --- a/talpid-core/src/offline/mod.rs +++ b/talpid-core/src/offline/mod.rs @@ -4,6 +4,7 @@ use once_cell::sync::Lazy; use talpid_routing::RouteManagerHandle; #[cfg(target_os = "android")] use talpid_types::android::AndroidContext; +use talpid_types::net::Connectivity; #[cfg(target_os = "macos")] #[path = "macos.rs"] @@ -33,35 +34,46 @@ pub use self::imp::Error; pub struct MonitorHandle(Option<imp::MonitorHandle>); impl MonitorHandle { - pub async fn host_is_offline(&self) -> bool { + pub async fn connectivity(&self) -> Connectivity { match self.0.as_ref() { - Some(monitor) => monitor.host_is_offline().await, - None => false, + Some(monitor) => monitor.connectivity().await, + None => Connectivity::PresumeOnline, } } } +#[cfg(not(target_os = "android"))] pub async fn spawn_monitor( - sender: UnboundedSender<bool>, - #[cfg(not(target_os = "android"))] route_manager: RouteManagerHandle, + sender: UnboundedSender<Connectivity>, + route_manager: RouteManagerHandle, #[cfg(target_os = "linux")] fwmark: Option<u32>, - #[cfg(target_os = "android")] android_context: AndroidContext, ) -> Result<MonitorHandle, Error> { - let monitor = if !*FORCE_DISABLE_OFFLINE_MONITOR { + let monitor = if *FORCE_DISABLE_OFFLINE_MONITOR { + None + } else { Some( imp::spawn_monitor( sender, - #[cfg(not(target_os = "android"))] route_manager, #[cfg(target_os = "linux")] fwmark, - #[cfg(target_os = "android")] - android_context, ) .await?, ) - } else { + }; + + Ok(MonitorHandle(monitor)) +} + +#[cfg(target_os = "android")] +pub async fn spawn_monitor( + sender: UnboundedSender<Connectivity>, + android_context: AndroidContext, +) -> Result<MonitorHandle, Error> { + let monitor = if *FORCE_DISABLE_OFFLINE_MONITOR { None + } else { + Some(imp::spawn_monitor(sender, android_context).await?) }; Ok(MonitorHandle(monitor)) diff --git a/talpid-core/src/offline/windows.rs b/talpid-core/src/offline/windows.rs index 6539e6e256..caa3ac8f5e 100644 --- a/talpid-core/src/offline/windows.rs +++ b/talpid-core/src/offline/windows.rs @@ -1,5 +1,3 @@ -use talpid_routing::{get_best_default_route, CallbackHandle, EventType, RouteManagerHandle}; - use crate::window::{PowerManagementEvent, PowerManagementListener}; use futures::channel::mpsc::UnboundedSender; use parking_lot::Mutex; @@ -8,7 +6,8 @@ use std::{ sync::{Arc, Weak}, time::Duration, }; -use talpid_types::ErrorExt; +use talpid_routing::{get_best_default_route, CallbackHandle, EventType, RouteManagerHandle}; +use talpid_types::{net::Connectivity, ErrorExt}; use talpid_windows::net::AddressFamily; #[derive(err_derive::Error, Debug)] @@ -22,23 +21,25 @@ pub enum Error { pub struct BroadcastListener { system_state: Arc<Mutex<SystemState>>, _callback_handle: CallbackHandle, - _notify_tx: Arc<UnboundedSender<bool>>, + _notify_tx: Arc<UnboundedSender<Connectivity>>, } unsafe impl Send for BroadcastListener {} impl BroadcastListener { pub async fn start( - notify_tx: UnboundedSender<bool>, + notify_tx: UnboundedSender<Connectivity>, route_manager_handle: RouteManagerHandle, mut power_mgmt_rx: PowerManagementListener, ) -> Result<Self, Error> { let notify_tx = Arc::new(notify_tx); - let (v4_connectivity, v6_connectivity) = Self::check_initial_connectivity(); + let (ipv4, ipv6) = Self::check_initial_connectivity(); let system_state = Arc::new(Mutex::new(SystemState { - v4_connectivity, - v6_connectivity, - suspended: false, + connectivity: ConnectivityInner { + ipv4, + ipv6, + suspended: false, + }, notify_tx: Arc::downgrade(¬ify_tx), })); @@ -139,9 +140,9 @@ impl BroadcastListener { } #[allow(clippy::unused_async)] - pub async fn host_is_offline(&self) -> bool { + pub async fn connectivity(&self) -> Connectivity { let state = self.system_state.lock(); - state.is_offline_currently() + state.connectivity.into_connectivity() } } @@ -153,10 +154,8 @@ enum StateChange { } struct SystemState { - v4_connectivity: bool, - v6_connectivity: bool, - suspended: bool, - notify_tx: Weak<UnboundedSender<bool>>, + connectivity: ConnectivityInner, + notify_tx: Weak<UnboundedSender<Connectivity>>, } impl SystemState { @@ -164,23 +163,21 @@ impl SystemState { let old_state = self.is_offline_currently(); match change { StateChange::NetworkV4Connectivity(connectivity) => { - self.v4_connectivity = connectivity; + self.connectivity.ipv4 = connectivity; } - StateChange::NetworkV6Connectivity(connectivity) => { - self.v6_connectivity = connectivity; + self.connectivity.ipv6 = connectivity; } - StateChange::Suspended(suspended) => { - self.suspended = suspended; + self.connectivity.suspended = suspended; } }; - let new_state = self.is_offline_currently(); + let new_state = self.connectivity.is_offline(); if old_state != new_state { log::info!("Connectivity changed: {}", is_offline_str(new_state)); if let Some(notify_tx) = self.notify_tx.upgrade() { - if let Err(e) = notify_tx.unbounded_send(new_state) { + if let Err(e) = notify_tx.unbounded_send(self.connectivity.into_connectivity()) { log::error!("Failed to send new offline state to daemon: {}", e); } } @@ -188,7 +185,7 @@ impl SystemState { } fn is_offline_currently(&self) -> bool { - (!self.v4_connectivity && !self.v6_connectivity) || self.suspended + self.connectivity.is_offline() } } @@ -204,7 +201,7 @@ fn is_offline_str(offline: bool) -> &'static str { pub type MonitorHandle = BroadcastListener; pub async fn spawn_monitor( - sender: UnboundedSender<bool>, + sender: UnboundedSender<Connectivity>, route_manager_handle: RouteManagerHandle, ) -> Result<MonitorHandle, Error> { let power_mgmt_rx = crate::window::PowerManagementListener::new(); @@ -215,3 +212,41 @@ fn apply_system_state_change(state: Arc<Mutex<SystemState>>, change: StateChange let mut state = state.lock(); state.apply_change(change); } + +#[derive(Clone, Copy, Debug)] +struct ConnectivityInner { + /// Whether IPv4 connectivity seems to be available on the host. + ipv4: bool, + /// Whether IPv6 connectivity seems to be available on the host. + ipv6: bool, + /// The host is suspended. + suspended: bool, +} + +impl ConnectivityInner { + /// Map [`ConnectivityInner`] to the public [`Connectivity`]. + /// + /// # Note + /// + /// If the host is suspended, there is a great likelihood that we should + /// consider the host to be offline. We synthesize this by setting both + /// `ipv4` and `ipv6` availability to `false`. + fn into_connectivity(self) -> Connectivity { + if self.suspended { + Connectivity::Status { + ipv4: false, + ipv6: false, + } + } else { + Connectivity::Status { + ipv4: self.ipv4, + ipv6: self.ipv6, + } + } + } + + /// See [`Connectivity::is_offline`] for details. + fn is_offline(&self) -> bool { + self.into_connectivity().is_offline() + } +} diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs index 6f32b796c3..c73232a895 100644 --- a/talpid-core/src/tunnel_state_machine/connected_state.rs +++ b/talpid-core/src/tunnel_state_machine/connected_state.rs @@ -298,9 +298,9 @@ impl ConnectedState { let _ = complete_tx.send(()); SameState(self) } - Some(TunnelCommand::IsOffline(is_offline)) => { - shared_values.is_offline = is_offline; - if is_offline { + Some(TunnelCommand::Connectivity(connectivity)) => { + shared_values.connectivity = connectivity; + if connectivity.is_offline() { self.disconnect( shared_values, AfterDisconnect::Block(ErrorStateCause::IsOffline), diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index 3b0afd8abf..927de207bf 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -57,7 +57,7 @@ impl ConnectingState { shared_values: &mut SharedTunnelStateValues, retry_attempt: u32, ) -> (Box<dyn TunnelState>, TunnelStateTransition) { - if shared_values.is_offline { + if shared_values.connectivity.is_offline() { // FIXME: Temporary: Nudge route manager to update the default interface #[cfg(target_os = "macos")] if let Ok(handle) = shared_values.route_manager.handle() { @@ -457,9 +457,9 @@ impl ConnectingState { let _ = complete_tx.send(()); SameState(self) } - Some(TunnelCommand::IsOffline(is_offline)) => { - shared_values.is_offline = is_offline; - if is_offline { + Some(TunnelCommand::Connectivity(connectivity)) => { + shared_values.connectivity = connectivity; + if connectivity.is_offline() { self.disconnect( shared_values, AfterDisconnect::Block(ErrorStateCause::IsOffline), diff --git a/talpid-core/src/tunnel_state_machine/disconnected_state.rs b/talpid-core/src/tunnel_state_machine/disconnected_state.rs index 49ed2575a3..00af35abd5 100644 --- a/talpid-core/src/tunnel_state_machine/disconnected_state.rs +++ b/talpid-core/src/tunnel_state_machine/disconnected_state.rs @@ -200,8 +200,8 @@ impl TunnelState for DisconnectedState { SameState(self) } } - Some(TunnelCommand::IsOffline(is_offline)) => { - shared_values.is_offline = is_offline; + Some(TunnelCommand::Connectivity(connectivity)) => { + shared_values.connectivity = connectivity; SameState(self) } Some(TunnelCommand::Connect) => NewState(ConnectingState::enter(shared_values, 0)), diff --git a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs index 185d2f7d0a..22fbcd04a3 100644 --- a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs @@ -63,8 +63,8 @@ impl DisconnectingState { let _ = complete_tx.send(()); AfterDisconnect::Nothing } - Some(TunnelCommand::IsOffline(is_offline)) => { - shared_values.is_offline = is_offline; + Some(TunnelCommand::Connectivity(connectivity)) => { + shared_values.connectivity = connectivity; AfterDisconnect::Nothing } Some(TunnelCommand::Connect) => AfterDisconnect::Reconnect(0), @@ -105,9 +105,9 @@ impl DisconnectingState { let _ = complete_tx.send(()); AfterDisconnect::Block(reason) } - Some(TunnelCommand::IsOffline(is_offline)) => { - shared_values.is_offline = is_offline; - if !is_offline && matches!(reason, ErrorStateCause::IsOffline) { + Some(TunnelCommand::Connectivity(connectivity)) => { + shared_values.connectivity = connectivity; + if !connectivity.is_offline() && matches!(reason, ErrorStateCause::IsOffline) { AfterDisconnect::Reconnect(0) } else { AfterDisconnect::Block(reason) @@ -152,9 +152,9 @@ impl DisconnectingState { let _ = complete_tx.send(()); AfterDisconnect::Reconnect(retry_attempt) } - Some(TunnelCommand::IsOffline(is_offline)) => { - shared_values.is_offline = is_offline; - if is_offline { + Some(TunnelCommand::Connectivity(connectivity)) => { + shared_values.connectivity = connectivity; + if connectivity.is_offline() { AfterDisconnect::Block(ErrorStateCause::IsOffline) } else { AfterDisconnect::Reconnect(retry_attempt) diff --git a/talpid-core/src/tunnel_state_machine/error_state.rs b/talpid-core/src/tunnel_state_machine/error_state.rs index 2f82cb4cf5..538ee5de1a 100644 --- a/talpid-core/src/tunnel_state_machine/error_state.rs +++ b/talpid-core/src/tunnel_state_machine/error_state.rs @@ -181,9 +181,11 @@ impl TunnelState for ErrorState { let _ = complete_tx.send(()); SameState(self) } - Some(TunnelCommand::IsOffline(is_offline)) => { - shared_values.is_offline = is_offline; - if !is_offline && matches!(self.block_reason, ErrorStateCause::IsOffline) { + Some(TunnelCommand::Connectivity(connectivity)) => { + shared_values.connectivity = connectivity; + if !connectivity.is_offline() + && matches!(self.block_reason, ErrorStateCause::IsOffline) + { Self::reset_dns(shared_values); NewState(ConnectingState::enter(shared_values, 0)) } else { diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs index 5957b2f731..6be9b8a1c3 100644 --- a/talpid-core/src/tunnel_state_machine/mod.rs +++ b/talpid-core/src/tunnel_state_machine/mod.rs @@ -42,7 +42,7 @@ use std::{ #[cfg(target_os = "android")] use talpid_types::{android::AndroidContext, ErrorExt}; use talpid_types::{ - net::{AllowedEndpoint, TunnelParameters}, + net::{AllowedEndpoint, Connectivity, TunnelParameters}, tunnel::{ErrorStateCause, ParameterGenerationError, TunnelStateTransition}, }; @@ -122,7 +122,7 @@ pub async fn spawn( log_dir: Option<PathBuf>, resource_dir: PathBuf, state_change_listener: impl Sender<TunnelStateTransition> + Send + 'static, - offline_state_listener: mpsc::UnboundedSender<bool>, + offline_state_listener: mpsc::UnboundedSender<Connectivity>, #[cfg(target_os = "windows")] volume_update_rx: mpsc::UnboundedReceiver<()>, #[cfg(target_os = "android")] android_context: AndroidContext, #[cfg(target_os = "linux")] linux_ids: LinuxNetworkingIdentifiers, @@ -199,7 +199,7 @@ pub enum TunnelCommand { /// Enable or disable the block_when_disconnected feature. BlockWhenDisconnected(bool, oneshot::Sender<()>), /// Notify the state machine of the connectivity of the device. - IsOffline(bool), + Connectivity(Connectivity), /// Open tunnel connection. Connect, /// Close tunnel connection. @@ -241,7 +241,7 @@ struct TunnelStateMachine { struct TunnelStateMachineInitArgs<G: TunnelParametersGenerator> { settings: InitialTunnelState, command_tx: std::sync::Weak<mpsc::UnboundedSender<TunnelCommand>>, - offline_state_tx: mpsc::UnboundedSender<bool>, + offline_state_tx: mpsc::UnboundedSender<Connectivity>, tunnel_parameters_generator: G, tun_provider: TunProvider, log_dir: Option<PathBuf>, @@ -319,13 +319,13 @@ impl TunnelStateMachine { let (offline_tx, mut offline_rx) = mpsc::unbounded(); let initial_offline_state_tx = args.offline_state_tx.clone(); tokio::spawn(async move { - while let Some(offline) = offline_rx.next().await { + while let Some(connectivity) = offline_rx.next().await { if let Some(tx) = args.command_tx.upgrade() { - let _ = tx.unbounded_send(TunnelCommand::IsOffline(offline)); + let _ = tx.unbounded_send(TunnelCommand::Connectivity(connectivity)); } else { break; } - let _ = args.offline_state_tx.unbounded_send(offline); + let _ = args.offline_state_tx.unbounded_send(connectivity); } }); let offline_monitor = offline::spawn_monitor( @@ -339,8 +339,8 @@ impl TunnelStateMachine { ) .await .map_err(Error::OfflineMonitorError)?; - let is_offline = offline_monitor.host_is_offline().await; - let _ = initial_offline_state_tx.unbounded_send(is_offline); + let connectivity = offline_monitor.connectivity().await; + let _ = initial_offline_state_tx.unbounded_send(connectivity); #[cfg(windows)] split_tunnel @@ -357,7 +357,7 @@ impl TunnelStateMachine { _offline_monitor: offline_monitor, allow_lan: args.settings.allow_lan, block_when_disconnected: args.settings.block_when_disconnected, - is_offline, + connectivity, dns_servers: args.settings.dns_servers, allowed_endpoint: args.settings.allowed_endpoint, tunnel_parameters_generator: Box::new(args.tunnel_parameters_generator), @@ -441,7 +441,7 @@ struct SharedTunnelStateValues { /// Should network access be allowed when in the disconnected state. block_when_disconnected: bool, /// True when the computer is known to be offline. - is_offline: bool, + connectivity: Connectivity, /// DNS servers to use (overriding default). dns_servers: Option<Vec<IpAddr>>, /// Endpoint that should not be blocked by the firewall. |
