From 3217614f02037416b0da72ef4114c420db3943c2 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Thu, 28 May 2026 17:15:04 +0800 Subject: [PATCH] fix --- Tun/Context/SDLContextActor.swift | 57 +++++++++++++++++++++++++------ Tun/DNS/DNSCloudClient.swift | 11 ++++-- Tun/DNS/DNSLocalClient.swift | 19 +++++++++-- Tun/Policy/FlowSessionTable.swift | 1 + 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/Tun/Context/SDLContextActor.swift b/Tun/Context/SDLContextActor.swift index f3b7c5f..9f9ec1f 100644 --- a/Tun/Context/SDLContextActor.swift +++ b/Tun/Context/SDLContextActor.swift @@ -62,6 +62,8 @@ actor SDLContextActor { // 处理权限控制 private let policyService: PolicyService private var rootTask: Task? + private var rootTaskID: UUID? + private var terminalError: Error? private let readySignal = AsyncOneShot() public init(provider: NEPacketTunnelProvider, config: SDLConfiguration, rsaCipher: RSACipher) { @@ -140,21 +142,31 @@ actor SDLContextActor { return } + let rootTaskID = UUID() let rootTask = Task { + var result: Result = .success(()) + do { try await self.runRootBody() - await self.cleanupRoot() } catch is CancellationError { - SDLLogger.fatal("[SDLContext] root task cancelled", category: .context) - await self.cleanupRoot() - throw CancellationError() + if let terminalError = await self.consumeTerminalError() { + SDLLogger.fatal("[SDLContext] root task stopped by terminal error: \(terminalError)", category: .context) + result = .failure(terminalError) + } else { + SDLLogger.fatal("[SDLContext] root task cancelled", category: .context) + result = .failure(CancellationError()) + } } catch { SDLLogger.fatal("[SDLContext] root task failed: \(error)", category: .context) await self.readySignal.fail(error) - await self.cleanupRoot() - throw error + result = .failure(error) } + + await self.cleanupRoot() + await self.finishRootTask(id: rootTaskID) + try result.get() } + self.rootTaskID = rootTaskID self.rootTask = rootTask do { @@ -164,6 +176,8 @@ actor SDLContextActor { rootTask.cancel() _ = try? await rootTask.value self.rootTask = nil + self.rootTaskID = nil + self.terminalError = nil throw error } } @@ -172,13 +186,14 @@ actor SDLContextActor { public func stop() async { SDLLogger.fatal("[SDLContext] stop requested", category: .context) let rootTask = self.rootTask - self.rootTask = nil rootTask?.cancel() await self.readySignal.fail(CancellationError()) _ = try? await rootTask?.value - await self.cleanupRoot() + self.rootTask = nil + self.rootTaskID = nil + self.terminalError = nil } private func runRootBody() async throws { @@ -370,6 +385,28 @@ actor SDLContextActor { await self.stopCurrentIPv6AssistClient() } + private func requestRootShutdown(error: Error) async { + self.terminalError = error + await self.readySignal.fail(error) + self.rootTask?.cancel() + } + + private func consumeTerminalError() -> Error? { + let error = self.terminalError + self.terminalError = nil + return error + } + + private func finishRootTask(id: UUID) { + guard self.rootTaskID == id else { + return + } + + self.rootTask = nil + self.rootTaskID = nil + self.terminalError = nil + } + deinit { SDLLogger.log("[SDLContext] deinit", category: .context) } @@ -441,7 +478,7 @@ extension SDLContextActor { SDLLogger.fatal("[SDLContext] Super shutdown received: \(message)", category: .context) self.publishTunnelEvent(message: message) let error = NSError(domain: "com.jihe.punchnet.tun", code: -2) - self.provider.cancelTunnelWithError(error) + await self.failTunnel(error) case .applyPolicyResponse(let policyResponse): await self.policyService.applyPolicyResponse(policyResponse) case .applyExposedServiceResponse(let response): @@ -469,8 +506,8 @@ extension SDLContextActor { private func failTunnel(_ error: Error) async { SDLLogger.fatal("[SDLContext] failTunnel: \(error)", category: .context) - await self.readySignal.fail(error) self.provider.cancelTunnelWithError(error) + await self.requestRootShutdown(error: error) } private func requestExposedService() async { diff --git a/Tun/DNS/DNSCloudClient.swift b/Tun/DNS/DNSCloudClient.swift index fda96f6..19ba3f5 100644 --- a/Tun/DNS/DNSCloudClient.swift +++ b/Tun/DNS/DNSCloudClient.swift @@ -82,8 +82,15 @@ actor DNSCloudClient { } /// 发送 DNS 查询包(由 TUN 拦截到的原始 IP 包数据) - func forward(ipPacketData: Data) { - guard connection.state == .ready else { + func forward(ipPacketData: Data) async { + do { + try await self.readySignal.wait(timeout: .seconds(3)) + } catch { + SDLLogger.log("[DNSCloudClient] drop query before ready: \(error)", category: .dns) + return + } + + guard !self.isStopped, connection.state == .ready else { return } diff --git a/Tun/DNS/DNSLocalClient.swift b/Tun/DNS/DNSLocalClient.swift index f037587..c6260f0 100644 --- a/Tun/DNS/DNSLocalClient.swift +++ b/Tun/DNS/DNSLocalClient.swift @@ -104,8 +104,19 @@ actor DNSLocalClient { } } - func query(tracker: DNSTracker, dnsPayload: Data) { - guard connection.state == .ready, dnsPayload.count >= 2 else { + func query(tracker: DNSTracker, dnsPayload: Data) async { + guard dnsPayload.count >= 2 else { + return + } + + do { + try await self.readySignal.wait(timeout: .seconds(3)) + } catch { + SDLLogger.log("[DNSLocalClient] drop query before ready: \(error)", category: .dns) + return + } + + guard !self.isStopped, connection.state == .ready else { return } @@ -146,6 +157,10 @@ actor DNSLocalClient { private func handleConnectionStateUpdate(_ state: NWConnection.State) async { switch state { case .ready: + guard !self.isStopped else { + return + } + await self.readySignal.succeed(()) case .failed(let error): await self.readySignal.fail(DNSLocalError.failed(error)) diff --git a/Tun/Policy/FlowSessionTable.swift b/Tun/Policy/FlowSessionTable.swift index 5e1c0be..d8dd8da 100644 --- a/Tun/Policy/FlowSessionTable.swift +++ b/Tun/Policy/FlowSessionTable.swift @@ -44,6 +44,7 @@ struct FlowSession: Hashable { // MARK: - 会话表 final class FlowSessionTable: @unchecked Sendable { + private enum SessionState: Hashable { case tcpPending case tcpEstablished