Skip to content

Commit

Permalink
Throttle network path updates in packet tunnel
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Petersson committed Nov 28, 2023
1 parent f976843 commit 7969c77
Showing 1 changed file with 17 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
//

import Foundation
import Combine
import NetworkExtension
import PacketTunnelCore

final class PacketTunnelPathObserver: DefaultPathObserverProtocol {
private weak var packetTunnelProvider: NEPacketTunnelProvider?
private let stateLock = NSLock()
private var observationToken: NSKeyValueObservation?
private var cancellable: AnyCancellable?
private let eventQueue: DispatchQueue

init(packetTunnelProvider: NEPacketTunnelProvider) {
init(packetTunnelProvider: NEPacketTunnelProvider, eventQueue: DispatchQueue) {
self.packetTunnelProvider = packetTunnelProvider
self.eventQueue = eventQueue
}

var defaultPath: NetworkPath? {
Expand All @@ -25,22 +27,26 @@ final class PacketTunnelPathObserver: DefaultPathObserverProtocol {

func start(_ body: @escaping (NetworkPath) -> Void) {
stateLock.withLock {
observationToken?.invalidate()
cancellable?.cancel()

// Normally packet tunnel provider should exist throughout the network extension lifetime.
observationToken = packetTunnelProvider?.observe(\.defaultPath, options: [.new]) { _, change in
let nwPath = change.newValue.flatMap { $0 }
if let nwPath {
body(nwPath)
cancellable = packetTunnelProvider?.publisher(for: \.defaultPath)
.removeDuplicates(by: { oldPath, newPath in
oldPath?.status == newPath?.status
})
.throttle(for: .seconds(2), scheduler: eventQueue, latest: true)
.sink { change in
if let change {
body(change)
}
}
}
}
}

func stop() {
stateLock.withLock {
observationToken?.invalidate()
observationToken = nil
cancellable?.cancel()
cancellable = nil
}
}
}
Expand Down

0 comments on commit 7969c77

Please sign in to comment.