diff --git a/Tun/PacketTunnelProvider.swift b/Tun/PacketTunnelProvider.swift index 0f81428..62ebb1d 100644 --- a/Tun/PacketTunnelProvider.swift +++ b/Tun/PacketTunnelProvider.swift @@ -29,23 +29,20 @@ class PacketTunnelProvider: NEPacketTunnelProvider { } let rsaCipher = try! CCRSACipher(keySize: 1024) - self.runtimeEnv = SDLRuntimeEnvironment(config: config, rsaCipher: rsaCipher) + self.runtimeEnv = SDLRuntimeEnvironment(config: config, rsaCipher: rsaCipher, provider: self) Task { - do { - try await self.runtimeEnv?.start(provider: self) - completionHandler(nil) - } catch let err { + await self.runtimeEnv?.submitCommand(command: .start(completion: { err in completionHandler(err) - } + })) } - } override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { // Add code here to start the process of stopping the tunnel. Task { - await self.runtimeEnv?.stop() - completionHandler() + await self.runtimeEnv?.submitCommand(command: .stop(completion: { + completionHandler() + })) } } @@ -70,37 +67,26 @@ class PacketTunnelProvider: NEPacketTunnelProvider { override func sleep(completionHandler: @escaping () -> Void) { // Add code here to get ready to sleep. Task { - await self.runtimeEnv?.stop() - completionHandler() + await self.runtimeEnv?.submitCommand(command: .stop(completion: { + SDLLogger.log("[PacketTunnelProvider] sleep") + })) } + completionHandler() } override func wake() { SDLLogger.log("[PacketTunnelProvider] wake up!!!!!!!") - // 启动monitor - let monitor = SDLPathMonitor() - // 启动监视器,允许重入 - monitor.start() - SDLLogger.log("[PacketTunnelProvider] monitor started") - // Add code here to wake up. Task { - - defer { - monitor.stop() - } - - // 等待网络可达 - _ = await monitor.statusStream().first {$0 == .satisfied} - SDLLogger.log("[PacketTunnelProvider] network is satisfied") // 重新启动 - try await self.runtimeEnv?.start(provider: self) + await self.runtimeEnv?.submitCommand(command: .start(completion: { err in + SDLLogger.log("[PacketTunnelProvider] wakeup and try start") + })) } - } private func handleAppRequest(message: AppRequest) async throws -> Data? { - guard let contextActor = self.runtimeEnv?.getContextActor() else { + guard let contextActor = await self.runtimeEnv?.getContextActor() else { throw TunnelError.invalidContext } @@ -130,146 +116,3 @@ class PacketTunnelProvider: NEPacketTunnelProvider { } } - -private class SDLRuntimeEnvironment { - private enum State { - case idle - case starting - case running - case stopping - } - - private let stateLock = NSLock() - private var state: State = .idle - private var pendingStop = false - private weak var pendingStartProvider: PacketTunnelProvider? - private var contextActor: SDLContextActor? - private var config: SDLConfiguration - private let rsaCipher: CCRSACipher - - init(config: SDLConfiguration, rsaCipher: CCRSACipher) { - self.config = config - self.rsaCipher = rsaCipher - } - - func start(provider: PacketTunnelProvider) async throws { - guard self.markStarting(provider: provider) else { - return - } - - // 重置通知中心 - SDLTunnelAppNotifier.shared.clear() - - let contextActor = SDLContextActor(provider: provider, config: config, rsaCipher: self.rsaCipher) - await contextActor.start() - - let shouldStop = self.markStarted(contextActor: contextActor) - if shouldStop { - await self.stop() - } - } - - func getContextActor() -> SDLContextActor? { - return self.withStateLock { - self.contextActor - } - } - - func stop() async { - guard let contextActor = self.markStopping() else { - return - } - - await contextActor.stop() - - if let provider = self.markStopped() { - try? await self.start(provider: provider) - } - } - - private func markStarting(provider: PacketTunnelProvider) -> Bool { - return self.withStateLock { - switch self.state { - case .idle: - self.pendingStop = false - self.pendingStartProvider = nil - self.state = .starting - return true - - case .starting, .running: - SDLLogger.log("[SDLRuntimeEnvironment] skip duplicated start: \(self.state)", for: .debug) - return false - - case .stopping: - self.pendingStartProvider = provider - SDLLogger.log("[SDLRuntimeEnvironment] delay start until stop finishes", for: .debug) - return false - } - } - } - - private func markStarted(contextActor: SDLContextActor) -> Bool { - return self.withStateLock { - self.contextActor = contextActor - self.state = .running - - let shouldStop = self.pendingStop - self.pendingStop = false - return shouldStop - } - } - - private func markStartFailed() { - self.withStateLock { - self.contextActor = nil - self.pendingStop = false - self.pendingStartProvider = nil - self.state = .idle - } - } - - private func markStopping() -> SDLContextActor? { - return self.withStateLock { - switch self.state { - case .idle: - self.contextActor = nil - self.pendingStop = false - return nil - - case .starting: - self.pendingStop = true - SDLLogger.log("[SDLRuntimeEnvironment] delay stop until start finishes", for: .debug) - return nil - - case .stopping: - SDLLogger.log("[SDLRuntimeEnvironment] skip duplicated stop", for: .debug) - return nil - - case .running: - self.state = .stopping - let contextActor = self.contextActor - self.contextActor = nil - self.pendingStop = false - return contextActor - } - } - } - - private func markStopped() -> PacketTunnelProvider? { - return self.withStateLock { - self.state = .idle - let provider = self.pendingStartProvider - self.pendingStartProvider = nil - return provider - } - } - - private func withStateLock(_ body: () -> T) -> T { - self.stateLock.lock() - defer { - self.stateLock.unlock() - } - return body() - } - -} diff --git a/Tun/Punchnet/Actors/SDLContextActor.swift b/Tun/Punchnet/Actors/SDLContextActor.swift index 3dc65ad..b31f1a1 100644 --- a/Tun/Punchnet/Actors/SDLContextActor.swift +++ b/Tun/Punchnet/Actors/SDLContextActor.swift @@ -14,13 +14,6 @@ import NIOCore 1. 处理rsa的加解密逻辑 */ actor SDLContextActor { - enum ReadyState { - case idle - case starting - case ready - case failed(any Error) - case stopped - } private enum UDPHoleKind: Equatable { case v4 @@ -36,8 +29,6 @@ actor SDLContextActor { } } - private var readyState: ReadyState = .idle - var config: SDLConfiguration // nat的网络类型 var natType: SDLNATProberActor.NatType = .blocked @@ -126,11 +117,6 @@ actor SDLContextActor { } public func start() async { - guard case .idle = self.readyState else { - return - } - - self.readyState = .starting await self.startRuntime(resetNotifier: true) } @@ -164,20 +150,6 @@ actor SDLContextActor { // } } - public func sleep() async { - SDLLogger.log("[SDLContext] sleep") - await self.stopRuntime() - } - - public func wake() async { - SDLLogger.log("[SDLContext] wakeup") - - // 先尝试停止 - await self.stopRuntime() - // 重新启动 - await self.startRuntime(resetNotifier: false) - } - // 取消出口节点的时候,ip地址为: 0.0.0.0 public func updateExitNode(exitNodeIp: String) async throws { if let ip = SDLUtil.ipv4StrToInt32(exitNodeIp), ip > 0 { @@ -211,6 +183,7 @@ actor SDLContextActor { group.addTask { for await event in quicClient.eventStream { + try Task.checkCancellation() switch event { case .ready: readyContinuation.yield() @@ -262,13 +235,14 @@ actor SDLContextActor { SDLLogger.log("[SDLContext] quic welcome: \(welcome)") // 注册 await self.doRegisterSuper() - + SDLLogger.log("[SDLContext] quic doRegisterSuper") + // 任务取消机制 self.registerTask = Task { do { try await Task.sleep(for: .seconds(5)) try Task.checkCancellation() - + // 关闭掉当前Tunnel self.publishTunnelEvent(message: "校验失败") // 报告错误并退出 @@ -297,7 +271,7 @@ actor SDLContextActor { self.handleRegisterSuperNak(nakPacket: registerSuperNak) case .peerInfo(let peerInfo): - //SDLLogger.shared.log("[SDLContext] peer message: \(peerInfo)") + SDLLogger.log("[SDLContext] peer message: \(peerInfo)") await self.puncherActor.handlePeerInfo(using: self.udpHole, udpHoleV6: self.udpHoleV6, peerInfo: peerInfo) case .event(let event): await self.handleEvent(event: event) @@ -305,7 +279,7 @@ actor SDLContextActor { // 处理权限的请求问题 await self.identifyStore.applyPolicyResponse(policyResponse) case .arpResponse(let arpResponse): - //SDLLogger.shared.log("[SDLContext] get arp response: \(arpResponse)") + SDLLogger.log("[SDLContext] get arp response: \(arpResponse)") await self.arpServer.handleArpResponse(arpResponse: arpResponse) } } @@ -384,7 +358,9 @@ actor SDLContextActor { self.udpHoleWorkers = [messageTask] // 开始探测nat的类型 - await self.probeNatType() + Task { + await self.probeNatType() + } return udpHole } @@ -413,7 +389,6 @@ actor SDLContextActor { // 处理context的停止问题 public func stop() async { - self.readyState = .stopped await self.stopRuntime() } diff --git a/Tun/SDLRuntimeEnvironment.swift b/Tun/SDLRuntimeEnvironment.swift new file mode 100644 index 0000000..4762c1f --- /dev/null +++ b/Tun/SDLRuntimeEnvironment.swift @@ -0,0 +1,117 @@ +import Foundation + +enum SDLRuntimeEnvironmentCommand { + case start(completion: @Sendable (Error?) -> Void) + case stop(completion: @Sendable () -> Void) +} + +actor SDLRuntimeEnvironment { + private enum State { + case idle + case running + } + + private var state: State = .idle + private var contextActor: SDLContextActor? + + private var config: SDLConfiguration + private let rsaCipher: CCRSACipher + private let provider: PacketTunnelProvider + + private let commandStream: AsyncStream + private let commandCont: AsyncStream.Continuation + + private var commandTask: Task? + + init(config: SDLConfiguration, rsaCipher: CCRSACipher, provider: PacketTunnelProvider) { + self.config = config + self.rsaCipher = rsaCipher + self.provider = provider + + let pair = AsyncStream.makeStream(of: SDLRuntimeEnvironmentCommand.self) + self.commandStream = pair.stream + self.commandCont = pair.continuation + } + + func submitCommand(command: SDLRuntimeEnvironmentCommand) { + self.commandCont.yield(command) + } + + func getContextActor() -> SDLContextActor? { + self.contextActor + } + + func run() { + let stream = self.commandStream + + self.commandTask = Task { [weak self] in + for await command in stream { + guard let self else { + break + } + + await self.handle(command) + } + } + } + + private func handle(_ command: SDLRuntimeEnvironmentCommand) async { + switch command { + case .start(let handler): + do { + try await self.startCommand() + handler(nil) + } catch { + handler(error) + } + + case .stop(let handler): + await self.stopCommand() + handler() + } + } + + private func startCommand() async throws { + switch self.state { + case .idle: + SDLTunnelAppNotifier.shared.clear() + + let contextActor = SDLContextActor( + provider: provider, + config: config, + rsaCipher: self.rsaCipher + ) + + self.contextActor = contextActor + await contextActor.start() + self.state = .running + case .running: + SDLLogger.log("[SDLRuntimeEnvironment] is running, ignore start command") + } + } + + private func stopCommand() async { + switch self.state { + case .idle: + SDLLogger.log("[SDLRuntimeEnvironment] is idle, ignore stop command") + + case .running: + let contextActor = self.contextActor + self.contextActor = nil + self.state = .idle + + await contextActor?.stop() + } + } + + func shutdown() { + self.commandCont.finish() + self.commandTask?.cancel() + self.commandTask = nil + } + + deinit { + self.commandCont.finish() + self.commandTask?.cancel() + } +}