解决网络状态变化的问题

This commit is contained in:
anlicheng 2026-04-29 17:22:51 +08:00
parent e68bf7e106
commit 971fa64685
2 changed files with 42 additions and 120 deletions

View File

@ -29,25 +29,29 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
// //
let rsaCipher = try! CCRSACipher(keySize: 1024) let rsaCipher = try! CCRSACipher(keySize: 1024)
self.rootTask = Task { self.rootTask = Task {
do { // host: "192.168.0.101", port: 1265
// host: "192.168.0.101", port: 1265 guard let options, let config = await SDLConfiguration.parse(options: options) else {
guard let options, let config = await SDLConfiguration.parse(options: options) else { completionHandler(TunnelError.invalidConfiguration)
completionHandler(TunnelError.invalidConfiguration) return
return }
let contextActor = SDLContextActor(provider: self, config: config, rsaCipher: rsaCipher)
self.contextActor = contextActor
await contextActor.start()
//
for await event in await contextActor.events() {
switch event {
case .ready:
completionHandler(nil)
case .failed(let err):
await self.contextActor?.stop()
self.contextActor = nil
completionHandler(err)
} }
let contextActor = SDLContextActor(provider: self, config: config, rsaCipher: rsaCipher)
self.contextActor = contextActor
await contextActor.start()
try await contextActor.waitForReady(timeout: .seconds(30))
completionHandler(nil)
} catch {
await self.contextActor?.stop()
self.contextActor = nil
completionHandler(error)
} }
} }
} }
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {

View File

@ -9,6 +9,11 @@ import Foundation
import NetworkExtension import NetworkExtension
import NIOCore import NIOCore
public enum SDLContextEvent: Sendable {
case ready
case failed(Error)
}
// //
/* /*
1. rsa的加解密逻辑 1. rsa的加解密逻辑
@ -36,8 +41,11 @@ actor SDLContextActor {
} }
} }
//
private let eventStream: AsyncStream<SDLContextEvent>
private let eventContinuation: AsyncStream<SDLContextEvent>.Continuation
private var readyState: ReadyState = .idle private var readyState: ReadyState = .idle
private var readyWaiters: [CheckedContinuation<Void, Error>] = []
var config: SDLConfiguration var config: SDLConfiguration
// nat // nat
@ -121,6 +129,11 @@ actor SDLContextActor {
self.config = config self.config = config
self.rsaCipher = rsaCipher self.rsaCipher = rsaCipher
//
let pair = AsyncStream<SDLContextEvent>.makeStream(bufferingPolicy: .bufferingNewest(32))
self.eventStream = pair.stream
self.eventContinuation = pair.continuation
self.puncherActor = SDLPuncherActor() self.puncherActor = SDLPuncherActor()
self.proberActor = SDLNATProberActor(addressArray: config.stunProbeSocketAddressArray) self.proberActor = SDLNATProberActor(addressArray: config.stunProbeSocketAddressArray)
@ -141,6 +154,10 @@ actor SDLContextActor {
await self.startRuntime(resetNotifier: true) await self.startRuntime(resetNotifier: true)
} }
public func events() -> AsyncStream<SDLContextEvent> {
return eventStream
}
private func startRuntime(resetNotifier: Bool) async { private func startRuntime(resetNotifier: Bool) async {
if resetNotifier { if resetNotifier {
self.prepareTunnelNotifier() self.prepareTunnelNotifier()
@ -186,37 +203,6 @@ actor SDLContextActor {
await self.startRuntime(resetNotifier: false) await self.startRuntime(resetNotifier: false)
} }
public func waitForReady() async throws {
switch self.readyState {
case .ready:
return
case .failed(let error):
throw error
case .stopped:
throw CancellationError()
case .idle, .starting:
try await withCheckedThrowingContinuation { continuation in
self.readyWaiters.append(continuation)
}
}
}
public func waitForReady(timeout: Duration) async throws {
let timeoutTask = Task {
try? await Task.sleep(for: timeout)
if Task.isCancelled {
return
}
self.handleReadyTimeout()
}
defer {
timeoutTask.cancel()
}
try await self.waitForReady()
}
// ip: 0.0.0.0 // ip: 0.0.0.0
public func updateExitNode(exitNodeIp: String) async throws { public func updateExitNode(exitNodeIp: String) async throws {
if let ip = SDLUtil.ipv4StrToInt32(exitNodeIp), ip > 0 { if let ip = SDLUtil.ipv4StrToInt32(exitNodeIp), ip > 0 {
@ -457,7 +443,6 @@ actor SDLContextActor {
// context // context
public func stop() async { public func stop() async {
self.resumeReadyWaiters(.failure(CancellationError()))
self.readyState = .stopped self.readyState = .stopped
await self.stopRuntime() await self.stopRuntime()
} }
@ -701,20 +686,6 @@ actor SDLContextActor {
} }
} }
private func spawnLoop(_ body: @escaping () async throws -> Void) -> Task<Void, Never> {
return Task.detached {
while !Task.isCancelled {
do {
try await body()
} catch is CancellationError {
break
} catch {
try? await Task.sleep(nanoseconds: 2_000_000_000)
}
}
}
}
private func getIpv4ExcludeRoutes() -> [NEIPv4Route] { private func getIpv4ExcludeRoutes() -> [NEIPv4Route] {
// //
let dnsServers = SDLUtil.getMacOSSystemDnsServers() let dnsServers = SDLUtil.getMacOSSystemDnsServers()
@ -737,57 +708,6 @@ actor SDLContextActor {
return ipv4DnsServers.map { NEIPv4Route(destinationAddress: $0, subnetMask: "255.255.255.255") } return ipv4DnsServers.map { NEIPv4Route(destinationAddress: $0, subnetMask: "255.255.255.255") }
} }
private func markReady() {
guard case .starting = self.readyState else {
return
}
self.readyState = .ready
self.resumeReadyWaiters(.success(()))
}
private func handleReadyTimeout() {
switch self.readyState {
case .idle, .starting:
break
case .ready, .failed, .stopped:
return
}
let error = NSError(
domain: "com.jihe.punchnet.tun",
code: -3,
userInfo: [NSLocalizedDescriptionKey: "Tunnel startup timed out"]
)
SDLLogger.log("[SDLContext] wait ready timeout")
self.failReady(error)
self.provider.cancelTunnelWithError(error)
}
private func failReady(_ error: any Error) {
switch self.readyState {
case .ready, .failed, .stopped:
return
case .idle, .starting:
self.readyState = .failed(error)
self.resumeReadyWaiters(.failure(error))
}
}
private func resumeReadyWaiters(_ result: Result<Void, any Error>) {
let waiters = self.readyWaiters
self.readyWaiters.removeAll()
waiters.forEach { continuation in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
deinit { deinit {
self.udpHole = nil self.udpHole = nil
self.udpHoleLocalAddress = nil self.udpHoleLocalAddress = nil
@ -843,7 +763,6 @@ extension SDLContextActor {
self.superRegistrationStateMachine.handleFailure() self.superRegistrationStateMachine.handleFailure()
SDLLogger.log("[SDLContext] registerSuperAck invalid key") SDLLogger.log("[SDLContext] registerSuperAck invalid key")
let error = SDLError.invalidKey let error = SDLError.invalidKey
self.failReady(error)
self.provider.cancelTunnelWithError(error) self.provider.cancelTunnelWithError(error)
return return
} }
@ -861,7 +780,6 @@ extension SDLContextActor {
self.superRegistrationStateMachine.handleFailure() self.superRegistrationStateMachine.handleFailure()
SDLLogger.log("[SDLContext] registerSuperAck invalid algorithm \(algorithm)") SDLLogger.log("[SDLContext] registerSuperAck invalid algorithm \(algorithm)")
let error = SDLError.unsupportedAlgorithm(algorithm: algorithm) let error = SDLError.unsupportedAlgorithm(algorithm: algorithm)
self.failReady(error)
self.provider.cancelTunnelWithError(error) self.provider.cancelTunnelWithError(error)
return return
} }
@ -873,12 +791,14 @@ extension SDLContextActor {
SDLLogger.log("[SDLContext] setNetworkSettings successed") SDLLogger.log("[SDLContext] setNetworkSettings successed")
self.superRegistrationStateMachine.handleRegisterSuperAck() self.superRegistrationStateMachine.handleRegisterSuperAck()
self.startReader() self.startReader()
self.markReady() self.eventContinuation.yield(.ready)
self.eventContinuation.finish()
} catch let err { } catch let err {
self.superRegistrationStateMachine.handleFailure() self.superRegistrationStateMachine.handleFailure()
SDLLogger.log("[SDLContext] setTunnelNetworkSettings get error: \(err)") SDLLogger.log("[SDLContext] setTunnelNetworkSettings get error: \(err)")
self.failReady(err)
self.provider.cancelTunnelWithError(err) self.provider.cancelTunnelWithError(err)
self.eventContinuation.yield(.failed(err))
self.eventContinuation.finish()
} }
} }
@ -894,7 +814,6 @@ extension SDLContextActor {
self.publishTunnelEvent(code: Int(errorCode.rawValue), message: errorMessage) self.publishTunnelEvent(code: Int(errorCode.rawValue), message: errorMessage)
// 退 // 退
let error = NSError(domain: "com.jihe.punchnet.tun", code: -1) let error = NSError(domain: "com.jihe.punchnet.tun", code: -1)
self.failReady(error)
self.provider.cancelTunnelWithError(error) self.provider.cancelTunnelWithError(error)
case .noIpAddress, .networkFault, .internalFault: case .noIpAddress, .networkFault, .internalFault:
@ -924,7 +843,6 @@ extension SDLContextActor {
// 退 // 退
let error = NSError(domain: "com.jihe.punchnet.tun", code: -2) let error = NSError(domain: "com.jihe.punchnet.tun", code: -2)
self.failReady(error)
self.provider.cancelTunnelWithError(error) self.provider.cancelTunnelWithError(error)
case .none: case .none:
() ()