From 5c3276e6b4d516148893d68561888bba20fb32de Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Wed, 27 May 2026 16:24:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=BB=E8=A6=81=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tun/Super/SDLSuperService.swift | 73 ---------- Tun/Super/SDLSuperSession.swift | 80 +++++++++++ Tun/UDPHole/SDLUDPHoleService.swift | 206 -------------------------- Tun/UDPHole/SDLUDPHoleSession.swift | 214 ++++++++++++++++++++++++++++ 4 files changed, 294 insertions(+), 279 deletions(-) create mode 100644 Tun/Super/SDLSuperSession.swift create mode 100644 Tun/UDPHole/SDLUDPHoleSession.swift diff --git a/Tun/Super/SDLSuperService.swift b/Tun/Super/SDLSuperService.swift index 9168d6c..98ab823 100644 --- a/Tun/Super/SDLSuperService.swift +++ b/Tun/Super/SDLSuperService.swift @@ -81,76 +81,3 @@ actor SDLSuperService { await self.onMessage(message) } } - -final class SDLSuperSession: @unchecked Sendable { - typealias MessageHandler = @Sendable (SDLQUICInboundMessage) async -> Void - - private let serverEndpoint: SDLConfiguration.ResolvedServerEndpoint - private let port: UInt16 - private let onMessage: MessageHandler - private let client: SDLSuperClient - - init(serverEndpoint: SDLConfiguration.ResolvedServerEndpoint, port: UInt16, onMessage: @escaping MessageHandler) { - self.serverEndpoint = serverEndpoint - self.port = port - self.onMessage = onMessage - self.client = SDLSuperClient(serverEndpoint: serverEndpoint, port: port) - } - - func run() async throws { - do { - try await self.runLoops() - await self.stop() - } catch { - await self.stop() - throw error - } - } - - func stop() async { - await self.client.stop() - } - - func send(type: SDLPacketType, data: Data) async { - await self.client.send(type: type, data: data) - } - - private func runLoops() async throws { - SDLLogger.log("[SDLSuperSession] start super client: \(self.serverEndpoint.ip)") - - try await withThrowingTaskGroup(of: Void.self) { group in - defer { - group.cancelAll() - } - - group.addTask { - try await self.client.run() - } - - group.addTask { - try await self.readLoop() - } - - group.addTask { - try await self.pingLoop() - } - - _ = try await group.next() - } - } - - private func readLoop() async throws { - for try await message in self.client.messageStream { - try Task.checkCancellation() - await self.onMessage(message) - } - } - - private func pingLoop() async throws { - while true { - try await Task.sleep(for: .seconds(5)) - try Task.checkCancellation() - await self.client.send(type: .ping, data: Data()) - } - } -} diff --git a/Tun/Super/SDLSuperSession.swift b/Tun/Super/SDLSuperSession.swift new file mode 100644 index 0000000..9759988 --- /dev/null +++ b/Tun/Super/SDLSuperSession.swift @@ -0,0 +1,80 @@ +// +// SDLSuperSession.swift +// punchnet +// +// Created by 安礼成 on 2026/5/27. +// +import Foundation + +final class SDLSuperSession: @unchecked Sendable { + typealias MessageHandler = @Sendable (SDLQUICInboundMessage) async -> Void + + private let serverEndpoint: SDLConfiguration.ResolvedServerEndpoint + private let port: UInt16 + private let onMessage: MessageHandler + private let client: SDLSuperClient + + init(serverEndpoint: SDLConfiguration.ResolvedServerEndpoint, port: UInt16, onMessage: @escaping MessageHandler) { + self.serverEndpoint = serverEndpoint + self.port = port + self.onMessage = onMessage + self.client = SDLSuperClient(serverEndpoint: serverEndpoint, port: port) + } + + func run() async throws { + do { + try await self.runLoops() + await self.stop() + } catch { + await self.stop() + throw error + } + } + + func stop() async { + await self.client.stop() + } + + func send(type: SDLPacketType, data: Data) async { + await self.client.send(type: type, data: data) + } + + private func runLoops() async throws { + SDLLogger.log("[SDLSuperSession] start super client: \(self.serverEndpoint.ip)") + + try await withThrowingTaskGroup(of: Void.self) { group in + defer { + group.cancelAll() + } + + group.addTask { + try await self.client.run() + } + + group.addTask { + try await self.readLoop() + } + + group.addTask { + try await self.pingLoop() + } + + _ = try await group.next() + } + } + + private func readLoop() async throws { + for try await message in self.client.messageStream { + try Task.checkCancellation() + await self.onMessage(message) + } + } + + private func pingLoop() async throws { + while true { + try await Task.sleep(for: .seconds(5)) + try Task.checkCancellation() + await self.client.send(type: .ping, data: Data()) + } + } +} diff --git a/Tun/UDPHole/SDLUDPHoleService.swift b/Tun/UDPHole/SDLUDPHoleService.swift index 333b638..f2036d9 100644 --- a/Tun/UDPHole/SDLUDPHoleService.swift +++ b/Tun/UDPHole/SDLUDPHoleService.swift @@ -106,209 +106,3 @@ actor SDLUDPHoleService { await self.onEvent(event) } } - -actor SDLUDPHoleSession { - private let proberActor: SDLNATProberActor - private let includeV6: Bool - private let onEvent: SDLUDPHoleService.EventHandler - private let onData: SDLUDPHoleService.DataHandler - - private var udpHole: SDLUDPHole? - private var udpHoleV6: SDLUDPHoleV6? - private var localAddress: SocketAddress? - - init( - proberActor: SDLNATProberActor, - includeV6: Bool, - onEvent: @escaping SDLUDPHoleService.EventHandler, - onData: @escaping SDLUDPHoleService.DataHandler - ) { - self.proberActor = proberActor - self.includeV6 = includeV6 - self.onEvent = onEvent - self.onData = onData - } - - func run() async throws { - do { - try await withThrowingTaskGroup(of: Void.self) { group in - defer { - group.cancelAll() - } - - group.addTask { - try await self.runV4() - } - - if self.includeV6 { - group.addTask { - try await self.runV6() - } - } - - try await group.waitForAll() - } - await self.stop() - } catch { - await self.stop() - throw error - } - } - - func stop() async { - let udpHole = self.udpHole - self.udpHole = nil - self.localAddress = nil - - let udpHoleV6 = self.udpHoleV6 - self.udpHoleV6 = nil - - await self.proberActor.cancelAll() - await udpHole?.stop() - udpHoleV6?.stop() - } - - func send(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) async { - switch remoteAddress { - case .v4: - guard let udpHole else { - SDLLogger.log("[SDLUDPHoleSession] udpHole is nil for remoteAddress: \(remoteAddress)", for: .debug) - return - } - - await udpHole.send(type: type, data: data, remoteAddress: remoteAddress) - case .v6: - guard let udpHoleV6 else { - SDLLogger.log("[SDLUDPHoleSession] udpHoleV6 is nil for remoteAddress: \(remoteAddress)", for: .debug) - return - } - - udpHoleV6.send(type: type, data: data, remoteAddress: remoteAddress) - default: - SDLLogger.log("[SDLUDPHoleSession] unsupported socket family: \(remoteAddress)", for: .debug) - } - } - - private func runV4() async throws { - let udpHole = try SDLUDPHole() - let localAddress = try await udpHole.start() - self.udpHole = udpHole - self.localAddress = localAddress - - SDLLogger.log("[SDLUDPHoleSession] udpHole started, on address: \(localAddress)") - await self.onEvent(.ready(localAddress)) - - do { - try await withThrowingTaskGroup(of: Void.self) { group in - defer { - group.cancelAll() - } - - group.addTask { - try await self.readV4Loop(udpHole: udpHole) - } - - group.addTask { - await self.probeNatType(udpHole: udpHole) - } - - try await group.waitForAll() - } - } catch { - await udpHole.stop() - if self.udpHole === udpHole { - self.udpHole = nil - self.localAddress = nil - } - throw error - } - } - - private func readV4Loop(udpHole: SDLUDPHole) async throws { - for try await datagram in await udpHole.messageStream() { - try Task.checkCancellation() - try await self.handleV4Message(remoteAddress: datagram.remoteAddress, message: datagram.message) - } - } - - private func probeNatType(udpHole: SDLUDPHole) async { - if Task.isCancelled { - return - } - - let natType = await self.proberActor.probeNatType(using: udpHole) - if Task.isCancelled { - return - } - - await self.onEvent(.natType(natType)) - } - - private func handleV4Message(remoteAddress: SocketAddress, message: SDLHoleMessage) async throws { - switch message { - case .control(let control): - switch control { - case .stunProbeReply(let probeReply): - await self.proberActor.handleProbeReply(localAddress: self.localAddress, reply: probeReply) - default: - await self.onEvent(.packet(remoteAddress, control, source: .v4)) - } - case .data(let data): - await self.onData(data) - } - } - - private func runV6() async throws { - let udpHoleV6 = try SDLUDPHoleV6() - let localAddress = try udpHoleV6.start() - self.udpHoleV6 = udpHoleV6 - - if let localAddress { - SDLLogger.log("[SDLUDPHoleSession] udpHoleV6 started, on address: \(localAddress)") - } else { - SDLLogger.log("[SDLUDPHoleSession] udpHoleV6 started, no local address") - } - - do { - try await withThrowingTaskGroup(of: Void.self) { group in - defer { - group.cancelAll() - } - - let onEvent = self.onEvent - let onData = self.onData - group.addTask { - for await (remoteAddress, message) in udpHoleV6.messageStream { - try Task.checkCancellation() - switch message { - case .control(let control): - await onEvent(.packet(remoteAddress, control, source: .v6)) - case .data(let data): - await onData(data) - } - } - } - - group.addTask { - for await event in udpHoleV6.eventStream { - try Task.checkCancellation() - switch event { - case .ready: - SDLLogger.log("[SDLUDPHoleSession] udpHoleV6 ready") - case .closed, .errorCaught: - throw SDLContextError.udpHoleClosed - } - } - } - - _ = try await group.next() - } - } catch { - udpHoleV6.stop() - if self.udpHoleV6 === udpHoleV6 { - self.udpHoleV6 = nil - } - throw error - } - } -} diff --git a/Tun/UDPHole/SDLUDPHoleSession.swift b/Tun/UDPHole/SDLUDPHoleSession.swift new file mode 100644 index 0000000..28238ad --- /dev/null +++ b/Tun/UDPHole/SDLUDPHoleSession.swift @@ -0,0 +1,214 @@ +// +// SDLUDPHoleSession.swift +// punchnet +// +// Created by 安礼成 on 2026/5/27. +// +import Foundation +import NIOCore + +actor SDLUDPHoleSession { + private let proberActor: SDLNATProberActor + private let includeV6: Bool + private let onEvent: SDLUDPHoleService.EventHandler + private let onData: SDLUDPHoleService.DataHandler + + private var udpHole: SDLUDPHole? + private var udpHoleV6: SDLUDPHoleV6? + private var localAddress: SocketAddress? + + init( + proberActor: SDLNATProberActor, + includeV6: Bool, + onEvent: @escaping SDLUDPHoleService.EventHandler, + onData: @escaping SDLUDPHoleService.DataHandler + ) { + self.proberActor = proberActor + self.includeV6 = includeV6 + self.onEvent = onEvent + self.onData = onData + } + + func run() async throws { + do { + try await withThrowingTaskGroup(of: Void.self) { group in + defer { + group.cancelAll() + } + + group.addTask { + try await self.runV4() + } + + if self.includeV6 { + group.addTask { + try await self.runV6() + } + } + + try await group.waitForAll() + } + await self.stop() + } catch { + await self.stop() + throw error + } + } + + func stop() async { + let udpHole = self.udpHole + self.udpHole = nil + self.localAddress = nil + + let udpHoleV6 = self.udpHoleV6 + self.udpHoleV6 = nil + + await self.proberActor.cancelAll() + await udpHole?.stop() + udpHoleV6?.stop() + } + + func send(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) async { + switch remoteAddress { + case .v4: + guard let udpHole else { + SDLLogger.log("[SDLUDPHoleSession] udpHole is nil for remoteAddress: \(remoteAddress)", for: .debug) + return + } + + await udpHole.send(type: type, data: data, remoteAddress: remoteAddress) + case .v6: + guard let udpHoleV6 else { + SDLLogger.log("[SDLUDPHoleSession] udpHoleV6 is nil for remoteAddress: \(remoteAddress)", for: .debug) + return + } + + udpHoleV6.send(type: type, data: data, remoteAddress: remoteAddress) + default: + SDLLogger.log("[SDLUDPHoleSession] unsupported socket family: \(remoteAddress)", for: .debug) + } + } + + private func runV4() async throws { + let udpHole = try SDLUDPHole() + let localAddress = try await udpHole.start() + self.udpHole = udpHole + self.localAddress = localAddress + + SDLLogger.log("[SDLUDPHoleSession] udpHole started, on address: \(localAddress)") + await self.onEvent(.ready(localAddress)) + + do { + try await withThrowingTaskGroup(of: Void.self) { group in + defer { + group.cancelAll() + } + + group.addTask { + try await self.readV4Loop(udpHole: udpHole) + } + + group.addTask { + await self.probeNatType(udpHole: udpHole) + } + + try await group.waitForAll() + } + } catch { + await udpHole.stop() + if self.udpHole === udpHole { + self.udpHole = nil + self.localAddress = nil + } + throw error + } + } + + private func readV4Loop(udpHole: SDLUDPHole) async throws { + for try await datagram in await udpHole.messageStream() { + try Task.checkCancellation() + try await self.handleV4Message(remoteAddress: datagram.remoteAddress, message: datagram.message) + } + } + + private func probeNatType(udpHole: SDLUDPHole) async { + if Task.isCancelled { + return + } + + let natType = await self.proberActor.probeNatType(using: udpHole) + if Task.isCancelled { + return + } + + await self.onEvent(.natType(natType)) + } + + private func handleV4Message(remoteAddress: SocketAddress, message: SDLHoleMessage) async throws { + switch message { + case .control(let control): + switch control { + case .stunProbeReply(let probeReply): + await self.proberActor.handleProbeReply(localAddress: self.localAddress, reply: probeReply) + default: + await self.onEvent(.packet(remoteAddress, control, source: .v4)) + } + case .data(let data): + await self.onData(data) + } + } + + private func runV6() async throws { + let udpHoleV6 = try SDLUDPHoleV6() + let localAddress = try udpHoleV6.start() + self.udpHoleV6 = udpHoleV6 + + if let localAddress { + SDLLogger.log("[SDLUDPHoleSession] udpHoleV6 started, on address: \(localAddress)") + } else { + SDLLogger.log("[SDLUDPHoleSession] udpHoleV6 started, no local address") + } + + do { + try await withThrowingTaskGroup(of: Void.self) { group in + defer { + group.cancelAll() + } + + let onEvent = self.onEvent + let onData = self.onData + group.addTask { + for await (remoteAddress, message) in udpHoleV6.messageStream { + try Task.checkCancellation() + switch message { + case .control(let control): + await onEvent(.packet(remoteAddress, control, source: .v6)) + case .data(let data): + await onData(data) + } + } + } + + group.addTask { + for await event in udpHoleV6.eventStream { + try Task.checkCancellation() + switch event { + case .ready: + SDLLogger.log("[SDLUDPHoleSession] udpHoleV6 ready") + case .closed, .errorCaught: + throw SDLContextError.udpHoleClosed + } + } + } + + _ = try await group.next() + } + } catch { + udpHoleV6.stop() + if self.udpHoleV6 === udpHoleV6 { + self.udpHoleV6 = nil + } + throw error + } + } +}