From 337fa37b056770cd2e31fc6807fee71f9cd26bb9 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Tue, 28 Apr 2026 10:39:17 +0800 Subject: [PATCH] fix sleep and wakeup --- Tun/PacketTunnelProvider.swift | 8 ++- Tun/Punchnet/Actors/ArpServer.swift | 1 + Tun/Punchnet/Actors/SDLContextActor.swift | 68 +++++++++++++++++++++-- Tun/Punchnet/SDLFlowSessionManager.swift | 17 ++++-- Tun/Punchnet/SessionManager.swift | 10 +++- 5 files changed, 92 insertions(+), 12 deletions(-) diff --git a/Tun/PacketTunnelProvider.swift b/Tun/PacketTunnelProvider.swift index dd25d8c..3e0b55f 100644 --- a/Tun/PacketTunnelProvider.swift +++ b/Tun/PacketTunnelProvider.swift @@ -83,11 +83,17 @@ class PacketTunnelProvider: NEPacketTunnelProvider { override func sleep(completionHandler: @escaping () -> Void) { // Add code here to get ready to sleep. - completionHandler() + Task { + await self.contextActor?.sleep() + completionHandler() + } } override func wake() { // Add code here to wake up. + Task { + await self.contextActor?.wake() + } } private func handleAppRequest(message: AppRequest) async throws -> Data? { diff --git a/Tun/Punchnet/Actors/ArpServer.swift b/Tun/Punchnet/Actors/ArpServer.swift index 34765d5..89bd077 100644 --- a/Tun/Punchnet/Actors/ArpServer.swift +++ b/Tun/Punchnet/Actors/ArpServer.swift @@ -67,6 +67,7 @@ actor ArpServer { func clear() { self.known_macs = [:] + self.coolingDown = [:] } func arpRequest(targetIp: UInt32, use quicClient: SDLQUICClient?) throws { diff --git a/Tun/Punchnet/Actors/SDLContextActor.swift b/Tun/Punchnet/Actors/SDLContextActor.swift index 13c2c02..1e04c5d 100644 --- a/Tun/Punchnet/Actors/SDLContextActor.swift +++ b/Tun/Punchnet/Actors/SDLContextActor.swift @@ -22,6 +22,14 @@ actor SDLContextActor { case stopped } + private enum RuntimeState { + case idle + case running + case sleeping + case waking + case stopped + } + private enum UDPHoleKind: Equatable { case v4 case v6 @@ -35,8 +43,9 @@ actor SDLContextActor { } } } - + private var readyState: ReadyState = .idle + private var runtimeState: RuntimeState = .idle private var readyWaiters: [CheckedContinuation] = [] var config: SDLConfiguration @@ -139,7 +148,14 @@ actor SDLContextActor { } self.readyState = .starting - self.prepareTunnelNotifier() + self.runtimeState = .running + await self.startRuntime(resetNotifier: true) + } + + private func startRuntime(resetNotifier: Bool) async { + if resetNotifier { + self.prepareTunnelNotifier() + } self.startMonitor() // 启动arp的定时清理任务 @@ -171,6 +187,38 @@ actor SDLContextActor { // } } + public func sleep() async { + guard self.runtimeState != .stopped else { + return + } + + SDLLogger.log("[SDLContext] sleep") + self.runtimeState = .sleeping + await self.stopRuntime(clearCaches: true) + } + + public func wake() async { + switch self.runtimeState { + case .stopped, .waking: + return + case .running: + await self.stopRuntime(clearCaches: true) + guard case .running = self.runtimeState else { + return + } + case .idle, .sleeping: + break + } + + SDLLogger.log("[SDLContext] wake") + self.runtimeState = .waking + await self.startRuntime(resetNotifier: false) + guard case .waking = self.runtimeState else { + return + } + self.runtimeState = .running + } + public func waitForReady() async throws { switch self.readyState { case .ready: @@ -201,7 +249,7 @@ actor SDLContextActor { try await self.waitForReady() } - + // 取消出口节点的时候,ip地址为: 0.0.0.0 public func updateExitNode(exitNodeIp: String) async throws { if let ip = SDLUtil.ipv4StrToInt32(exitNodeIp), ip > 0 { @@ -391,10 +439,21 @@ actor SDLContextActor { public func stop() async { self.resumeReadyWaiters(.failure(CancellationError())) self.readyState = .stopped + self.runtimeState = .stopped + await self.stopRuntime(clearCaches: true) + } + + private func stopRuntime(clearCaches: Bool) async { self.superRegistrationStateMachine.reset() - + await self.supervisor.stop() await self.puncherActor.stop() + await self.arpServer.clear() + await self.sessionManager.clear() + + if clearCaches { + self.flowSessionManager.clear() + } self.udpHoleWorkers?.forEach { $0.cancel() } self.udpHoleWorkers = nil @@ -442,6 +501,7 @@ actor SDLContextActor { self.sessionToken = nil self.dataCipher = nil + self.natType = .blocked await self.ipv6AssistClient?.stop() self.ipv6AssistClient = nil diff --git a/Tun/Punchnet/SDLFlowSessionManager.swift b/Tun/Punchnet/SDLFlowSessionManager.swift index 9fbca75..2eec422 100644 --- a/Tun/Punchnet/SDLFlowSessionManager.swift +++ b/Tun/Punchnet/SDLFlowSessionManager.swift @@ -29,7 +29,7 @@ struct FlowSession: Hashable { lhs.dstPort == rhs.dstPort && lhs.proto == rhs.proto } - + func reverse() -> FlowSession { return FlowSession( srcIP: dstIP, @@ -39,7 +39,7 @@ struct FlowSession: Hashable { proto: proto ) } - + } // MARK: - 会话管理器 @@ -68,14 +68,14 @@ final class SDLFlowSessionManager { defer { lock.unlock() } - + if let expireTs = sessions[key] { if expireTs >= Date().timeIntervalSince1970 { return true } self.sessions.removeValue(forKey: key) } - + return false } @@ -89,6 +89,15 @@ final class SDLFlowSessionManager { sessions.removeValue(forKey: key) } + func clear() { + lock.lock() + defer { + lock.unlock() + } + + sessions.removeAll() + } + // 清理过期会话 func cleanupExpiredSessions() { lock.lock() diff --git a/Tun/Punchnet/SessionManager.swift b/Tun/Punchnet/SessionManager.swift index d325cab..b25e08b 100644 --- a/Tun/Punchnet/SessionManager.swift +++ b/Tun/Punchnet/SessionManager.swift @@ -13,7 +13,7 @@ struct Session { case v4 case v6 } - + // 在内部的通讯的ip地址, 整数格式 let dstMac: Data // 对端的主机在nat上映射的端口信息 @@ -30,7 +30,7 @@ struct Session { self.addressType = addressType self.lastTimestamp = Int32(Date().timeIntervalSince1970) } - + mutating func updateLastTimestamp(_ lastTimestamp: Int32) { self.lastTimestamp = lastTimestamp } @@ -67,7 +67,7 @@ actor SessionManager { return session } - + func addSession(session: Session) { let timestamp = Int32(Date().timeIntervalSince1970) @@ -84,6 +84,10 @@ actor SessionManager { self.sessions.removeValue(forKey: dstMac) } + func clear() { + self.sessions.removeAll() + } + private func selectSession(in sessions: [Session.AddressType: Session]) -> Session? { return sessions.values.max(by: { $0.lastTimestamp < $1.lastTimestamp }) }