Compare commits

..

No commits in common. "385edf3c6cc3cca856f01c377f1bc8331f03e0a0" and "3225d8fa17d7028e81b16e2c3470cec61bac926e" have entirely different histories.

4 changed files with 105 additions and 124 deletions

View File

@ -82,7 +82,7 @@ actor ArpServer {
var arpRequest = SDLArpRequest() var arpRequest = SDLArpRequest()
arpRequest.targetIp = targetIp arpRequest.targetIp = targetIp
await quicClient.send(type: .arpRequest, data: try arpRequest.serializedData()) quicClient.send(type: .arpRequest, data: try arpRequest.serializedData())
} }
func handleArpResponse(arpResponse: SDLArpResponse) { func handleArpResponse(arpResponse: SDLArpResponse) {

View File

@ -166,49 +166,72 @@ actor SDLContextActor {
// monitor // monitor
let quicClient = SDLQUICClient(host: self.config.serverHost, port: 1443) let quicClient = SDLQUICClient(host: self.config.serverHost, port: 1443)
self.quicClient = quicClient self.quicClient = quicClient
await quicClient.start() quicClient.start()
defer { defer {
Task { self.quicClient?.stop()
await self.quicClient?.stop()
self.quicClient = nil self.quicClient = nil
SDLLogger.log("[SDLContext] quicClient: stop") SDLLogger.log("[SDLContext] quicClient: stop")
} }
}
// quic // quic
try await Task.sleep(for: .seconds(0.5)) try await Task.sleep(for: .seconds(0.5))
SDLLogger.log("[SDLContext] start quic client: \(self.config.serverHost)") SDLLogger.log("[SDLContext] start quic client: \(self.config.serverHost)")
try await withTaskCancellationHandler {
try await withThrowingTaskGroup { group in try await withThrowingTaskGroup { group in
defer { defer {
group.cancelAll() group.cancelAll()
} }
// Actor AsyncStream
let (readyStream, readyContinuation) = AsyncStream<Void>.makeStream()
group.addTask { group.addTask {
for try await message in await quicClient.messageStream { for await event in quicClient.eventStream {
try Task.checkCancellation()
switch event {
case .ready:
readyContinuation.yield()
case .failed(let error):
throw error
case .cancelled:
throw SDLQUICEvent.cancelled
case .writeFailed(let error):
throw error
}
}
}
group.addTask {
//
var it = readyStream.makeAsyncIterator()
await it.next()
try Task.checkCancellation()
await withThrowingTaskGroup { workerGroup in
workerGroup.addTask {
for await message in quicClient.messageStream {
try Task.checkCancellation() try Task.checkCancellation()
await self.handleQUICMessage(message: message) await self.handleQUICMessage(message: message)
} }
} }
group.addTask { workerGroup.addTask {
while true { let timerStream = SDLAsyncTimerStream()
try await Task.sleep(for: .seconds(5)) timerStream.start(interval: .seconds(5))
for await _ in timerStream.stream {
try Task.checkCancellation() try Task.checkCancellation()
await quicClient.send(type: .ping, data: Data()) quicClient.send(type: .ping, data: Data())
} }
SDLLogger.log("[SDLQUICClient] udp pingTask cancel", for: .debug) SDLLogger.log("[SDLQUICClient] udp pingTask cancel", for: .debug)
} }
}
}
try await group.next() try await group.next()
} }
} onCancel: {
Task {
await quicClient.stop()
}
}
} }
private func handleQUICMessage(message: SDLQUICInboundMessage) async { private func handleQUICMessage(message: SDLQUICInboundMessage) async {
@ -857,7 +880,7 @@ extension SDLContextActor {
if let registerSuperData = try? registerSuper.serializedData() { if let registerSuperData = try? registerSuper.serializedData() {
SDLLogger.log("[SDLContext] will send register super") SDLLogger.log("[SDLContext] will send register super")
await self.quicClient?.send(type: .registerSuper, data: registerSuperData) self.quicClient?.send(type: .registerSuper, data: registerSuperData)
} }
} }

View File

@ -90,7 +90,7 @@ actor SDLPuncherActor {
phase: .waitingPeerInfo(deadline: now.addingTimeInterval(self.peerInfoTimeout)) phase: .waitingPeerInfo(deadline: now.addingTimeInterval(self.peerInfoTimeout))
) )
await quicClient.send(type: .queryInfo, data: queryData) quicClient.send(type: .queryInfo, data: queryData)
} }
func handlePeerInfo(using udpHole: SDLUDPHole?, udpHoleV6: SDLUDPHoleV6?, peerInfo: SDLPeerInfo) async { func handlePeerInfo(using udpHole: SDLUDPHole?, udpHoleV6: SDLUDPHoleV6?, peerInfo: SDLPeerInfo) async {

View File

@ -15,61 +15,55 @@ import Security
enum SDLQUICError: Error { enum SDLQUICError: Error {
case connectionFailed(Error) case connectionFailed(Error)
case connectionCancelled case connectionCancelled
case writeFailed(Error)
case internalError(Error)
case timeout case timeout
case decodeError(String) case decodeError(String)
case packetTooLarge case packetTooLarge
case dataStreamClosed case dataStreamClosed
} }
actor SDLQUICClient { enum SDLQUICEvent: Error {
enum State { case ready
case idle case failed(Error)
case running case cancelled
case stopped case writeFailed(Error)
} }
private var state: State = .idle
final class SDLQUICClient {
private let frameParser: SDLQUICFrameParser private let frameParser: SDLQUICFrameParser
// //
public var messageStream: AsyncThrowingStream<SDLQUICInboundMessage, Error> public var messageStream: AsyncStream<SDLQUICInboundMessage>
private let messageCont: AsyncThrowingStream<SDLQUICInboundMessage, Error>.Continuation private let messageCont: AsyncStream<SDLQUICInboundMessage>.Continuation
private var isMessageContinuationFinished: Bool = false
private var readTask: Task<Void, Never>? private var readTask: Task<Void, Never>?
private var connection: NWConnection? //
public var eventStream: AsyncStream<SDLQUICEvent>
private let eventCont: AsyncStream<SDLQUICEvent>.Continuation
private var isFinished: Bool = false
private let connection: NWConnection
private let queue = DispatchQueue(label: "com.sdl.QUICClient.queue") // 线 private let queue = DispatchQueue(label: "com.sdl.QUICClient.queue") // 线
private let host: String
private let port: UInt16
init(host: String, port: UInt16, maxBufferSize: Int = 2 * 1024 * 1024) { init(host: String, port: UInt16, maxBufferSize: Int = 2 * 1024 * 1024) {
self.host = host
self.port = port
self.frameParser = SDLQUICFrameParser(maxBufferSize: maxBufferSize)
(self.messageStream, self.messageCont) = AsyncThrowingStream.makeStream(of: SDLQUICInboundMessage.self)
}
func start() {
let options = NWProtocolTLS.Options() let options = NWProtocolTLS.Options()
sec_protocol_options_add_tls_application_protocol( sec_protocol_options_add_tls_application_protocol(
options.securityProtocolOptions, options.securityProtocolOptions,
"punchnet/1.0" "punchnet/1.0"
) )
self.frameParser = SDLQUICFrameParser(maxBufferSize: maxBufferSize)
(self.eventStream, self.eventCont) = AsyncStream.makeStream(of: SDLQUICEvent.self)
(self.messageStream, self.messageCont) = AsyncStream.makeStream(of: SDLQUICInboundMessage.self)
// //
sec_protocol_options_set_verify_block( sec_protocol_options_set_verify_block(
options.securityProtocolOptions, options.securityProtocolOptions,
{ metadata, trust, complete in { metadata, trust, complete in
// //
complete(TLSVerifier.verify(trust: trust, host: self.host)) complete(TLSVerifier.verify(trust: trust, host: host))
}, },
self.queue self.queue
) )
@ -79,95 +73,64 @@ actor SDLQUICClient {
// Network.framework // Network.framework
params.preferNoProxies = true params.preferNoProxies = true
let connection = NWConnection(host: .init(host), port: .init(rawValue: port)!, using: params) self.connection = NWConnection(host: .init(host), port: .init(rawValue: port)!, using: params)
}
func start() {
connection.stateUpdateHandler = { [weak self] state in connection.stateUpdateHandler = { [weak self] state in
SDLLogger.log("[SDLQUICClient] new state: \(state)", for: .debug) SDLLogger.log("[SDLQUICClient] new state: \(state)", for: .debug)
Task {
await self?.handleConnectionState(state: state)
}
}
connection.start(queue: self.queue)
self.connection = connection
}
private func handleConnectionState(state: NWConnection.State) {
switch state { switch state {
case .ready: case .ready:
self.startReadTask() self?.startReadTask()
self.state = .running self?.eventCont.yield(.ready)
case .failed(let error): case .failed(let error):
self.finishMessageContinuationIfNeed(throwing: .connectionFailed(error)) self?.eventCont.yield(.failed(error))
case .cancelled: case .cancelled:
self.finishMessageContinuationIfNeed(throwing: .connectionCancelled) self?.eventCont.yield(.cancelled)
default: default:
() ()
} }
} }
connection.start(queue: self.queue)
private func finishMessageContinuationIfNeed(throwing error: SDLQUICError?) {
guard !self.isMessageContinuationFinished else {
return
}
self.isMessageContinuationFinished = true
if let error {
self.messageCont.finish(throwing: error)
} else {
self.messageCont.finish()
}
} }
private func startReadTask() { private func startReadTask() {
self.readTask?.cancel() self.readTask?.cancel()
self.readTask = Task { self.readTask = Task {
do { do {
while true { while !Task.isCancelled {
try Task.checkCancellation()
let data = try await self.readOnce() let data = try await self.readOnce()
let frames = try self.frameParser.parseFrames(data: data) let frames = try self.frameParser.parseFrames(data: data)
for frame in frames { for frame in frames {
if let message = SDLQUICCodec.decode(frame: frame) { if let message = SDLQUICCodec.decode(frame: frame) {
self.messageCont.yield(message) self.messageCont.yield(message)
} else {
self.finishMessageContinuationIfNeed(throwing: .decodeError("invalid message"))
} }
} }
} }
} catch let err { } catch {
self.finishMessageContinuationIfNeed(throwing: .internalError(err)) self.messageCont.finish()
} }
} }
} }
func send(type: SDLPacketType, data: Data) { func send(type: SDLPacketType, data: Data) {
guard case .running = state, let connection = self.connection, connection.state == .ready else {
return
}
var len = UInt16(data.count + 1).bigEndian var len = UInt16(data.count + 1).bigEndian
var packet = Data(Data(bytes: &len, count: 2)) var packet = Data(Data(bytes: &len, count: 2))
packet.append(type.rawValue) packet.append(type.rawValue)
packet.append(data) packet.append(data)
connection.send(content: packet, completion: .contentProcessed { [weak self] error in connection.send(content: packet, completion: .contentProcessed { [weak self] error in
if let error { if let error {
Task {
SDLLogger.log("[SDLQUICClient] send data get error: \(error)", for: .debug) SDLLogger.log("[SDLQUICClient] send data get error: \(error)", for: .debug)
await self?.finishMessageContinuationIfNeed(throwing: .writeFailed(error)) self?.eventCont.yield(.writeFailed(error))
}
} }
}) })
} }
private func readOnce() async throws -> Data { private func readOnce() async throws -> Data {
guard let connection = self.connection else {
throw SDLQUICError.connectionCancelled
}
return try await withCheckedThrowingContinuation { cont in return try await withCheckedThrowingContinuation { cont in
connection.receive(minimumIncompleteLength: 1, maximumLength: 64 * 1024) { data, _, isComplete, error in self.connection.receive(minimumIncompleteLength: 1, maximumLength: 64 * 1024) { data, _, isComplete, error in
if let error { if let error {
cont.resume(throwing: error) cont.resume(throwing: error)
return return
@ -183,15 +146,10 @@ actor SDLQUICClient {
} }
func stop() { func stop() {
guard self.state != .stopped else {
return
}
self.state = .stopped
self.readTask?.cancel() self.readTask?.cancel()
self.connection?.cancel() self.connection.cancel()
self.finishMessageContinuationIfNeed(throwing: nil) self.eventCont.finish()
self.messageCont.finish()
} }
} }