From 9817e5a5caf8616c64cc796b5c3290e7e2d2b0bc Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Thu, 30 Apr 2026 17:33:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8D=E5=B0=9D=E8=AF=95=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=EF=BC=8C=E5=A4=B1=E8=B4=A5=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tun/PacketTunnelProvider.swift | 20 ++++ Tun/Punchnet/Actors/SDLContextActor.swift | 111 +++++------------- .../SDLSuperRegistrationStateMachine.swift | 76 ------------ Tun/Punchnet/NWPath/SDLPathMonitor.swift | 7 ++ 4 files changed, 54 insertions(+), 160 deletions(-) delete mode 100644 Tun/Punchnet/Actors/SDLSuperRegistrationStateMachine.swift diff --git a/Tun/PacketTunnelProvider.swift b/Tun/PacketTunnelProvider.swift index 0a793b6..3693ea3 100644 --- a/Tun/PacketTunnelProvider.swift +++ b/Tun/PacketTunnelProvider.swift @@ -15,6 +15,8 @@ enum TunnelError: Error { class PacketTunnelProvider: NEPacketTunnelProvider { private var runtimeEnv: SDLRuntimeEnvironment? + + override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { // 如果当前在运行状态,不允许重复请求 guard self.runtimeEnv == nil else { @@ -27,6 +29,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider { return } + + self.runtimeEnv = SDLRuntimeEnvironment(options: options) Task { do { @@ -74,10 +78,26 @@ class PacketTunnelProvider: NEPacketTunnelProvider { } override func wake() { + // 启动monitor + let monitor = SDLPathMonitor() + // 启动监视器,允许重入 + monitor.start() + SDLLogger.log("[SDLContext] monitor started") + // Add code here to wake up. Task { + + defer { + monitor.stop() + } + + // 等待网络可达 + _ = await monitor.statusStream().first {$0 == .satisfied} + SDLLogger.log("[SDLContext] network is satisfied") + // 重新启动 try await self.runtimeEnv?.start(provider: self) } + } private func handleAppRequest(message: AppRequest) async throws -> Data? { diff --git a/Tun/Punchnet/Actors/SDLContextActor.swift b/Tun/Punchnet/Actors/SDLContextActor.swift index 0662f92..df74924 100644 --- a/Tun/Punchnet/Actors/SDLContextActor.swift +++ b/Tun/Punchnet/Actors/SDLContextActor.swift @@ -84,10 +84,6 @@ actor SDLContextActor { private let sessionManager = SessionManager() nonisolated private let arpServer: ArpServer - // 网络状态变化的健康 - private var monitor: SDLPathMonitor? - private var monitorWorker: Task? - // 内部socket通讯 // 改为基于 App Group + Darwin Notification 的通知 @@ -113,8 +109,6 @@ actor SDLContextActor { // stunRequest任务 private var stunRequestTask: Task? - private let superRegistrationStateMachine = SDLSuperRegistrationStateMachine() - public init(provider: NEPacketTunnelProvider, config: SDLConfiguration, rsaCipher: RSACipher) { self.provider = provider self.config = config @@ -144,7 +138,6 @@ actor SDLContextActor { if resetNotifier { self.prepareTunnelNotifier() } - self.startMonitor() // 启动arp的定时清理任务 await self.puncherActor.start() @@ -268,7 +261,24 @@ actor SDLContextActor { case .welcome(let welcome): SDLLogger.log("[SDLContext] quic welcome: \(welcome)") // 注册 - self.startRegisterLoop() + await self.doRegisterSuper() + + // 任务取消机制 + self.registerTask = Task { + do { + try await Task.sleep(for: .seconds(5)) + try Task.checkCancellation() + + // 关闭掉当前Tunnel + self.publishTunnelEvent(message: "校验失败") + // 报告错误并退出 + let error = NSError(domain: "com.jihe.punchnet.tun", code: -3) + self.provider.cancelTunnelWithError(error) + } catch { + return + } + } + // 启动stun任务 await self.startStunRequestTask(welcome: welcome) @@ -276,8 +286,14 @@ actor SDLContextActor { //SDLLogger.shared.log("[SDLContext] quic pong") () case .registerSuperAck(let registerSuperAck): + self.registerTask?.cancel() + self.registerTask = nil + await self.handleRegisterSuperAck(registerSuperAck: registerSuperAck) case .registerSuperNak(let registerSuperNak): + self.registerTask?.cancel() + self.registerTask = nil + self.handleRegisterSuperNak(nakPacket: registerSuperNak) case .peerInfo(let peerInfo): //SDLLogger.shared.log("[SDLContext] peer message: \(peerInfo)") @@ -301,35 +317,6 @@ actor SDLContextActor { SDLLogger.log("[SDLContext] tunnelAppNotifier ready") } - private func startMonitor() { - self.monitorWorker?.cancel() - self.monitorWorker = nil - - // 启动monitor - let monitor = SDLPathMonitor() - monitor.start() - SDLLogger.log("[SDLContext] monitor started") - self.monitor = monitor - - self.monitorWorker = Task { - for await status in monitor.statusStream() { - switch status { - case .satisfied: - SDLLogger.log("[Path] stable satisfied", for: .debug) - // await contextActor.networkPathDidBecomeSatisfied(snapshot) - case .unsatisfied: - SDLLogger.log("[Path] stable unsatisfied", for: .debug) - // await contextActor.networkPathDidBecomeUnsatisfied(snapshot) - case .requiresConnection: - SDLLogger.log("[Path] stable requiresConnection", for: .debug) - - @unknown default: - SDLLogger.log("[Path] stable unknown", for: .debug) - } - } - } - } - private func startDnsClient() async { self.dnsWorker?.cancel() self.dnsWorker = nil @@ -430,7 +417,6 @@ actor SDLContextActor { } private func stopRuntime() async { - self.superRegistrationStateMachine.reset() await self.supervisor.stop() await self.puncherActor.stop() @@ -463,12 +449,7 @@ actor SDLContextActor { self.dnsLocalWorker?.cancel() self.dnsLocalWorker = nil self.dnsLocalClient = nil - - self.monitor?.stop() - self.monitorWorker?.cancel() - self.monitorWorker = nil - self.monitor = nil - + self.readTask?.cancel() self.readTask = nil @@ -706,43 +687,9 @@ extension SDLContextActor { return .init(networkAddress: self.config.networkAddress) } - // 开启注册任务 - private func startRegisterLoop() { - guard self.registerTask == nil, - self.superRegistrationStateMachine.beginLoop() else { - return - } - - self.registerTask = Task { - defer { - self.registerTask = nil - } - - while !Task.isCancelled { - switch self.superRegistrationStateMachine.makeLoopAction() { - case .sendRegister: - await self.doRegisterSuper() - case .stop: - return - } - try? await Task.sleep(for: .seconds(5)) - switch self.superRegistrationStateMachine.makeWaitDecision() { - case .registered: - await self.whenRegistedSuper() - return - case .retry: - SDLLogger.log("[SDLContext] register super failed, retry") - case .stop: - return - } - } - } - } - private func handleRegisterSuperAck(registerSuperAck: SDLRegisterSuperAck) async { // 需要对数据通过rsa的私钥解码 guard let key = try? self.rsaCipher.decode(data: Data(registerSuperAck.key)) else { - self.superRegistrationStateMachine.handleFailure() SDLLogger.log("[SDLContext] registerSuperAck invalid key") let error = SDLError.invalidKey self.provider.cancelTunnelWithError(error) @@ -759,7 +706,6 @@ extension SDLContextActor { case "chacha20": self.dataCipher = CCChaCha20Cipher(regionId: regionId, keyData: key) default: - self.superRegistrationStateMachine.handleFailure() SDLLogger.log("[SDLContext] registerSuperAck invalid algorithm \(algorithm)") let error = SDLError.unsupportedAlgorithm(algorithm: algorithm) self.provider.cancelTunnelWithError(error) @@ -771,10 +717,10 @@ extension SDLContextActor { do { try await self.setNetworkSettings(config: self.config, dnsServer: DNSHelper.dnsServer) SDLLogger.log("[SDLContext] setNetworkSettings successed") - self.superRegistrationStateMachine.handleRegisterSuperAck() self.startReader() + // 开启权限的定时更新 + await self.whenRegistedSuper() } catch let err { - self.superRegistrationStateMachine.handleFailure() SDLLogger.log("[SDLContext] setTunnelNetworkSettings get error: \(err)") self.provider.cancelTunnelWithError(err) } @@ -788,18 +734,15 @@ extension SDLContextActor { switch errorCode { case .invalidToken, .nodeDisabled: - self.superRegistrationStateMachine.handleFailure() self.publishTunnelEvent(code: Int(errorCode.rawValue), message: errorMessage) // 报告错误并退出 let error = NSError(domain: "com.jihe.punchnet.tun", code: -1) self.provider.cancelTunnelWithError(error) case .noIpAddress, .networkFault, .internalFault: - self.superRegistrationStateMachine.handleRetryableNak() self.publishTunnelEvent(code: Int(errorCode.rawValue), message: errorMessage) } SDLLogger.log("[SDLContext] Get a SuperNak message exit") - } private func handleEvent(event: SDLEvent) async { diff --git a/Tun/Punchnet/Actors/SDLSuperRegistrationStateMachine.swift b/Tun/Punchnet/Actors/SDLSuperRegistrationStateMachine.swift deleted file mode 100644 index aeaf5f6..0000000 --- a/Tun/Punchnet/Actors/SDLSuperRegistrationStateMachine.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// SDLSuperRegistrationStateMachine.swift -// Tun -// -// Created by 安礼成 on 2026/4/15. -// - -import Foundation - -final class SDLSuperRegistrationStateMachine { - enum State: Equatable { - case idle - case registering - case registered - case failed - } - - enum LoopAction { - case sendRegister - case stop - } - - enum WaitDecision { - case retry - case registered - case stop - } - - private(set) var state: State = .idle - - func beginLoop() -> Bool { - guard self.state != .registering else { - return false - } - - self.state = .registering - return true - } - - func makeLoopAction() -> LoopAction { - switch self.state { - case .registering: - return .sendRegister - case .idle, .registered, .failed: - return .stop - } - } - - func makeWaitDecision() -> WaitDecision { - switch self.state { - case .registering: - return .retry - case .registered: - return .registered - case .idle, .failed: - return .stop - } - } - - func handleRegisterSuperAck() { - self.state = .registered - } - - func handleRetryableNak() { - self.state = .registering - } - - func handleFailure() { - self.state = .failed - } - - func reset() { - self.state = .idle - } - -} diff --git a/Tun/Punchnet/NWPath/SDLPathMonitor.swift b/Tun/Punchnet/NWPath/SDLPathMonitor.swift index 62c72be..e01f08e 100644 --- a/Tun/Punchnet/NWPath/SDLPathMonitor.swift +++ b/Tun/Punchnet/NWPath/SDLPathMonitor.swift @@ -12,7 +12,14 @@ final class SDLPathMonitor { private let queue = DispatchQueue(label: "com.sdlan.path-monitor") private let debouncer = SDLPathDebounceActor(delay: .seconds(2)) + private var isStarted: Bool = false + func start() { + guard !isStarted else { + return + } + + self.isStarted = true monitor.pathUpdateHandler = { path in let snapshot = SDLPathSnapshot(path)