mirror of
https://github.com/StikDebug/StikDebug.git
synced 2026-10-16 04:20:30 +00:00
Merge 61542ce0f6 into 300ebff50b
This commit is contained in:
commit
231cb884ed
5 changed files with 122 additions and 4 deletions
|
|
@ -791,7 +791,7 @@ func simulate_location(_ deviceIP: String, _ latitude: Double, _ longitude: Doub
|
|||
|
||||
var address = sockaddr_in()
|
||||
address.sin_family = sa_family_t(AF_INET)
|
||||
address.sin_port = in_port_t(49152).bigEndian
|
||||
address.sin_port = in_port_t(RemotePairingPortResolver.resolve()).bigEndian
|
||||
|
||||
let inetResult = deviceIP.withCString { inet_pton(AF_INET, $0, &address.sin_addr) }
|
||||
guard inetResult == 1 else {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,99 @@ import Foundation
|
|||
import idevice
|
||||
import Darwin
|
||||
|
||||
final class RemotePairingPortResolver: NSObject, NetServiceBrowserDelegate, NetServiceDelegate {
|
||||
static let fallback: UInt16 = 49152
|
||||
private static let overrideKey = "TunnelRemotePairingPort"
|
||||
private static let stateLock = NSLock()
|
||||
private static var selectedEndpoint = "Not attempted yet"
|
||||
|
||||
/// The precise port and discovery method used for the latest connection attempt.
|
||||
static var lastAttemptDescription: String {
|
||||
stateLock.lock()
|
||||
defer { stateLock.unlock() }
|
||||
return selectedEndpoint
|
||||
}
|
||||
|
||||
private static func record(port: UInt16, source: String) {
|
||||
let endpoint = "\(DeviceConnectionContext.targetIPAddress):\(port) [\(source)]"
|
||||
stateLock.lock()
|
||||
selectedEndpoint = endpoint
|
||||
stateLock.unlock()
|
||||
NSLog("[StikDebug] Remote Pairing selected endpoint: %@", endpoint)
|
||||
}
|
||||
|
||||
private let browser = NetServiceBrowser()
|
||||
private var services: [NetService] = []
|
||||
private var resolvedPort: UInt16?
|
||||
private var resolvedServiceName: String?
|
||||
private var discoveryError: String?
|
||||
|
||||
/// Resolve on a worker thread with an active run loop. An explicit Settings
|
||||
/// override takes precedence when multicast DNS cannot see the local service.
|
||||
static func resolve(timeout: TimeInterval = 5) -> UInt16 {
|
||||
let override = (UserDefaults.standard.string(forKey: overrideKey) ?? "")
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !override.isEmpty, let port = UInt16(override), port != 0 {
|
||||
record(port: port, source: "manual override")
|
||||
return port
|
||||
}
|
||||
if !override.isEmpty {
|
||||
NSLog("[StikDebug] Ignoring invalid manual Remote Pairing port: %@", override)
|
||||
}
|
||||
|
||||
let worker = RemotePairingPortResolver()
|
||||
let completion = DispatchSemaphore(value: 0)
|
||||
DispatchQueue.global(qos: .utility).async {
|
||||
worker.search(timeout: timeout)
|
||||
completion.signal()
|
||||
}
|
||||
guard completion.wait(timeout: .now() + timeout + 1) == .success else {
|
||||
record(port: fallback, source: "Bonjour timeout; fallback")
|
||||
return fallback
|
||||
}
|
||||
if let port = worker.resolvedPort {
|
||||
record(port: port, source: "Bonjour: \(worker.resolvedServiceName ?? "unknown service")")
|
||||
return port
|
||||
}
|
||||
let detail = worker.discoveryError ?? "no _remotepairing._tcp service resolved"
|
||||
record(port: fallback, source: "Bonjour unavailable (\(detail)); fallback")
|
||||
return fallback
|
||||
}
|
||||
|
||||
private func search(timeout: TimeInterval) {
|
||||
browser.delegate = self
|
||||
browser.schedule(in: .current, forMode: .default)
|
||||
browser.searchForServices(ofType: "_remotepairing._tcp.", inDomain: "local.")
|
||||
let deadline = Date().addingTimeInterval(timeout)
|
||||
while resolvedPort == nil && Date() < deadline {
|
||||
_ = RunLoop.current.run(mode: .default, before: Date().addingTimeInterval(0.1))
|
||||
}
|
||||
browser.stop()
|
||||
services.forEach { $0.stop() }
|
||||
}
|
||||
|
||||
func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
|
||||
services.append(service)
|
||||
service.delegate = self
|
||||
service.resolve(withTimeout: 4)
|
||||
}
|
||||
|
||||
func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String: NSNumber]) {
|
||||
discoveryError = "browser error \(errorDict)"
|
||||
}
|
||||
|
||||
func netService(_ sender: NetService, didNotResolve errorDict: [String: NSNumber]) {
|
||||
discoveryError = "service \(sender.name): \(errorDict)"
|
||||
}
|
||||
|
||||
func netServiceDidResolveAddress(_ sender: NetService) {
|
||||
if (1...65535).contains(sender.port), resolvedPort == nil {
|
||||
resolvedPort = UInt16(sender.port)
|
||||
resolvedServiceName = sender.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typealias LogFunc = (String?) -> Void
|
||||
typealias DebugAppCallback = (_ pid: Int32, _ debugProxy: OpaquePointer?, _ remoteServer: OpaquePointer?, _ semaphore: DispatchSemaphore) -> Void
|
||||
typealias SyslogLineHandler = (String) -> Void
|
||||
|
|
@ -169,7 +262,8 @@ final class JITEnableContext {
|
|||
|
||||
var addr = sockaddr_in()
|
||||
addr.sin_family = sa_family_t(AF_INET)
|
||||
addr.sin_port = in_port_t(49152).bigEndian
|
||||
let remotePairingPort = RemotePairingPortResolver.resolve()
|
||||
addr.sin_port = in_port_t(remotePairingPort).bigEndian
|
||||
|
||||
let deviceIP = DeviceConnectionContext.targetIPAddress
|
||||
let parseResult = deviceIP.withCString { inet_pton(AF_INET, $0, &addr.sin_addr) }
|
||||
|
|
|
|||
|
|
@ -16,8 +16,11 @@
|
|||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>StikDebug discovers this iPhone's Remote Pairing service to enable JIT.</string>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_remotepairing._tcp</string>
|
||||
<string>_stikdebug._tcp</string>
|
||||
<string>_stikdebug._udp</string>
|
||||
</array>
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ func markTunnelDisconnected() {
|
|||
}
|
||||
|
||||
private func tunnelConnectionLogMessage(for error: NSError) -> String {
|
||||
let target = "\(DeviceConnectionContext.targetIPAddress):49152"
|
||||
let target = RemotePairingPortResolver.lastAttemptDescription
|
||||
return "Tunnel connection failed for \(target): \(error.localizedDescription) (Domain: \(error.domain), Code: \(error.code), Raw: \(String(describing: error)))"
|
||||
}
|
||||
|
||||
|
|
@ -157,6 +157,14 @@ private func tunnelConnectionAlertMessage(for error: NSError) -> String {
|
|||
"Reconnect Wi-Fi and LocalDevVPN, then try again.",
|
||||
"If this keeps happening, select a fresh pairing file."
|
||||
]
|
||||
} else if error.code == 16 || lowercasedMessage.contains("device socket io failed") {
|
||||
likelyCause = "The Remote Pairing tunnel could not connect to the selected endpoint."
|
||||
recoverySteps = [
|
||||
"Check the Target attempted line below (including whether Bonjour or fallback selected the port).",
|
||||
"In SideStore Network Discovery, find the _remotepairing._tcp service port.",
|
||||
"If it differs, set Settings > Advanced > Remote Pairing Port to SideStore's discovered port, then reconnect.",
|
||||
"If the addresses and ports already match, check LocalDevVPN routing and the pairing file."
|
||||
]
|
||||
} else if error.code == -18 || lowercasedMessage.contains("parse target ip") {
|
||||
likelyCause = "The configured target IP address is not valid."
|
||||
recoverySteps = [
|
||||
|
|
@ -193,7 +201,7 @@ private func tunnelConnectionAlertMessage(for error: NSError) -> String {
|
|||
return """
|
||||
\(likelyCause)
|
||||
|
||||
Target: \(targetIP):49152
|
||||
Target attempted: \(RemotePairingPortResolver.lastAttemptDescription)
|
||||
Expected LocalDevVPN IP: \(DeviceConnectionContext.defaultTargetIPAddress)
|
||||
|
||||
Try this:
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ struct SettingsView: View {
|
|||
@AppStorage("keepAliveAudio") private var keepAliveAudio = true
|
||||
@AppStorage("keepAliveLocation") private var keepAliveLocation = true
|
||||
@AppStorage(UserDefaults.Keys.targetDeviceIP) private var targetDeviceIP = DeviceConnectionContext.defaultTargetIPAddress
|
||||
@AppStorage("TunnelRemotePairingPort") private var remotePairingPortOverride = ""
|
||||
@AppStorage(UserDefaults.Keys.mallocDebug) private var mallocDebug = false
|
||||
|
||||
@State private var isShowingPairingFilePicker = false
|
||||
|
|
@ -153,6 +154,18 @@ struct SettingsView: View {
|
|||
.keyboardType(.numbersAndPunctuation)
|
||||
.frame(maxWidth: 160)
|
||||
}
|
||||
HStack {
|
||||
Text("Remote Pairing Port")
|
||||
Spacer()
|
||||
TextField("Auto (Bonjour)", text: $remotePairingPortOverride)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.foregroundStyle(.secondary)
|
||||
.keyboardType(.numberPad)
|
||||
.frame(maxWidth: 160)
|
||||
}
|
||||
Text("Leave blank for automatic discovery. Use the port reported by SideStore Network Discovery if Bonjour fails. Restart the tunnel after changing this value.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
Button { openAppFolder() } label: {
|
||||
Label("App Folder", systemImage: "folder")
|
||||
}.foregroundStyle(.primary)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue