Skip to content

Commit

Permalink
Avoid deadlocking the Packet Tunnel after a reboot
Browse files Browse the repository at this point in the history
  • Loading branch information
buggmagnet committed Oct 29, 2024
1 parent fc5d608 commit 7f3d297
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 21 deletions.
2 changes: 1 addition & 1 deletion ios/MullvadREST/RetryStrategy/RetryStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ extension REST {
maxRetryCount: .max,
delay: .exponentialBackoff(
initial: .seconds(5),
multiplier: UInt64(1),
multiplier: UInt64(2),
maxDelay: .minutes(1)
),
applyJitter: true
Expand Down
3 changes: 3 additions & 0 deletions ios/MullvadSettings/MigrationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ public struct MigrationManager {
)
} catch .itemNotFound as KeychainError {
migrationCompleted(.nothing)
} catch let couldNotReadKeychainError as KeychainError
where couldNotReadKeychainError == .interactionNotAllowed {
migrationCompleted(.failure(couldNotReadKeychainError))
} catch {
resetStoreHandler(.failure(error))
}
Expand Down
48 changes: 28 additions & 20 deletions ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,28 +174,36 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
}

private func performSettingsMigration() {
migrationManager.migrateSettings(
store: SettingsManager.store,
migrationCompleted: { [unowned self] migrationResult in
switch migrationResult {
case .success:
providerLogger.debug("Successful migration from PacketTunnel")
case .nothing:
providerLogger.debug("Attempted migration from PacketTunnel, but found nothing to do")
case let .failure(error):
// `next` returns an Optional value, but this iterator is guaranteed to always have a next value
guard let delay = migrationFailureIterator.next() else { return }
providerLogger
.error(
"Failed migration from PacketTunnel: \(error), retrying in \(delay.timeInterval) seconds"
)
// Block the launch of the Packet Tunnel for as long as the settings migration fail.
// The process watchdog introduced by iOS 17 will kill this process after 60 seconds.
Thread.sleep(forTimeInterval: delay.timeInterval)
performSettingsMigration()
var hasNotMigrated = true
repeat {
migrationManager.migrateSettings(
store: SettingsManager.store,
migrationCompleted: { [unowned self] migrationResult in
switch migrationResult {
case .success:
providerLogger.debug("Successful migration from PacketTunnel")
hasNotMigrated = false
case .nothing:
hasNotMigrated = false
providerLogger.debug("Attempted migration from PacketTunnel, but found nothing to do")
case let .failure(error):
providerLogger
.error(
"Failed migration from PacketTunnel: \(error)"
)
}
}
)
if hasNotMigrated {
// `next` returns an Optional value, but this iterator is guaranteed to always have a next value
guard let delay = migrationFailureIterator.next() else { continue }

providerLogger.error("Retrying migration in \(delay.timeInterval) seconds")
// Block the launch of the Packet Tunnel for as long as the settings migration fail.
// The process watchdog introduced by iOS 17 will kill this process after 60 seconds.
Thread.sleep(forTimeInterval: delay.timeInterval)
}
)
} while hasNotMigrated
}

private func setUpTransportProvider(
Expand Down

0 comments on commit 7f3d297

Please sign in to comment.