fix SDLUDPHole

This commit is contained in:
anlicheng 2026-05-07 08:43:48 +08:00
parent 358e555666
commit 5b37ac2552
3 changed files with 50 additions and 5 deletions

View File

@ -27,6 +27,7 @@ actor SDLNATProberActor {
// step -> SDLStunProbeReply // step -> SDLStunProbeReply
var replies: [UInt32: SDLStunProbeReply] var replies: [UInt32: SDLStunProbeReply]
var timeoutTask: Task<Void, Never>? var timeoutTask: Task<Void, Never>?
var sendTask: Task<Void, Never>?
var continuation: CheckedContinuation<NatType, Never> var continuation: CheckedContinuation<NatType, Never>
private var isFinished: Bool = false private var isFinished: Bool = false
@ -46,6 +47,7 @@ actor SDLNATProberActor {
self.continuation.resume(returning: type) self.continuation.resume(returning: type)
// //
self.timeoutTask?.cancel() self.timeoutTask?.cancel()
self.sendTask?.cancel()
self.isFinished = true self.isFinished = true
} }
} }
@ -68,6 +70,10 @@ actor SDLNATProberActor {
// MARK: - Public API // MARK: - Public API
func probeNatType(using udpHole: SDLUDPHole) async -> NatType { func probeNatType(using udpHole: SDLUDPHole) async -> NatType {
if Task.isCancelled {
return .blocked
}
let cookieId = self.cookieId let cookieId = self.cookieId
self.cookieId &+= 1 self.cookieId &+= 1
@ -83,7 +89,7 @@ actor SDLNATProberActor {
continuation: continuation continuation: continuation
) )
self.sessions[cookieId] = session self.sessions[cookieId] = session
Task { session.sendTask = Task {
await self.sendProbe(using: udpHole, cookie: cookieId) await self.sendProbe(using: udpHole, cookie: cookieId)
} }
} }
@ -132,6 +138,14 @@ actor SDLNATProberActor {
} }
} }
func cancelAll() {
let sessions = self.sessions
self.sessions.removeAll()
sessions.values.forEach { session in
session.finished(with: .blocked)
}
}
/// Timer / Task /// Timer / Task
private func handleTimeout(cookie: UInt32) async { private func handleTimeout(cookie: UInt32) async {
guard let session = self.sessions[cookie] else { guard let session = self.sessions[cookie] else {
@ -158,9 +172,21 @@ actor SDLNATProberActor {
// MARK: - Internal helpers // MARK: - Internal helpers
private func sendProbe(using udpHole: SDLUDPHole, cookie: UInt32) async { private func sendProbe(using udpHole: SDLUDPHole, cookie: UInt32) async {
guard !Task.isCancelled else {
return
}
await udpHole.send(type: .stunProbe, data: makeProbePacket(cookieId: cookie, step: 1, attr: .none), remoteAddress: addressArray[0][0]) await udpHole.send(type: .stunProbe, data: makeProbePacket(cookieId: cookie, step: 1, attr: .none), remoteAddress: addressArray[0][0])
guard !Task.isCancelled else {
return
}
await udpHole.send(type: .stunProbe, data: makeProbePacket(cookieId: cookie, step: 2, attr: .none), remoteAddress: addressArray[1][1]) await udpHole.send(type: .stunProbe, data: makeProbePacket(cookieId: cookie, step: 2, attr: .none), remoteAddress: addressArray[1][1])
guard !Task.isCancelled else {
return
}
await udpHole.send(type: .stunProbe, data: makeProbePacket(cookieId: cookie, step: 3, attr: .peer), remoteAddress: addressArray[0][0]) await udpHole.send(type: .stunProbe, data: makeProbePacket(cookieId: cookie, step: 3, attr: .peer), remoteAddress: addressArray[0][0])
guard !Task.isCancelled else {
return
}
await udpHole.send(type: .stunProbe, data: makeProbePacket(cookieId: cookie, step: 4, attr: .port), remoteAddress: addressArray[0][0]) await udpHole.send(type: .stunProbe, data: makeProbePacket(cookieId: cookie, step: 4, attr: .port), remoteAddress: addressArray[0][0])
} }

View File

@ -182,17 +182,32 @@ actor SDLContextActor {
let udpHole = self.udpHole let udpHole = self.udpHole
self.udpHole = nil self.udpHole = nil
self.udpHoleLocalAddress = nil self.udpHoleLocalAddress = nil
self.udpHoleMonitorTask?.cancel()
let udpHoleMonitorTask = self.udpHoleMonitorTask
self.udpHoleMonitorTask = nil self.udpHoleMonitorTask = nil
self.natProbeTask?.cancel() let natProbeTask = self.natProbeTask
self.natProbeTask = nil self.natProbeTask = nil
udpHoleMonitorTask?.cancel()
natProbeTask?.cancel()
await self.proberActor.cancelAll()
await udpHole?.stop() await udpHole?.stop()
if let natProbeTask {
await natProbeTask.value
}
if let udpHoleMonitorTask {
await udpHoleMonitorTask.value
}
let udpHoleV6 = self.udpHoleV6 let udpHoleV6 = self.udpHoleV6
self.udpHoleV6 = nil self.udpHoleV6 = nil
self.udpHoleV6MonitorTask?.cancel() let udpHoleV6MonitorTask = self.udpHoleV6MonitorTask
self.udpHoleV6MonitorTask = nil self.udpHoleV6MonitorTask = nil
udpHoleV6MonitorTask?.cancel()
udpHoleV6?.stop() udpHoleV6?.stop()
if let udpHoleV6MonitorTask {
await udpHoleV6MonitorTask.value
}
let dnsClient = self.dnsClient let dnsClient = self.dnsClient
self.dnsClient = nil self.dnsClient = nil
@ -680,6 +695,9 @@ extension SDLContextActor {
let proberActor = self.proberActor let proberActor = self.proberActor
self.natProbeTask = Task { [weak self] in self.natProbeTask = Task { [weak self] in
SDLLogger.log("[SDLContext] start probeNatType") SDLLogger.log("[SDLContext] start probeNatType")
if Task.isCancelled {
return
}
let natType = await proberActor.probeNatType(using: udpHole) let natType = await proberActor.probeNatType(using: udpHole)
if Task.isCancelled { if Task.isCancelled {
return return

View File

@ -172,8 +172,9 @@ private final class SDLUDPHoleHandler: ChannelInboundHandler {
func stop() { func stop() {
self.finishMessageContinuationIfNeed(throwing: nil) self.finishMessageContinuationIfNeed(throwing: nil)
try? self.channel?.close().wait() let channel = self.channel
self.channel = nil self.channel = nil
try? channel?.close().wait()
try? self.group.syncShutdownGracefully() try? self.group.syncShutdownGracefully()
let counterActor = self.counterActor let counterActor = self.counterActor