From 24fc27f422940a5b0d5b2fef658ad9d0e958a058 Mon Sep 17 00:00:00 2001 From: Andrej Mihajlov Date: Wed, 4 Oct 2023 14:29:58 +0200 Subject: [PATCH] PacketTunnelCore: Introduce SelectedRelay and remove dependency on RelaySelector module Also: - IPC: accept NextRelay in "reconnect" message --- ios/MullvadVPN.xcodeproj/project.pbxproj | 19 ---------- .../SimulatorTunnelProviderHost.swift | 37 ++++++++++++------- .../TunnelManager/StartTunnelOperation.swift | 16 ++++---- .../TunnelManager/Tunnel+Messaging.swift | 8 ++-- .../TunnelManager/TunnelInteractor.swift | 5 +-- .../TunnelManager/TunnelManager.swift | 17 ++++++--- .../AppMessageHandler.swift | 4 +- .../PacketTunnelProvider.swift | 4 +- .../RelaySelectorWrapper.swift | 10 ++++- ios/PacketTunnelCore/Actor/Actor.swift | 16 +++++--- ios/PacketTunnelCore/Actor/Command.swift | 2 +- .../Protocols/RelaySelectorProtocol.swift | 35 ++++++++++++++++-- ios/PacketTunnelCore/Actor/StartOptions.swift | 11 +++--- .../Actor/State+Extensions.swift | 2 +- ios/PacketTunnelCore/Actor/State.swift | 6 +-- .../IPC/PacketTunnelOptions.swift | 16 ++++---- ...elaySelectorResult+PacketTunnelRelay.swift | 21 ----------- .../IPC/TunnelProviderMessage.swift | 4 +- .../Mocks/RelaySelectorStub.swift | 30 ++++++--------- 19 files changed, 134 insertions(+), 129 deletions(-) delete mode 100644 ios/PacketTunnelCore/IPC/RelaySelectorResult+PacketTunnelRelay.swift diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 7a8db6966edd..615d9919d29d 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -286,7 +286,6 @@ 58C7AF112ABD8480007EDD7A /* TunnelProviderMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA89226B0323E00B8C587 /* TunnelProviderMessage.swift */; }; 58C7AF122ABD8480007EDD7A /* TunnelProviderReply.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5898D2A7290182B000EB5EBA /* TunnelProviderReply.swift */; }; 58C7AF132ABD8480007EDD7A /* PacketTunnelStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA89826B0329200B8C587 /* PacketTunnelStatus.swift */; }; - 58C7AF142ABD8480007EDD7A /* RelaySelectorResult+PacketTunnelRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C9B8CC2ABB247700040B46 /* RelaySelectorResult+PacketTunnelRelay.swift */; }; 58C7AF152ABD8480007EDD7A /* PacketTunnelRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5898D2B62902A9EA00EB5EBA /* PacketTunnelRelay.swift */; }; 58C7AF162ABD84A8007EDD7A /* URLRequestProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D229B6298D1D5200BB5A2D /* URLRequestProxy.swift */; }; 58C7AF172ABD84AA007EDD7A /* ProxyURLRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 063687AF28EB083800BE7161 /* ProxyURLRequest.swift */; }; @@ -414,7 +413,6 @@ 58FE25BF2AA72311003D1918 /* MigrationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D96B192A8247C100A5C673 /* MigrationManager.swift */; }; 58FE25C22AA72729003D1918 /* MullvadREST.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06799ABC28F98E1D00ACD94E /* MullvadREST.framework */; }; 58FE25C62AA72779003D1918 /* PacketTunnelCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58C7A4362A863F440060C66F /* PacketTunnelCore.framework */; }; - 58FE25CB2AA727A9003D1918 /* libRelaySelector.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5898D29829017DAC00EB5EBA /* libRelaySelector.a */; }; 58FE25CE2AA72802003D1918 /* MullvadSettings.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58B2FDD32AA71D2A003EB5C6 /* MullvadSettings.framework */; }; 58FE25D42AA729B5003D1918 /* ActorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FE25D32AA729B5003D1918 /* ActorTests.swift */; }; 58FE25D72AA72A8F003D1918 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5824030C2A811B0000163DE8 /* State.swift */; }; @@ -820,13 +818,6 @@ remoteGlobalIDString = 58C7A4352A863F440060C66F; remoteInfo = PacketTunnelCore; }; - 58FE25CC2AA727A9003D1918 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 58CE5E58224146200008646E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 5898D29729017DAC00EB5EBA; - remoteInfo = RelaySelector; - }; 58FE25D02AA72802003D1918 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 58CE5E58224146200008646E /* Project object */; @@ -1324,7 +1315,6 @@ 58C7A43D2A863F460060C66F /* PacketTunnelCoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PacketTunnelCoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58C7A46F2A8649ED0060C66F /* PingerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PingerTests.swift; sourceTree = ""; }; 58C8191729FAA2C400DEB1B4 /* NotificationConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationConfiguration.swift; sourceTree = ""; }; - 58C9B8CC2ABB247700040B46 /* RelaySelectorResult+PacketTunnelRelay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelaySelectorResult+PacketTunnelRelay.swift"; sourceTree = ""; }; 58CAF9F72983D36800BE19F7 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; 58CAF9FF2983FF0200BE19F7 /* LoginInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginInteractor.swift; sourceTree = ""; }; 58CAFA01298530DC00BE19F7 /* Promise.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Promise.swift; sourceTree = ""; }; @@ -1593,7 +1583,6 @@ buildActionMask = 2147483647; files = ( A94D691A2ABAD66700413DD4 /* WireGuardKitTypes in Frameworks */, - 58FE25CB2AA727A9003D1918 /* libRelaySelector.a in Frameworks */, 58C9B8DA2ABB271D00040B46 /* MullvadTransport.framework in Frameworks */, 58FE65952AB1D90600E53CB5 /* MullvadTypes.framework in Frameworks */, 58C7A45C2A8640490060C66F /* MullvadLogging.framework in Frameworks */, @@ -2454,7 +2443,6 @@ 587C575226D2615F005EF767 /* PacketTunnelOptions.swift */, 5898D2B62902A9EA00EB5EBA /* PacketTunnelRelay.swift */, 585DA89826B0329200B8C587 /* PacketTunnelStatus.swift */, - 58C9B8CC2ABB247700040B46 /* RelaySelectorResult+PacketTunnelRelay.swift */, 585DA89226B0323E00B8C587 /* TunnelProviderMessage.swift */, 5898D2A7290182B000EB5EBA /* TunnelProviderReply.swift */, ); @@ -3160,7 +3148,6 @@ ); dependencies = ( 58C7A45F2A8640490060C66F /* PBXTargetDependency */, - 58FE25CD2AA727A9003D1918 /* PBXTargetDependency */, 58FE65982AB1D90600E53CB5 /* PBXTargetDependency */, 58C9B8DD2ABB271D00040B46 /* PBXTargetDependency */, ); @@ -3934,7 +3921,6 @@ 58C7A4522A863FB50060C66F /* Pinger.swift in Sources */, 580D6B8C2AB3369300B2D6E0 /* BlockedStateErrorMapperProtocol.swift in Sources */, 58C7AF172ABD84AA007EDD7A /* ProxyURLRequest.swift in Sources */, - 58C7AF142ABD8480007EDD7A /* RelaySelectorResult+PacketTunnelRelay.swift in Sources */, 5838321F2AC3160A00EA2071 /* Actor+KeyPolicy.swift in Sources */, 58C7AF122ABD8480007EDD7A /* TunnelProviderReply.swift in Sources */, 58C7A4572A863FB90060C66F /* TunnelDeviceInfoProtocol.swift in Sources */, @@ -4587,11 +4573,6 @@ target = 58C7A4352A863F440060C66F /* PacketTunnelCore */; targetProxy = 58FE25C82AA72779003D1918 /* PBXContainerItemProxy */; }; - 58FE25CD2AA727A9003D1918 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 5898D29729017DAC00EB5EBA /* RelaySelector */; - targetProxy = 58FE25CC2AA727A9003D1918 /* PBXContainerItemProxy */; - }; 58FE25D12AA72802003D1918 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 58B2FDD22AA71D2A003EB5C6 /* MullvadSettings */; diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift index 39cd909202d2..d09a3e94ab3a 100644 --- a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift +++ b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift @@ -20,7 +20,7 @@ import RelayCache import RelaySelector final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { - private var selectorResult: RelaySelectorResult? + private var selectedRelay: SelectedRelay? private let urlRequestProxy: URLRequestProxy private let relayCacheTracker: RelayCacheTracker @@ -40,24 +40,24 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { completionHandler: @escaping (Error?) -> Void ) { dispatchQueue.async { - var selectorResult: RelaySelectorResult? + var selectedRelay: SelectedRelay? do { let tunnelOptions = PacketTunnelOptions(rawOptions: options ?? [:]) - selectorResult = try tunnelOptions.getSelectorResult() + selectedRelay = try tunnelOptions.getSelectedRelay() } catch { self.providerLogger.error( error: error, message: """ - Failed to decode relay selector result passed from the app. \ + Failed to decode selected relay passed from the app. \ Will continue by picking new relay. """ ) } do { - self.selectorResult = try selectorResult ?? self.pickRelay() + self.selectedRelay = try selectedRelay ?? self.pickRelay() completionHandler(nil) } catch { @@ -72,7 +72,7 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { dispatchQueue.async { - self.selectorResult = nil + self.selectedRelay = nil completionHandler() } @@ -99,7 +99,7 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { switch message { case .getTunnelStatus: var tunnelStatus = PacketTunnelStatus() - tunnelStatus.tunnelRelay = self.selectorResult?.packetTunnelRelay + tunnelStatus.tunnelRelay = self.selectedRelay?.packetTunnelRelay var reply: Data? do { @@ -113,10 +113,17 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { completionHandler?(reply) - case let .reconnectTunnel(aSelectorResult): + case let .reconnectTunnel(nextRelay): reasserting = true - if let aSelectorResult { - selectorResult = aSelectorResult + switch nextRelay { + case let .preSelected(selectedRelay): + self.selectedRelay = selectedRelay + case .random: + if let nextRelay = try? pickRelay() { + self.selectedRelay = nextRelay + } + case .current: + break } reasserting = false completionHandler?(nil) @@ -145,15 +152,19 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { } } - private func pickRelay() throws -> RelaySelectorResult { + private func pickRelay() throws -> SelectedRelay { let cachedRelays = try relayCacheTracker.getCachedRelays() let tunnelSettings = try SettingsManager.readSettings() - - return try RelaySelector.evaluate( + let selectorResult = try RelaySelector.evaluate( relays: cachedRelays.relays, constraints: tunnelSettings.relayConstraints, numberOfFailedAttempts: 0 ) + return SelectedRelay( + endpoint: selectorResult.endpoint, + hostname: selectorResult.relay.hostname, + location: selectorResult.location + ) } } diff --git a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift index 9404d02cde4f..afba76a88790 100644 --- a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift +++ b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift @@ -51,9 +51,9 @@ class StartTunnelOperation: ResultOperation { case .disconnected, .pendingReconnect: do { - let selectorResult = try interactor.selectRelay() + let selectedRelay = try interactor.selectRelay() - makeTunnelProviderAndStartTunnel(selectorResult: selectorResult) { error in + makeTunnelProviderAndStartTunnel(selectedRelay: selectedRelay) { error in self.finish(result: error.map { .failure($0) } ?? .success(())) } } catch { @@ -66,7 +66,7 @@ class StartTunnelOperation: ResultOperation { } private func makeTunnelProviderAndStartTunnel( - selectorResult: RelaySelectorResult, + selectedRelay: SelectedRelay, completionHandler: @escaping (Error?) -> Void ) { makeTunnelProvider { result in @@ -74,7 +74,7 @@ class StartTunnelOperation: ResultOperation { do { try self.startTunnel( tunnel: try result.get(), - selectorResult: selectorResult + selectedRelay: selectedRelay ) completionHandler(nil) @@ -85,11 +85,11 @@ class StartTunnelOperation: ResultOperation { } } - private func startTunnel(tunnel: Tunnel, selectorResult: RelaySelectorResult) throws { + private func startTunnel(tunnel: Tunnel, selectedRelay: SelectedRelay) throws { var tunnelOptions = PacketTunnelOptions() do { - try tunnelOptions.setSelectorResult(selectorResult) + try tunnelOptions.setSelectedRelay(selectedRelay) } catch { logger.error( error: error, @@ -101,8 +101,8 @@ class StartTunnelOperation: ResultOperation { interactor.updateTunnelStatus { tunnelStatus in tunnelStatus = TunnelStatus() - tunnelStatus.packetTunnelStatus.tunnelRelay = selectorResult.packetTunnelRelay - tunnelStatus.state = .connecting(selectorResult.packetTunnelRelay) + tunnelStatus.packetTunnelStatus.tunnelRelay = selectedRelay.packetTunnelRelay + tunnelStatus.state = .connecting(selectedRelay.packetTunnelRelay) } try tunnel.start(options: tunnelOptions.rawOptions()) diff --git a/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift b/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift index ff5704428b13..d40136159646 100644 --- a/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift +++ b/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift @@ -23,17 +23,17 @@ private let dispatchQueue = DispatchQueue(label: "Tunnel.dispatchQueue") private let proxyRequestTimeout = REST.defaultAPINetworkTimeout + 2 extension Tunnel { - /// Request packet tunnel process to reconnect the tunnel with the given relay selector result. - /// Packet tunnel will reconnect to the current relay if relay selector result is not provided. + /// Request packet tunnel process to reconnect the tunnel with the given relay. + /// Packet tunnel will reconnect to the current relay if relay is not provided. func reconnectTunnel( - relaySelectorResult: RelaySelectorResult?, + to nextRelay: NextRelay, completionHandler: @escaping (Result) -> Void ) -> Cancellable { let operation = SendTunnelProviderMessageOperation( dispatchQueue: dispatchQueue, application: .shared, tunnel: self, - message: .reconnectTunnel(relaySelectorResult), + message: .reconnectTunnel(nextRelay), completionHandler: completionHandler ) diff --git a/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift b/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift index d5f9d9ae8bce..26f40bc0d4f0 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift @@ -8,8 +8,7 @@ import Foundation import MullvadSettings -import RelayCache -import RelaySelector +import PacketTunnelCore protocol TunnelInteractor { // MARK: - Tunnel manipulation @@ -38,5 +37,5 @@ protocol TunnelInteractor { func startTunnel() func prepareForVPNConfigurationDeletion() - func selectRelay() throws -> RelaySelectorResult + func selectRelay() throws -> SelectedRelay } diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index 1f27c66395de..34cfca0d1aae 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -283,9 +283,9 @@ final class TunnelManager: StorePaymentObserver { throw UnsetTunnelError() } - let selectorResult = selectNewRelay ? try self.selectRelay() : nil + let nextRelay: NextRelay = selectNewRelay ? .preSelected(try self.selectRelay()) : .current - return tunnel.reconnectTunnel(relaySelectorResult: selectorResult) { result in + return tunnel.reconnectTunnel(to: nextRelay) { result in finish(result.error) } } catch { @@ -819,14 +819,19 @@ final class TunnelManager: StorePaymentObserver { updateTunnelStatus(tunnel?.status ?? .disconnected) } - fileprivate func selectRelay() throws -> RelaySelectorResult { + fileprivate func selectRelay() throws -> SelectedRelay { let cachedRelays = try relayCacheTracker.getCachedRelays() - - return try RelaySelector.evaluate( + let selectorResult = try RelaySelector.evaluate( relays: cachedRelays.relays, constraints: settings.relayConstraints, numberOfFailedAttempts: tunnelStatus.packetTunnelStatus.numberOfFailedAttempts ) + + return SelectedRelay( + endpoint: selectorResult.endpoint, + hostname: selectorResult.relay.hostname, + location: selectorResult.location + ) } fileprivate func prepareForVPNConfigurationDeletion() { @@ -1306,7 +1311,7 @@ private struct TunnelInteractorProxy: TunnelInteractor { tunnelManager.prepareForVPNConfigurationDeletion() } - func selectRelay() throws -> RelaySelectorResult { + func selectRelay() throws -> SelectedRelay { try tunnelManager.selectRelay() } diff --git a/ios/PacketTunnel/PacketTunnelProvider/AppMessageHandler.swift b/ios/PacketTunnel/PacketTunnelProvider/AppMessageHandler.swift index 952fcb4bdeb7..4071468799bc 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/AppMessageHandler.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/AppMessageHandler.swift @@ -54,8 +54,8 @@ struct AppMessageHandler { packetTunnelActor.notifyKeyRotation(date: nil) return nil - case let .reconnectTunnel(selectorResult): - packetTunnelActor.reconnect(to: selectorResult.map { .preSelected($0) } ?? .current) + case let .reconnectTunnel(nextRelay): + packetTunnelActor.reconnect(to: nextRelay) return nil } } diff --git a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift index 9c4e53c79df4..62c80284d797 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift @@ -168,9 +168,9 @@ extension PacketTunnelProvider { var parsedOptions = StartOptions(launchSource: tunnelOptions.isOnDemand() ? .onDemand : .app) do { - if let selectorResult = try tunnelOptions.getSelectorResult() { + if let selectedRelay = try tunnelOptions.getSelectedRelay() { parsedOptions.launchSource = .app - parsedOptions.selectorResult = selectorResult + parsedOptions.selectedRelay = selectedRelay } else if !tunnelOptions.isOnDemand() { parsedOptions.launchSource = .system } diff --git a/ios/PacketTunnel/PacketTunnelProvider/RelaySelectorWrapper.swift b/ios/PacketTunnel/PacketTunnelProvider/RelaySelectorWrapper.swift index 31e1e68f3cdc..eb5bd6dcee4c 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/RelaySelectorWrapper.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/RelaySelectorWrapper.swift @@ -18,11 +18,17 @@ struct RelaySelectorWrapper: RelaySelectorProtocol { func selectRelay( with constraints: RelayConstraints, connectionAttemptFailureCount: UInt - ) throws -> RelaySelectorResult { - try RelaySelector.evaluate( + ) throws -> SelectedRelay { + let selectorResult = try RelaySelector.evaluate( relays: relayCache.read().relays, constraints: constraints, numberOfFailedAttempts: connectionAttemptFailureCount ) + + return SelectedRelay( + endpoint: selectorResult.endpoint, + hostname: selectorResult.relay.hostname, + location: selectorResult.location + ) } } diff --git a/ios/PacketTunnelCore/Actor/Actor.swift b/ios/PacketTunnelCore/Actor/Actor.swift index 18be2e2d409e..e0f63f2117a4 100644 --- a/ios/PacketTunnelCore/Actor/Actor.swift +++ b/ios/PacketTunnelCore/Actor/Actor.swift @@ -133,7 +133,7 @@ extension PacketTunnelActor { setTunnelMonitorEventHandler() do { - try await tryStart(nextRelay: options.selectorResult.map { .preSelected($0) } ?? .random) + try await tryStart(nextRelay: options.selectedRelay.map { .preSelected($0) } ?? .random) } catch { logger.error(error: error, message: "Failed to start the tunnel.") @@ -332,9 +332,9 @@ extension PacketTunnelActor { private func selectRelay( nextRelay: NextRelay, relayConstraints: RelayConstraints, - currentRelay: RelaySelectorResult?, + currentRelay: SelectedRelay?, connectionAttemptCount: UInt - ) throws -> RelaySelectorResult { + ) throws -> SelectedRelay { switch nextRelay { case .current: if let currentRelay { @@ -350,8 +350,14 @@ extension PacketTunnelActor { connectionAttemptFailureCount: connectionAttemptCount ) - case let .preSelected(selectorResult): - return selectorResult + case let .preSelected(selectedRelay): + return selectedRelay } } } + +extension RelaySelectorResult { + func asSelectedRelay() -> SelectedRelay { + return SelectedRelay(endpoint: endpoint, hostname: relay.hostname, location: location) + } +} diff --git a/ios/PacketTunnelCore/Actor/Command.swift b/ios/PacketTunnelCore/Actor/Command.swift index 43771e62afb4..d7cf121684aa 100644 --- a/ios/PacketTunnelCore/Actor/Command.swift +++ b/ios/PacketTunnelCore/Actor/Command.swift @@ -50,7 +50,7 @@ enum Command { case .random: return "reconnect(random, \(stopTunnelMonitor))" case let .preSelected(selectedRelay): - return "reconnect(\(selectedRelay.relay.hostname), \(stopTunnelMonitor))" + return "reconnect(\(selectedRelay.hostname), \(stopTunnelMonitor))" } case let .error(reason): return "error(\(reason))" diff --git a/ios/PacketTunnelCore/Actor/Protocols/RelaySelectorProtocol.swift b/ios/PacketTunnelCore/Actor/Protocols/RelaySelectorProtocol.swift index b856b2f1fe99..8127008a8f9a 100644 --- a/ios/PacketTunnelCore/Actor/Protocols/RelaySelectorProtocol.swift +++ b/ios/PacketTunnelCore/Actor/Protocols/RelaySelectorProtocol.swift @@ -8,10 +8,39 @@ import Foundation import MullvadTypes -import RelaySelector /// Protocol describing a type that can select a relay. public protocol RelaySelectorProtocol { - func selectRelay(with constraints: RelayConstraints, connectionAttemptFailureCount: UInt) throws - -> RelaySelectorResult + func selectRelay(with constraints: RelayConstraints, connectionAttemptFailureCount: UInt) throws -> SelectedRelay +} + +/// Struct describing the selected relay. +public struct SelectedRelay: Equatable, Codable { + /// Selected relay endpoint. + public var endpoint: MullvadEndpoint + + /// Relay hostname. + public var hostname: String + + /// Relay geo location. + public var location: Location + + /// Designated initializer. + public init(endpoint: MullvadEndpoint, hostname: String, location: Location) { + self.endpoint = endpoint + self.hostname = hostname + self.location = location + } +} + +extension SelectedRelay { + /// Converts `SelectedRelay` to `PacketTunnelRelay` for sharing with UI. + public var packetTunnelRelay: PacketTunnelRelay { + PacketTunnelRelay( + ipv4Relay: endpoint.ipv4Relay, + ipv6Relay: endpoint.ipv6Relay, + hostname: hostname, + location: location + ) + } } diff --git a/ios/PacketTunnelCore/Actor/StartOptions.swift b/ios/PacketTunnelCore/Actor/StartOptions.swift index d2ebe72611b3..9dd3ffeb6829 100644 --- a/ios/PacketTunnelCore/Actor/StartOptions.swift +++ b/ios/PacketTunnelCore/Actor/StartOptions.swift @@ -7,7 +7,6 @@ // import Foundation -import RelaySelector /// Packet tunnel start options parsed from dictionary passed to packet tunnel with a call to `startTunnel()`. public struct StartOptions { @@ -15,19 +14,19 @@ public struct StartOptions { public var launchSource: LaunchSource /// Pre-selected relay received from UI when available. - public var selectorResult: RelaySelectorResult? + public var selectedRelay: SelectedRelay? /// Designated initializer. - public init(launchSource: LaunchSource, selectorResult: RelaySelectorResult? = nil) { + public init(launchSource: LaunchSource, selectedRelay: SelectedRelay? = nil) { self.launchSource = launchSource - self.selectorResult = selectorResult + self.selectedRelay = selectedRelay } /// Returns a brief description suitable for output to tunnel provider log. public func logFormat() -> String { var s = "Start the tunnel via \(launchSource)" - if let selectorResult { - s += ", connect to \(selectorResult.relay.hostname)" + if let selectedRelay { + s += ", connect to \(selectedRelay.hostname)" } s += "." return s diff --git a/ios/PacketTunnelCore/Actor/State+Extensions.swift b/ios/PacketTunnelCore/Actor/State+Extensions.swift index cfaed6cf0787..71a090acb268 100644 --- a/ios/PacketTunnelCore/Actor/State+Extensions.swift +++ b/ios/PacketTunnelCore/Actor/State+Extensions.swift @@ -41,7 +41,7 @@ extension State { func logFormat() -> String { switch self { case let .connecting(connState), let .connected(connState), let .reconnecting(connState): - let hostname = connState.selectedRelay.relay.hostname + let hostname = connState.selectedRelay.hostname return """ \(name) to \(hostname), \ diff --git a/ios/PacketTunnelCore/Actor/State.swift b/ios/PacketTunnelCore/Actor/State.swift index 2c5cfd13b81f..3c92dbe20df5 100644 --- a/ios/PacketTunnelCore/Actor/State.swift +++ b/ios/PacketTunnelCore/Actor/State.swift @@ -100,7 +100,7 @@ public enum NetworkReachability: Equatable { /// Data associated with states that hold connection data. public struct ConnectionState { /// Current selected relay. - public var selectedRelay: RelaySelectorResult + public var selectedRelay: SelectedRelay /// Last relay constraints read from settings. /// This is primarily used by packet tunnel for updating constraints in tunnel provider. @@ -203,7 +203,7 @@ public enum TargetStateForReconnect { } /// Describes which relay the tunnel should connect to next. -public enum NextRelay: Equatable { +public enum NextRelay: Equatable, Codable { /// Select next relay randomly. case random @@ -211,5 +211,5 @@ public enum NextRelay: Equatable { case current /// Use pre-selected relay. - case preSelected(RelaySelectorResult) + case preSelected(SelectedRelay) } diff --git a/ios/PacketTunnelCore/IPC/PacketTunnelOptions.swift b/ios/PacketTunnelCore/IPC/PacketTunnelOptions.swift index 8290895294a6..bc46ad218963 100644 --- a/ios/PacketTunnelCore/IPC/PacketTunnelOptions.swift +++ b/ios/PacketTunnelCore/IPC/PacketTunnelOptions.swift @@ -7,15 +7,13 @@ // import Foundation -import RelaySelector public struct PacketTunnelOptions { /// Keys for options dictionary private enum Keys: String { - /// Option key that holds the `NSData` value with `RelaySelectorResult` - /// encoded using `JSONEncoder`. + /// Option key that holds serialized`SelectedRelay` value encoded using `JSONEncoder`. /// Used for passing the pre-selected relay in the GUI process to the Packet tunnel process. - case relaySelectorResult = "relay-selector-result" + case selectedRelay = "selected-relay" /// Option key that holds the `NSNumber` value, which is when set to `1` indicates that /// the tunnel was started by the system. @@ -37,14 +35,14 @@ public struct PacketTunnelOptions { _rawOptions = rawOptions } - public func getSelectorResult() throws -> RelaySelectorResult? { - guard let data = _rawOptions[Keys.relaySelectorResult.rawValue] as? Data else { return nil } + public func getSelectedRelay() throws -> SelectedRelay? { + guard let data = _rawOptions[Keys.selectedRelay.rawValue] as? Data else { return nil } - return try Self.decode(RelaySelectorResult.self, data) + return try Self.decode(SelectedRelay.self, data) } - public mutating func setSelectorResult(_ value: RelaySelectorResult) throws { - _rawOptions[Keys.relaySelectorResult.rawValue] = try Self.encode(value) as NSData + public mutating func setSelectedRelay(_ value: SelectedRelay) throws { + _rawOptions[Keys.selectedRelay.rawValue] = try Self.encode(value) as NSData } public func isOnDemand() -> Bool { diff --git a/ios/PacketTunnelCore/IPC/RelaySelectorResult+PacketTunnelRelay.swift b/ios/PacketTunnelCore/IPC/RelaySelectorResult+PacketTunnelRelay.swift deleted file mode 100644 index 4169f7bca814..000000000000 --- a/ios/PacketTunnelCore/IPC/RelaySelectorResult+PacketTunnelRelay.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// RelaySelectorResult+PacketTunnelRelay.swift -// PacketTunnelCore -// -// Created by pronebird on 20/09/2023. -// Copyright © 2023 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import RelaySelector - -extension RelaySelectorResult { - public var packetTunnelRelay: PacketTunnelRelay { - PacketTunnelRelay( - ipv4Relay: endpoint.ipv4Relay, - ipv6Relay: endpoint.ipv6Relay, - hostname: relay.hostname, - location: location - ) - } -} diff --git a/ios/PacketTunnelCore/IPC/TunnelProviderMessage.swift b/ios/PacketTunnelCore/IPC/TunnelProviderMessage.swift index 231c1cd858fd..70626744379e 100644 --- a/ios/PacketTunnelCore/IPC/TunnelProviderMessage.swift +++ b/ios/PacketTunnelCore/IPC/TunnelProviderMessage.swift @@ -7,13 +7,11 @@ // import Foundation -import RelaySelector /// Enum describing supported app messages handled by packet tunnel provider. public enum TunnelProviderMessage: Codable, CustomStringConvertible { /// Request the tunnel to reconnect. - /// The packet tunnel reconnects to the current relay when selector result is `nil`. - case reconnectTunnel(RelaySelectorResult?) + case reconnectTunnel(NextRelay) /// Request the tunnel status. case getTunnelStatus diff --git a/ios/PacketTunnelCoreTests/Mocks/RelaySelectorStub.swift b/ios/PacketTunnelCoreTests/Mocks/RelaySelectorStub.swift index 64f0c7472a3d..8c69404bdcb5 100644 --- a/ios/PacketTunnelCoreTests/Mocks/RelaySelectorStub.swift +++ b/ios/PacketTunnelCoreTests/Mocks/RelaySelectorStub.swift @@ -7,20 +7,18 @@ // import Foundation -@testable import MullvadREST import MullvadTypes import PacketTunnelCore -@testable import RelaySelector import class WireGuardKitTypes.PrivateKey /// Relay selector stub that accepts a block that can be used to provide custom implementation. struct RelaySelectorStub: RelaySelectorProtocol { - let block: (RelayConstraints, UInt) throws -> RelaySelectorResult + let block: (RelayConstraints, UInt) throws -> SelectedRelay func selectRelay( with constraints: RelayConstraints, connectionAttemptFailureCount: UInt - ) throws -> RelaySelectorResult { + ) throws -> SelectedRelay { return try block(constraints, connectionAttemptFailureCount) } } @@ -31,26 +29,22 @@ extension RelaySelectorStub { let publicKey = PrivateKey().publicKey.rawValue return RelaySelectorStub { _, _ in - return RelaySelectorResult( + return SelectedRelay( endpoint: MullvadEndpoint( ipv4Relay: IPv4Endpoint(ip: .loopback, port: 1300), ipv4Gateway: .loopback, ipv6Gateway: .loopback, publicKey: publicKey ), - relay: REST.ServerRelay( - hostname: "se-got", - active: true, - owned: true, - location: "se-got", - provider: "", - weight: 0, - ipv4AddrIn: .loopback, - ipv6AddrIn: .loopback, - publicKey: publicKey, - includeInCountry: true - ), - location: Location(country: "", countryCode: "se", city: "", cityCode: "got", latitude: 0, longitude: 0) + hostname: "se-got", + location: Location( + country: "", + countryCode: "se", + city: "", + cityCode: "got", + latitude: 0, + longitude: 0 + ) ) } }