Files
umbrix/ios/SingBoxPacketTunnel/SingBox/ExtensionProvider.swift

167 lines
5.1 KiB
Swift
Raw Normal View History

2023-10-17 03:15:15 +03:30
//
// ExtensionProvider.swift
// SingBoxPacketTunnel
//
// Created by GFWFighter on 7/25/1402 AP.
//
import Foundation
import Libcore
import NetworkExtension
open class ExtensionProvider: NEPacketTunnelProvider {
public static let errorFile = FilePath.workingDirectory.appendingPathComponent("network_extension_error")
private var commandServer: LibboxCommandServer!
private var boxService: LibboxBoxService!
private var systemProxyAvailable = false
private var systemProxyEnabled = false
private var platformInterface: ExtensionPlatformInterface!
private var config: String!
2023-10-24 18:29:53 +03:30
2023-10-17 03:15:15 +03:30
override open func startTunnel(options: [String: NSObject]?) async throws {
2023-10-24 18:29:53 +03:30
try? FileManager.default.removeItem(at: ExtensionProvider.errorFile)
try? FileManager.default.removeItem(at: FilePath.workingDirectory.appendingPathComponent("TestLog"))
2023-10-17 03:15:15 +03:30
let disableMemoryLimit = (options?["DisableMemoryLimit"] as? NSString as? String ?? "NO") == "YES"
guard let config = options?["Config"] as? NSString as? String else {
writeFatalError("(packet-tunnel) error: config not provided")
return
}
guard let config = SingBox.setupConfig(config: config) else {
writeFatalError("(packet-tunnel) error: config is invalid")
return
}
self.config = config
do {
try FileManager.default.createDirectory(at: FilePath.workingDirectory, withIntermediateDirectories: true)
} catch {
writeFatalError("(packet-tunnel) error: create working directory: \(error.localizedDescription)")
return
}
2023-10-24 18:29:53 +03:30
LibboxSetup(
FilePath.sharedDirectory.relativePath,
FilePath.workingDirectory.relativePath,
FilePath.cacheDirectory.relativePath,
false
)
2023-10-17 03:15:15 +03:30
var error: NSError?
LibboxRedirectStderr(FilePath.cacheDirectory.appendingPathComponent("stderr.log").relativePath, &error)
if let error {
writeError("(packet-tunnel) redirect stderr error: \(error.localizedDescription)")
}
LibboxSetMemoryLimit(!disableMemoryLimit)
if platformInterface == nil {
platformInterface = ExtensionPlatformInterface(self)
}
commandServer = LibboxNewCommandServer(platformInterface, Int32(30))
do {
try commandServer.start()
} catch {
writeFatalError("(packet-tunnel): log server start error: \(error.localizedDescription)")
return
}
writeMessage("(packet-tunnel) log server started")
await startService()
}
func writeMessage(_ message: String) {
if let commandServer {
commandServer.writeMessage(message)
} else {
NSLog(message)
}
}
func writeError(_ message: String) {
writeMessage(message)
try? message.write(to: ExtensionProvider.errorFile, atomically: true, encoding: .utf8)
}
public func writeFatalError(_ message: String) {
#if DEBUG
NSLog(message)
#endif
writeError(message)
cancelTunnelWithError(NSError(domain: message, code: 0))
}
private func startService() async {
let configContent = config
var error: NSError?
let service = LibboxNewService(configContent, platformInterface, &error)
if let error {
writeError("(packet-tunnel) error: create service: \(error.localizedDescription)")
return
}
guard let service else {
return
}
do {
try service.start()
} catch {
writeError("(packet-tunnel) error: start service: \(error.localizedDescription)")
return
}
boxService = service
commandServer.setService(service)
}
private func stopService() {
if let service = boxService {
do {
try service.close()
} catch {
writeError("(packet-tunnel) error: stop service: \(error.localizedDescription)")
}
boxService = nil
commandServer.setService(nil)
}
if let platformInterface {
platformInterface.reset()
}
}
func reloadService() async {
writeMessage("(packet-tunnel) reloading service")
reasserting = true
defer {
reasserting = false
}
stopService()
await startService()
}
override open func stopTunnel(with reason: NEProviderStopReason) async {
writeMessage("(packet-tunnel) stopping, reason: \(reason)")
stopService()
if let server = commandServer {
try? await Task.sleep(nanoseconds: 100 * NSEC_PER_MSEC)
try? server.close()
commandServer = nil
}
}
override open func handleAppMessage(_ messageData: Data) async -> Data? {
messageData
}
override open func sleep() async {
if let boxService {
boxService.sleep()
}
}
override open func wake() {
if let boxService {
boxService.wake()
}
}
}