diff options
| -rw-r--r-- | ios/MullvadVPN/ConnectViewController.swift | 7 | ||||
| -rw-r--r-- | ios/MullvadVPN/TunnelManager.swift | 32 |
2 files changed, 34 insertions, 5 deletions
diff --git a/ios/MullvadVPN/ConnectViewController.swift b/ios/MullvadVPN/ConnectViewController.swift index bef9afe4ed..a388c5e23f 100644 --- a/ios/MullvadVPN/ConnectViewController.swift +++ b/ios/MullvadVPN/ConnectViewController.swift @@ -145,7 +145,12 @@ class ConnectViewController: UIViewController, RootContainment, TunnelControlVie startStopTunnelSubscriber = TunnelManager.shared.stopTunnel() .receive(on: DispatchQueue.main) .sink(receiveCompletion: { (completion) in - // no-op + if case .failure(let error) = completion { + os_log(.error, "Failed to stop the tunnel: %{public}s", + error.localizedDescription) + + self.presentError(error, preferredStyle: .alert) + } }) } diff --git a/ios/MullvadVPN/TunnelManager.swift b/ios/MullvadVPN/TunnelManager.swift index bc80d8b0c3..f90140491e 100644 --- a/ios/MullvadVPN/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager.swift @@ -19,6 +19,9 @@ enum TunnelManagerError: Error { /// A failure to start the tunnel case startTunnel(StartTunnelError) + /// A failure to stop the tunnel + case stopTunnel(Error) + /// A failure to load the account with the assumption that it was already set up earlier case loadTunnel(LoadTunnelError) @@ -57,6 +60,9 @@ extension TunnelManagerError: LocalizedError { case .startTunnel: return NSLocalizedString("Cannot start the tunnel", comment: "") + case .stopTunnel: + return NSLocalizedString("Cannot stop the tunnel", comment: "") + default: return nil } @@ -377,10 +383,22 @@ class TunnelManager { }.eraseToAnyPublisher() } - func stopTunnel() -> AnyPublisher<(), Never> { - MutuallyExclusive(exclusivityQueue: exclusivityQueue, executionQueue: executionQueue) { () -> Just<()> in - self.tunnelProvider?.connection.stopVPNTunnel() - return Just(()) + func stopTunnel() -> AnyPublisher<(), TunnelManagerError> { + MutuallyExclusive(exclusivityQueue: exclusivityQueue, executionQueue: executionQueue) { () -> AnyPublisher<(), TunnelManagerError> in + if let tunnelProvider = self.tunnelProvider { + // Disable on-demand when turning off the tunnel to prevent the tunnel from coming + // back up + tunnelProvider.isOnDemandEnabled = false + + return tunnelProvider.saveToPreferences() + .mapError { TunnelManagerError.stopTunnel($0) } + .map { _ -> () in + tunnelProvider.connection.stopVPNTunnel() + return () + }.eraseToAnyPublisher() + } else { + return Result.Publisher(()).eraseToAnyPublisher() + } }.eraseToAnyPublisher() } @@ -800,6 +818,12 @@ class TunnelManager { passwordReference: passwordReference ) + // Enable on-demand VPN, always connect the tunnel when on Wi-Fi or cellular + let alwaysOnRule = NEOnDemandRuleConnect() + alwaysOnRule.interfaceTypeMatch = .any + tunnelProvider.onDemandRules = [alwaysOnRule] + tunnelProvider.isOnDemandEnabled = true + return tunnelProvider.saveToPreferences() .mapError { SetupTunnelError.saveTunnel($0) } .flatMap { |
