Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a 2 second delay before shutting down the tunnel when encountering an error #1078

Merged
merged 9 commits into from
Nov 22, 2024
13 changes: 13 additions & 0 deletions Sources/Common/EventMapping.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,20 @@ open class EventMapping<Event> {
eventMapper = mapping
}

@available(*, renamed: "fire(_:error:parameters:)")
samsymons marked this conversation as resolved.
Show resolved Hide resolved
public func fire(_ event: Event, error: Error? = nil, parameters: [String: String]? = nil, onComplete: @escaping (Error?) -> Void = {_ in }) {
eventMapper(event, error, parameters, onComplete)
}

public func asyncFire(_ event: Event, error: Error? = nil, parameters: [String: String]? = nil) async throws {
samsymons marked this conversation as resolved.
Show resolved Hide resolved
return try await withCheckedThrowingContinuation { continuation in
fire(event, error: error, parameters: parameters) { error in
if let error = error {
continuation.resume(throwing: error)
return
}
continuation.resume(returning: ())
}
}
}
samsymons marked this conversation as resolved.
Show resolved Hide resolved
}
14 changes: 7 additions & 7 deletions Sources/NetworkProtection/PacketTunnelProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -691,20 +691,20 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
// expired. In either case it should be enough to record the manual failures
// for these prerequisited to avoid flooding our metrics.
providerEvents.fire(.tunnelStartOnDemandWithoutAccessToken)
try await Task.sleep(interval: .seconds(15))
try? await Task.sleep(interval: .seconds(15))
} else {
// If the VPN was started manually without the basic prerequisites we always
// want to know as this should not be possible.
providerEvents.fire(.tunnelStartAttempt(.begin))
providerEvents.fire(.tunnelStartAttempt(.failure(error)))
try? await providerEvents.asyncFire(.tunnelStartAttempt(.begin))
try? await providerEvents.asyncFire(.tunnelStartAttempt(.failure(error)))
}

Logger.networkProtection.log("🔴 Stopping VPN due to no auth token")
await attemptShutdownDueToRevokedAccess()

// Check that the error is valid and able to be re-thrown to the OS before shutting the tunnel down
if let wrappedError = wrapped(error: error) {
providerEvents.fire(.malformedErrorDetected(error))
try? await providerEvents.asyncFire(.malformedErrorDetected(error))
throw wrappedError
} else {
throw error
Expand All @@ -725,7 +725,7 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
// We add a delay when the VPN is started by
// on-demand and there's an error, to avoid frenetic ON/OFF
// cycling.
try await Task.sleep(interval: .seconds(15))
try? await Task.sleep(interval: .seconds(15))
}

let errorDescription = (error as? LocalizedError)?.localizedDescription ?? String(describing: error)
Expand All @@ -734,11 +734,11 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
self.connectionStatus = .disconnected
self.knownFailureStore.lastKnownFailure = KnownFailure(error)

providerEvents.fire(.tunnelStartAttempt(.failure(error)))
try? await providerEvents.asyncFire(.tunnelStartAttempt(.failure(error)))

// Check that the error is valid and able to be re-thrown to the OS before shutting the tunnel down
if let wrappedError = wrapped(error: error) {
providerEvents.fire(.malformedErrorDetected(error))
try? await providerEvents.asyncFire(.malformedErrorDetected(error))
throw wrappedError
} else {
throw error
Expand Down
Loading