TunnelsManager: Handle waiting on a stale tunnel
If we have a stale tunnel on which we don't get status updates we rely
on a timer to update the status (see commit 34a7e5b
). Previously, if
the user tries to activate another tunnel, that resulted in both tunnels
waiting indefinitely. This commit fixes that.
Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
parent
fab7af6f38
commit
4e516d6769
|
@ -24,6 +24,7 @@ class TunnelsManager {
|
||||||
weak var tunnelsListDelegate: TunnelsManagerListDelegate?
|
weak var tunnelsListDelegate: TunnelsManagerListDelegate?
|
||||||
weak var activationDelegate: TunnelsManagerActivationDelegate?
|
weak var activationDelegate: TunnelsManagerActivationDelegate?
|
||||||
private var statusObservationToken: AnyObject?
|
private var statusObservationToken: AnyObject?
|
||||||
|
private var waiteeObservationToken: AnyObject?
|
||||||
|
|
||||||
init(tunnelProviders: [NETunnelProviderManager]) {
|
init(tunnelProviders: [NETunnelProviderManager]) {
|
||||||
tunnels = tunnelProviders.map { TunnelContainer(tunnel: $0) }.sorted { $0.name < $1.name }
|
tunnels = tunnelProviders.map { TunnelContainer(tunnel: $0) }.sorted { $0.name < $1.name }
|
||||||
|
@ -205,6 +206,7 @@ class TunnelsManager {
|
||||||
if let tunnelInOperation = tunnels.first(where: { $0.status != .inactive }) {
|
if let tunnelInOperation = tunnels.first(where: { $0.status != .inactive }) {
|
||||||
wg_log(.info, message: "Tunnel '\(tunnel.name)' waiting for deactivation of '\(tunnelInOperation.name)'")
|
wg_log(.info, message: "Tunnel '\(tunnel.name)' waiting for deactivation of '\(tunnelInOperation.name)'")
|
||||||
tunnel.status = .waiting
|
tunnel.status = .waiting
|
||||||
|
activateWaitingTunnelOnDeactivation(of: tunnelInOperation)
|
||||||
if tunnelInOperation.status != .deactivating {
|
if tunnelInOperation.status != .deactivating {
|
||||||
startDeactivation(of: tunnelInOperation)
|
startDeactivation(of: tunnelInOperation)
|
||||||
}
|
}
|
||||||
|
@ -232,6 +234,18 @@ class TunnelsManager {
|
||||||
tunnels.forEach { $0.refreshStatus() }
|
tunnels.forEach { $0.refreshStatus() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func activateWaitingTunnelOnDeactivation(of tunnel: TunnelContainer) {
|
||||||
|
waiteeObservationToken = tunnel.observe(\.status) { [weak self] tunnel, _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if tunnel.status == .inactive {
|
||||||
|
if let waitingTunnel = self.tunnels.first(where: { $0.status == .waiting }) {
|
||||||
|
waitingTunnel.startActivation(activationDelegate: self.activationDelegate)
|
||||||
|
}
|
||||||
|
self.waiteeObservationToken = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func startObservingTunnelStatuses() {
|
private func startObservingTunnelStatuses() {
|
||||||
guard statusObservationToken == nil else { return }
|
guard statusObservationToken == nil else { return }
|
||||||
|
|
||||||
|
@ -268,13 +282,6 @@ class TunnelsManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
tunnel.refreshStatus()
|
tunnel.refreshStatus()
|
||||||
|
|
||||||
// In case some other tunnel is waiting for this tunnel to get deactivated
|
|
||||||
if session.status == .disconnected || session.status == .invalid {
|
|
||||||
if let waitingTunnel = self.tunnels.first(where: { $0.status == .waiting }) {
|
|
||||||
waitingTunnel.startActivation(activationDelegate: self.activationDelegate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,18 +315,21 @@ class TunnelContainer: NSObject {
|
||||||
var isAttemptingActivation = false {
|
var isAttemptingActivation = false {
|
||||||
didSet {
|
didSet {
|
||||||
if isAttemptingActivation {
|
if isAttemptingActivation {
|
||||||
|
self.activationTimer?.invalidate()
|
||||||
let activationTimer = Timer(timeInterval: 5 /* seconds */, repeats: true) { [weak self] _ in
|
let activationTimer = Timer(timeInterval: 5 /* seconds */, repeats: true) { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.refreshStatus()
|
wg_log(.debug, message: "Status update notification timeout for tunnel '\(self.name)'. Tunnel status is now '\(self.tunnelProvider.connection.status)'.")
|
||||||
if self.status == .inactive || self.status == .active {
|
switch self.tunnelProvider.connection.status {
|
||||||
self.isAttemptingActivation = false // This also invalidates the timer
|
case .connected, .disconnected, .invalid:
|
||||||
|
self.activationTimer?.invalidate()
|
||||||
|
self.activationTimer = nil
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
self.refreshStatus()
|
||||||
}
|
}
|
||||||
self.activationTimer = activationTimer
|
self.activationTimer = activationTimer
|
||||||
RunLoop.main.add(activationTimer, forMode: .default)
|
RunLoop.main.add(activationTimer, forMode: .default)
|
||||||
} else {
|
|
||||||
activationTimer?.invalidate()
|
|
||||||
activationTimer = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue