VPN: When activating while another tunnel is active, deactivate the other tunnel

Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
Roopesh Chander 2018-11-10 15:50:56 +05:30
parent 8e7bfb15ed
commit e8d68396ca
3 changed files with 16 additions and 22 deletions

View File

@ -23,21 +23,6 @@ class ErrorPresenter {
// TunnelActivationError // TunnelActivationError
case TunnelActivationError.tunnelActivationFailed: case TunnelActivationError.tunnelActivationFailed:
return ("Activation failure", "The tunnel could not be activated due to an internal error") 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: default:
os_log("ErrorPresenter: Error not presented: %{public}@", log: OSLog.default, type: .error, "\(error)") os_log("ErrorPresenter: Error not presented: %{public}@", log: OSLog.default, type: .error, "\(error)")

View File

@ -259,6 +259,8 @@ class TunnelDetailTableViewStatusCell: UITableViewCell {
text = "Reactivating" text = "Reactivating"
case .restarting: case .restarting:
text = "Restarting" text = "Restarting"
case .waiting:
text = "Waiting"
} }
textLabel?.text = text textLabel?.text = text
DispatchQueue.main.async { [weak statusSwitch] in DispatchQueue.main.async { [weak statusSwitch] in

View File

@ -14,7 +14,6 @@ protocol TunnelsManagerDelegate: class {
enum TunnelActivationError: Error { enum TunnelActivationError: Error {
case tunnelActivationFailed case tunnelActivationFailed
case attemptingActivationWhenAnotherTunnelIsBusy(otherTunnelStatus: TunnelStatus)
case attemptingActivationWhenTunnelIsNotInactive case attemptingActivationWhenTunnelIsNotInactive
case attemptingDeactivationWhenTunnelIsInactive case attemptingDeactivationWhenTunnelIsInactive
} }
@ -191,13 +190,15 @@ class TunnelsManager {
completionHandler(TunnelActivationError.attemptingActivationWhenTunnelIsNotInactive) completionHandler(TunnelActivationError.attemptingActivationWhenTunnelIsNotInactive)
return return
} }
for t in tunnels { if let tunnelInOperation = tunnels.first(where: { $0.status != .inactive }) {
if t.status != .inactive { tunnel.status = .waiting
completionHandler(TunnelActivationError.attemptingActivationWhenAnotherTunnelIsBusy(otherTunnelStatus: t.status)) tunnelInOperation.onDeactivationComplete = {
return tunnel.startActivation(completionHandler: completionHandler)
} }
startDeactivation(of: tunnelInOperation)
} else {
tunnel.startActivation(completionHandler: completionHandler)
} }
tunnel.startActivation(completionHandler: completionHandler)
} }
func startDeactivation(of tunnel: TunnelContainer) { func startDeactivation(of tunnel: TunnelContainer) {
@ -218,6 +219,8 @@ class TunnelContainer: NSObject {
@objc dynamic var name: String @objc dynamic var name: String
@objc dynamic var status: TunnelStatus @objc dynamic var status: TunnelStatus
var onDeactivationComplete: (() -> Void)?
fileprivate let tunnelProvider: NETunnelProviderManager fileprivate let tunnelProvider: NETunnelProviderManager
private var statusObservationToken: AnyObject? private var statusObservationToken: AnyObject?
@ -245,10 +248,11 @@ class TunnelContainer: NSObject {
} }
fileprivate func startActivation(completionHandler: @escaping (Error?) -> Void) { 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() } guard let tunnelConfiguration = tunnelConfiguration() else { fatalError() }
onDeactivationComplete = nil
startActivation(tunnelConfiguration: tunnelConfiguration, startActivation(tunnelConfiguration: tunnelConfiguration,
completionHandler: completionHandler) completionHandler: completionHandler)
} }
@ -356,6 +360,8 @@ class TunnelContainer: NSObject {
s.status = TunnelStatus(from: connection.status) s.status = TunnelStatus(from: connection.status)
if (s.status == .inactive) { if (s.status == .inactive) {
s.statusObservationToken = nil s.statusObservationToken = nil
s.onDeactivationComplete?()
s.onDeactivationComplete = nil
} }
} }
} }
@ -369,6 +375,7 @@ class TunnelContainer: NSObject {
case reasserting // Not a possible state at present case reasserting // Not a possible state at present
case restarting // Restarting tunnel (done after saving modifications to an active tunnel) 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) { init(from vpnStatus: NEVPNStatus) {
switch (vpnStatus) { switch (vpnStatus) {