summaryrefslogtreecommitdiffhomepage
path: root/ios
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-11-30 14:40:28 +0100
committerAndrej Mihajlov <and@mullvad.net>2022-11-30 14:40:28 +0100
commit4c83a396fda3c70bfa872e4b0d88dac1297d21dc (patch)
treef506922cb88234eb2088581d88517d828a32f1b8 /ios
parent4bf5b1c5df0776d18e7a31f40c0d840e508b4b22 (diff)
parent3a79afbca1c1b12a372ede2d88ef16cbcf94f3b8 (diff)
downloadmullvadvpn-4c83a396fda3c70bfa872e4b0d88dac1297d21dc.tar.xz
mullvadvpn-4c83a396fda3c70bfa872e4b0d88dac1297d21dc.zip
Merge branch 'improve-network-path-status-reporting'
Diffstat (limited to 'ios')
-rw-r--r--ios/MullvadTypes/PacketTunnelStatus.swift1
-rw-r--r--ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift83
2 files changed, 43 insertions, 41 deletions
diff --git a/ios/MullvadTypes/PacketTunnelStatus.swift b/ios/MullvadTypes/PacketTunnelStatus.swift
index 1e4cbf18ba..2b5a1abf91 100644
--- a/ios/MullvadTypes/PacketTunnelStatus.swift
+++ b/ios/MullvadTypes/PacketTunnelStatus.swift
@@ -42,6 +42,7 @@ public struct PacketTunnelStatus: Codable, Equatable {
/// Last performed device check.
public var deviceCheck: DeviceCheck?
+
/// Current relay.
public var tunnelRelay: PacketTunnelRelay?
diff --git a/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift b/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift
index 4614c8e733..b13659127e 100644
--- a/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift
+++ b/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift
@@ -54,6 +54,10 @@ final class TunnelMonitor: PingerDelegate {
/// Initialized and doing nothing.
case stopped
+ /// Preparing to start.
+ /// Intermediate state before recieving the first path update.
+ case pendingStart
+
/// Establishing connection.
case connecting
@@ -167,7 +171,7 @@ final class TunnelMonitor: PingerDelegate {
return maxEstablishTimeout
}
- case .connected, .waitingConnectivity, .stopped:
+ case .pendingStart, .connected, .waitingConnectivity, .stopped:
return pingTimeout
}
}
@@ -305,6 +309,7 @@ final class TunnelMonitor: PingerDelegate {
}
self.probeAddress = probeAddress
+ state.connectionState = .pendingStart
let pathMonitor = NWPathMonitor()
pathMonitor.pathUpdateHandler = { [weak self] path in
@@ -312,16 +317,6 @@ final class TunnelMonitor: PingerDelegate {
}
pathMonitor.start(queue: internalQueue)
self.pathMonitor = pathMonitor
-
- if isNetworkPathReachable(pathMonitor.currentPath) {
- logger.debug("Start monitoring connection.")
-
- startMonitoring()
- } else {
- logger.debug("Wait for network to become reachable before starting monitoring.")
-
- state.connectionState = .waitingConnectivity
- }
}
private func stopNoQueue(forRestart: Bool = false) {
@@ -423,7 +418,7 @@ final class TunnelMonitor: PingerDelegate {
case .connecting, .connected:
self.startConnectivityCheckTimer()
- case .stopped, .waitingConnectivity:
+ case .pendingStart, .stopped, .waitingConnectivity:
break
}
}
@@ -442,21 +437,44 @@ final class TunnelMonitor: PingerDelegate {
}
private func handleNetworkPathUpdate(_ networkPath: Network.NWPath) {
- let isReachable = isNetworkPathReachable(networkPath)
+ let pathStatus = networkPath.status
+ let isReachable = pathStatus == .requiresConnection || pathStatus == .satisfied
+ let hasPhysicalNetworkInterface = networkPath.availableInterfaces.contains { nw in
+ return nw.type == .wifi || nw.type == .cellular || nw.type == .wiredEthernet
+ }
- switch (isReachable, state.connectionState) {
- case (true, .waitingConnectivity):
- logger.debug("Network is reachable. Resume monitoring.")
+ lazy var isRoutableViaUtun = isTunnelInterfaceUp(networkPath) &&
+ hasPhysicalNetworkInterface && isReachable
+
+ switch state.connectionState {
+ case .pendingStart:
+ // Wait for tunnel interface to appear first.
+ guard isTunnelInterfaceUp(networkPath) else { return }
+ if isReachable, hasPhysicalNetworkInterface {
+ logger.debug("Start monitoring connection.")
+ startMonitoring()
+ sendDelegateNetworkStatusChange(true)
+ } else {
+ logger.debug("Wait for network to become reachable before starting monitoring.")
+ state.connectionState = .waitingConnectivity
+ sendDelegateNetworkStatusChange(false)
+ }
+
+ case .waitingConnectivity:
+ guard isRoutableViaUtun else { return }
+
+ logger.debug("Network is reachable. Resume monitoring.")
startMonitoring()
- sendDelegateNetworkStatusChange(isReachable)
+ sendDelegateNetworkStatusChange(true)
- case (false, .connecting), (false, .connected):
- logger.debug("Network is unreachable. Pause monitoring.")
+ case .connecting, .connected:
+ guard !isRoutableViaUtun else { return }
+ logger.debug("Network is unreachable. Pause monitoring.")
state.connectionState = .waitingConnectivity
stopMonitoring(resetRetryAttempt: true)
- sendDelegateNetworkStatusChange(isReachable)
+ sendDelegateNetworkStatusChange(false)
default:
break
@@ -552,7 +570,7 @@ final class TunnelMonitor: PingerDelegate {
case .connecting, .connected:
startConnectivityCheckTimer()
- case .stopped, .waitingConnectivity:
+ case .pendingStart, .stopped, .waitingConnectivity:
break
}
}
@@ -564,7 +582,7 @@ final class TunnelMonitor: PingerDelegate {
case .connecting, .connected:
stopConnectivityCheckTimer()
- case .stopped, .waitingConnectivity:
+ case .pendingStart, .stopped, .waitingConnectivity:
break
}
}
@@ -633,30 +651,13 @@ final class TunnelMonitor: PingerDelegate {
return newStats
}
- private func isNetworkPathReachable(_ networkPath: Network.NWPath) -> Bool {
+ private func isTunnelInterfaceUp(_ networkPath: Network.NWPath) -> Bool {
guard let tunName = adapter.interfaceName else { return false }
- // Check if utun is up.
let utunUp = networkPath.availableInterfaces.contains { interface in
return interface.name == tunName
}
- guard utunUp else {
- return false
- }
-
- // Return false if utun is the only available interface.
- if networkPath.availableInterfaces.count == 1 {
- return false
- }
-
- switch networkPath.status {
- case .requiresConnection, .satisfied:
- return true
- case .unsatisfied:
- return false
- @unknown default:
- return false
- }
+ return utunUp
}
}