Compare commits

..

2 Commits

Author SHA1 Message Date
e10329ba2a 修复休眠恢复的问题 2026-05-04 17:13:36 +08:00
d3f5d7388f 修复休眠恢复的问题 2026-05-03 21:27:20 +08:00
5 changed files with 146 additions and 108 deletions

View File

@ -5,6 +5,7 @@
// Created by on 2025/8/3.
//
import Foundation
import NetworkExtension
enum TunnelError: Error {
@ -22,28 +23,26 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return
}
guard let options else {
guard let options, let config = SDLConfiguration.parse(options: options) else {
completionHandler(TunnelError.invalidConfiguration)
return
}
self.runtimeEnv = SDLRuntimeEnvironment(options: options)
let rsaCipher = try! CCRSACipher(keySize: 1024)
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()
}))
}
}
@ -68,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
}
@ -128,37 +116,3 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
}
}
private class SDLRuntimeEnvironment {
var contextActor: SDLContextActor?
private var options: [String: NSObject]
init(options: [String: NSObject]) {
self.options = options
}
func start(provider: PacketTunnelProvider) async throws {
//
SDLTunnelAppNotifier.shared.clear()
guard let config = await SDLConfiguration.parse(options: options) else {
throw TunnelError.invalidConfiguration
}
//
let rsaCipher = try! CCRSACipher(keySize: 1024)
let contextActor = SDLContextActor(provider: provider, config: config, rsaCipher: rsaCipher)
self.contextActor = contextActor
await contextActor.start()
}
func getContextActor() -> SDLContextActor? {
return self.contextActor
}
func stop() async {
await self.contextActor?.stop()
self.contextActor = nil
}
}

View File

@ -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,6 +235,7 @@ actor SDLContextActor {
SDLLogger.log("[SDLContext] quic welcome: \(welcome)")
//
await self.doRegisterSuper()
SDLLogger.log("[SDLContext] quic doRegisterSuper")
//
self.registerTask = Task {
@ -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)
}
}
@ -323,7 +297,7 @@ actor SDLContextActor {
self.dnsWorker = nil
// dns
let dnsClient = DNSCloudClient(host: self.config.serverIp, port: 15353)
let dnsClient = DNSCloudClient(host: self.config.serverHost, port: 15353)
await dnsClient.start()
SDLLogger.log("[SDLContext] dnsClient started")
self.dnsClient = dnsClient
@ -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()
}

View File

@ -49,7 +49,6 @@ public class SDLConfiguration {
let version: Int
let serverHost: String
let serverIp: String
let stunServers: [String]
lazy var stunSocketAddress: SocketAddress = {
@ -77,7 +76,6 @@ public class SDLConfiguration {
public init(version: Int,
serverHost: String,
serverIp: String,
stunServers: [String],
clientId: String,
networkAddress: NetworkAddress,
@ -87,7 +85,6 @@ public class SDLConfiguration {
exitNode: ExitNode?) {
self.version = version
self.serverHost = serverHost
self.serverIp = serverIp
self.stunServers = stunServers
self.clientId = clientId
self.networkAddress = networkAddress
@ -102,7 +99,7 @@ public class SDLConfiguration {
//
extension SDLConfiguration {
static func parse(options: [String: NSObject]) async -> SDLConfiguration? {
static func parse(options: [String: NSObject]) -> SDLConfiguration? {
guard let version = options["version"] as? Int,
let serverHost = options["server_host"] as? String,
let stunAssistHost = options["stun_assist_host"] as? String,
@ -118,11 +115,6 @@ extension SDLConfiguration {
return nil
}
// dns
guard let serverIp = await SDLUtil.resolveHostname(host: serverHost) else {
return nil
}
//
var exitNode: ExitNode? = nil
if let exitNodeIpStr = options["exit_node_ip"] as? String, let exitNodeIp = SDLUtil.ipv4StrToInt32(exitNodeIpStr) {
@ -131,7 +123,6 @@ extension SDLConfiguration {
return SDLConfiguration(version: version,
serverHost: serverHost,
serverIp: serverIp,
stunServers: [serverHost, stunAssistHost],
clientId: clientId,
networkAddress: networkAddress,

View File

@ -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<SDLRuntimeEnvironmentCommand>
private let commandCont: AsyncStream<SDLRuntimeEnvironmentCommand>.Continuation
private var commandTask: Task<Void, Never>?
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()
}
}

View File

@ -7,6 +7,7 @@
import Foundation
import Observation
@MainActor
@Observable
final class NetworkModel {
@ObservationIgnored