diff --git a/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift b/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift index d06f632..fd56588 100644 --- a/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift +++ b/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift @@ -23,21 +23,6 @@ class ErrorPresenter { // TunnelActivationError case TunnelActivationError.tunnelActivationFailed: return ("Activation failure", "The tunnel could not be activated due to an internal error") - case TunnelActivationError.attemptingActivationWhenAnotherTunnelIsBusy(let otherTunnelStatus): - let statusString: String = { - switch (otherTunnelStatus) { - case .active: fallthrough - case .reasserting: fallthrough - case .restarting: - return "active" - case .activating: fallthrough - case .deactivating: - return "being deactivated" - case .inactive: - fatalError() - } - }() - return ("Activation failure", "Another tunnel is currently \(statusString)") default: os_log("ErrorPresenter: Error not presented: %{public}@", log: OSLog.default, type: .error, "\(error)") diff --git a/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift b/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift index 5209b3a..92d5c64 100644 --- a/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/TunnelDetailTableViewController.swift @@ -259,6 +259,8 @@ class TunnelDetailTableViewStatusCell: UITableViewCell { text = "Reactivating" case .restarting: text = "Restarting" + case .waiting: + text = "Waiting" } textLabel?.text = text DispatchQueue.main.async { [weak statusSwitch] in diff --git a/WireGuard/WireGuard/VPN/TunnelsManager.swift b/WireGuard/WireGuard/VPN/TunnelsManager.swift index d07f439..8827ea3 100644 --- a/WireGuard/WireGuard/VPN/TunnelsManager.swift +++ b/WireGuard/WireGuard/VPN/TunnelsManager.swift @@ -14,7 +14,6 @@ protocol TunnelsManagerDelegate: class { enum TunnelActivationError: Error { case tunnelActivationFailed - case attemptingActivationWhenAnotherTunnelIsBusy(otherTunnelStatus: TunnelStatus) case attemptingActivationWhenTunnelIsNotInactive case attemptingDeactivationWhenTunnelIsInactive } @@ -191,13 +190,15 @@ class TunnelsManager { completionHandler(TunnelActivationError.attemptingActivationWhenTunnelIsNotInactive) return } - for t in tunnels { - if t.status != .inactive { - completionHandler(TunnelActivationError.attemptingActivationWhenAnotherTunnelIsBusy(otherTunnelStatus: t.status)) - return + if let tunnelInOperation = tunnels.first(where: { $0.status != .inactive }) { + tunnel.status = .waiting + tunnelInOperation.onDeactivationComplete = { + tunnel.startActivation(completionHandler: completionHandler) } + startDeactivation(of: tunnelInOperation) + } else { + tunnel.startActivation(completionHandler: completionHandler) } - tunnel.startActivation(completionHandler: completionHandler) } func startDeactivation(of tunnel: TunnelContainer) { @@ -218,6 +219,8 @@ class TunnelContainer: NSObject { @objc dynamic var name: String @objc dynamic var status: TunnelStatus + var onDeactivationComplete: (() -> Void)? + fileprivate let tunnelProvider: NETunnelProviderManager private var statusObservationToken: AnyObject? @@ -245,10 +248,11 @@ class TunnelContainer: NSObject { } fileprivate func startActivation(completionHandler: @escaping (Error?) -> Void) { - assert(status == .inactive || status == .restarting) + assert(status == .inactive || status == .restarting || status == .waiting) guard let tunnelConfiguration = tunnelConfiguration() else { fatalError() } + onDeactivationComplete = nil startActivation(tunnelConfiguration: tunnelConfiguration, completionHandler: completionHandler) } @@ -356,6 +360,8 @@ class TunnelContainer: NSObject { s.status = TunnelStatus(from: connection.status) if (s.status == .inactive) { s.statusObservationToken = nil + s.onDeactivationComplete?() + s.onDeactivationComplete = nil } } } @@ -369,6 +375,7 @@ class TunnelContainer: NSObject { case reasserting // Not a possible state at present case restarting // Restarting tunnel (done after saving modifications to an active tunnel) + case waiting // Waiting for another tunnel to be brought down init(from vpnStatus: NEVPNStatus) { switch (vpnStatus) {