diff --git a/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift b/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift index 2fe06dafe3dd..f2f8952df4f0 100644 --- a/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift +++ b/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift @@ -6,8 +6,8 @@ // Copyright © 2023 Mullvad VPN AB. All rights reserved. // -import MullvadTypes import MullvadREST +import MullvadTypes import WireGuardKitTypes /// Relay selector stub that accepts a block that can be used to provide custom implementation. diff --git a/ios/MullvadREST/Relay/RelaySelector+Wireguard.swift b/ios/MullvadREST/Relay/RelaySelector+Wireguard.swift index 382479ee2067..1e611569417c 100644 --- a/ios/MullvadREST/Relay/RelaySelector+Wireguard.swift +++ b/ios/MullvadREST/Relay/RelaySelector+Wireguard.swift @@ -10,7 +10,7 @@ import MullvadTypes extension RelaySelector { public enum WireGuard { - /// Filters relay list using given constraints and selects random relay for exit relay. + /// Filters relay list using given constraints. public static func findCandidates( by relayConstraint: RelayConstraint, in relays: REST.ServerRelaysResponse, @@ -25,7 +25,7 @@ extension RelaySelector { ) } - // TODO: Add comment. + /// Picks a random relay from a list. public static func pickCandidate( from relayWithLocations: [RelayWithLocation], relays: REST.ServerRelaysResponse, diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift index bc3ce91307aa..08b49d4b0585 100644 --- a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift +++ b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift @@ -18,7 +18,7 @@ import PacketTunnelCore final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { private var observedState: ObservedState = .disconnected - private var selectedRelay: SelectedRelay? + private var selectedRelays: SelectedRelays? private let urlRequestProxy: URLRequestProxy private let relaySelector: RelaySelectorProtocol @@ -43,12 +43,12 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { return } - var selectedRelay: SelectedRelay? + var selectedRelays: SelectedRelays? do { let tunnelOptions = PacketTunnelOptions(rawOptions: options ?? [:]) - selectedRelay = try tunnelOptions.getSelectedRelay() + selectedRelays = try tunnelOptions.getSelectedRelays() } catch { providerLogger.error( error: error, @@ -60,7 +60,7 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { } do { - setInternalStateConnected(with: try selectedRelay ?? pickRelay()) + setInternalStateConnected(with: try selectedRelays ?? pickRelays()) completionHandler(nil) } catch { providerLogger.error( @@ -74,7 +74,7 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { dispatchQueue.async { [weak self] in - self?.selectedRelay = nil + self?.selectedRelays = nil self?.observedState = .disconnected completionHandler() @@ -117,17 +117,17 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { reasserting = true switch nextRelay { - case let .preSelected(selectedRelay): - self.selectedRelay = selectedRelay + case let .preSelected(selectedRelays): + self.selectedRelays = selectedRelays case .random: - if let nextRelay = try? pickRelay() { - self.selectedRelay = nextRelay + if let nextRelays = try? pickRelays() { + self.selectedRelays = nextRelays } case .current: break } - setInternalStateConnected(with: selectedRelay) + setInternalStateConnected(with: selectedRelays) reasserting = false completionHandler?(nil) @@ -156,28 +156,28 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { } } - private func pickRelay() throws -> SelectedRelay { + private func pickRelays() throws -> SelectedRelays { let tunnelSettings = try SettingsManager.readSettings() return try relaySelector.selectRelays( with: tunnelSettings.relayConstraints, connectionAttemptCount: 0 - ).exit // TODO: Multihop + ) } - private func setInternalStateConnected(with selectedRelay: SelectedRelay?) { - guard let selectedRelay = selectedRelay else { return } + private func setInternalStateConnected(with selectedRelays: SelectedRelays?) { + guard let selectedRelays = selectedRelays else { return } do { let settings = try SettingsManager.readSettings() observedState = .connected( ObservedConnectionState( - selectedRelay: selectedRelay, + selectedRelays: selectedRelays, relayConstraints: settings.relayConstraints, networkReachability: .reachable, connectionAttemptCount: 0, transportLayer: .udp, - remotePort: selectedRelay.endpoint.ipv4Relay.port, + remotePort: selectedRelays.exit.endpoint.ipv4Relay.port, // TODO: Multihop isPostQuantum: settings.tunnelQuantumResistance.isEnabled ) ) diff --git a/ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift b/ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift index 4957af7c52ec..b605b85b476d 100644 --- a/ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift +++ b/ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift @@ -51,19 +51,19 @@ class MapConnectionStatusOperation: AsyncOperation { switch observedState { case let .connected(connectionState): return connectionState.isNetworkReachable - ? .connected(connectionState.selectedRelay, isPostQuantum: connectionState.isPostQuantum) + ? .connected(connectionState.selectedRelays, isPostQuantum: connectionState.isPostQuantum) : .waitingForConnectivity(.noConnection) case let .connecting(connectionState): return connectionState.isNetworkReachable - ? .connecting(connectionState.selectedRelay, isPostQuantum: connectionState.isPostQuantum) + ? .connecting(connectionState.selectedRelays, isPostQuantum: connectionState.isPostQuantum) : .waitingForConnectivity(.noConnection) case let .negotiatingPostQuantumKey(connectionState, privateKey): return connectionState.isNetworkReachable - ? .negotiatingPostQuantumKey(connectionState.selectedRelay, privateKey) + ? .negotiatingPostQuantumKey(connectionState.selectedRelays, privateKey) : .waitingForConnectivity(.noConnection) case let .reconnecting(connectionState): return connectionState.isNetworkReachable - ? .reconnecting(connectionState.selectedRelay, isPostQuantum: connectionState.isPostQuantum) + ? .reconnecting(connectionState.selectedRelays, isPostQuantum: connectionState.isPostQuantum) : .waitingForConnectivity(.noConnection) case let .error(blockedState): return .error(blockedState.reason) diff --git a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift index cd9e8b7a88c5..bb125db5abd1 100644 --- a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift +++ b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift @@ -72,12 +72,12 @@ class StartTunnelOperation: ResultOperation { } private func startTunnel(tunnel: any TunnelProtocol) throws { - let selectedRelay = try? interactor.selectRelay() + let selectedRelays = try? interactor.selectRelays() var tunnelOptions = PacketTunnelOptions() do { - if let selectedRelay { - try tunnelOptions.setSelectedRelay(selectedRelay) + if let selectedRelays { + try tunnelOptions.setSelectedRelays(selectedRelays) } } catch { logger.error( @@ -91,7 +91,7 @@ class StartTunnelOperation: ResultOperation { interactor.updateTunnelStatus { tunnelStatus in tunnelStatus = TunnelStatus() tunnelStatus.state = .connecting( - selectedRelay, + selectedRelays, isPostQuantum: interactor.settings.tunnelQuantumResistance.isEnabled ) } diff --git a/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift b/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift index 5299a281cc8d..04a231c5c497 100644 --- a/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift +++ b/ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift @@ -22,16 +22,16 @@ private let dispatchQueue = DispatchQueue(label: "Tunnel.dispatchQueue") private let proxyRequestTimeout = REST.defaultAPINetworkTimeout + 2 extension TunnelProtocol { - /// Request packet tunnel process to reconnect the tunnel with the given relay. + /// Request packet tunnel process to reconnect the tunnel with the given relays. func reconnectTunnel( - to nextRelay: NextRelay, + to nextRelays: NextRelays, completionHandler: @escaping (Result) -> Void ) -> Cancellable { let operation = SendTunnelProviderMessageOperation( dispatchQueue: dispatchQueue, application: .shared, tunnel: self, - message: .reconnectTunnel(nextRelay), + message: .reconnectTunnel(nextRelays), completionHandler: completionHandler ) diff --git a/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift b/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift index ef76cd8b8509..3b6735bd396a 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelInteractor.swift @@ -39,5 +39,5 @@ protocol TunnelInteractor { func startTunnel() func prepareForVPNConfigurationDeletion() - func selectRelay() throws -> SelectedRelay + func selectRelays() throws -> SelectedRelays } diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index 4e4d44cd4c05..d6d4be4d0616 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -782,13 +782,13 @@ final class TunnelManager: StorePaymentObserver { updateTunnelStatus(tunnel?.status ?? .disconnected) } - fileprivate func selectRelay() throws -> SelectedRelay { + fileprivate func selectRelays() throws -> SelectedRelays { let retryAttempts = tunnelStatus.observedState.connectionState?.connectionAttemptCount ?? 0 return try relaySelector.selectRelays( with: settings.relayConstraints, connectionAttemptCount: retryAttempts - ).exit // TODO: Multihop + ) } fileprivate func prepareForVPNConfigurationDeletion() { @@ -1260,8 +1260,8 @@ private struct TunnelInteractorProxy: TunnelInteractor { tunnelManager.prepareForVPNConfigurationDeletion() } - func selectRelay() throws -> SelectedRelay { - try tunnelManager.selectRelay() + func selectRelays() throws -> SelectedRelays { + try tunnelManager.selectRelays() } func handleRestError(_ error: Error) { diff --git a/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift b/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift index eefb1db415d4..3422c8602d88 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelState+UI.swift @@ -187,8 +187,8 @@ extension TunnelState { value: "Quantum secure connection. Connected to %@, %@", comment: "" ), - tunnelInfo.location.city, - tunnelInfo.location.country + tunnelInfo.exit.location.city, // TODO: Multihop + tunnelInfo.exit.location.country // TODO: Multihop ) } else { String( @@ -198,8 +198,8 @@ extension TunnelState { value: "Secure connection. Connected to %@, %@", comment: "" ), - tunnelInfo.location.city, - tunnelInfo.location.country + tunnelInfo.exit.location.city, // TODO: Multihop + tunnelInfo.exit.location.country // TODO: Multihop ) } @@ -219,8 +219,8 @@ extension TunnelState { value: "Reconnecting to %@, %@", comment: "" ), - tunnelInfo.location.city, - tunnelInfo.location.country + tunnelInfo.exit.location.city, // TODO: Multihop + tunnelInfo.exit.location.country // TODO: Multihop ) case .waitingForConnectivity(.noConnection), .error: diff --git a/ios/MullvadVPN/TunnelManager/TunnelState.swift b/ios/MullvadVPN/TunnelManager/TunnelState.swift index 43ae78e17d49..2c5a6109b678 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelState.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelState.swift @@ -50,13 +50,13 @@ enum TunnelState: Equatable, CustomStringConvertible { case pendingReconnect /// Connecting the tunnel. - case connecting(SelectedRelay?, isPostQuantum: Bool) + case connecting(SelectedRelays?, isPostQuantum: Bool) /// Negotiating a key for post-quantum resistance - case negotiatingPostQuantumKey(SelectedRelay, PrivateKey) + case negotiatingPostQuantumKey(SelectedRelays, PrivateKey) /// Connected the tunnel - case connected(SelectedRelay, isPostQuantum: Bool) + case connected(SelectedRelays, isPostQuantum: Bool) /// Disconnecting the tunnel case disconnecting(ActionAfterDisconnect) @@ -66,10 +66,10 @@ enum TunnelState: Equatable, CustomStringConvertible { /// Reconnecting the tunnel. /// Transition to this state happens when: - /// 1. Asking the running tunnel to reconnect to new relay via IPC. - /// 2. Tunnel attempts to reconnect to new relay as the current relay appears to be + /// 1. Asking the running tunnel to reconnect to new relays via IPC. + /// 2. Tunnel attempts to reconnect to new relays as the current relays appear to be /// dysfunctional. - case reconnecting(SelectedRelay, isPostQuantum: Bool) + case reconnecting(SelectedRelays, isPostQuantum: Bool) /// Waiting for connectivity to come back up. case waitingForConnectivity(WaitingForConnectionReason) @@ -81,26 +81,26 @@ enum TunnelState: Equatable, CustomStringConvertible { switch self { case .pendingReconnect: "pending reconnect after disconnect" - case let .connecting(tunnelRelay, isPostQuantum): - if let tunnelRelay { - "connecting \(isPostQuantum ? "(PQ) " : "")to \(tunnelRelay.hostname)" + case let .connecting(tunnelRelays, isPostQuantum): + if let tunnelRelays { + "connecting \(isPostQuantum ? "(PQ) " : "")to \(tunnelRelays.exit.hostname)" // TODO: Multihop } else { "connecting\(isPostQuantum ? " (PQ)" : ""), fetching relay" } - case let .connected(tunnelRelay, isPostQuantum): - "connected \(isPostQuantum ? "(PQ) " : "")to \(tunnelRelay.hostname)" + case let .connected(tunnelRelays, isPostQuantum): + "connected \(isPostQuantum ? "(PQ) " : "")to \(tunnelRelays.exit.hostname)" // TODO: Multihop case let .disconnecting(actionAfterDisconnect): "disconnecting and then \(actionAfterDisconnect)" case .disconnected: "disconnected" - case let .reconnecting(tunnelRelay, isPostQuantum): - "reconnecting \(isPostQuantum ? "(PQ) " : "")to \(tunnelRelay.hostname)" + case let .reconnecting(tunnelRelays, isPostQuantum): + "reconnecting \(isPostQuantum ? "(PQ) " : "")to \(tunnelRelays.exit.hostname)" // TODO: Multihop case .waitingForConnectivity: "waiting for connectivity" case let .error(blockedStateReason): "error state: \(blockedStateReason)" - case let .negotiatingPostQuantumKey(tunnelRelay, _): - "negotiating key with \(tunnelRelay.hostname)" + case let .negotiatingPostQuantumKey(tunnelRelays, _): + "negotiating key with \(tunnelRelays.exit.hostname)" // TODO: Multihop } } @@ -114,12 +114,12 @@ enum TunnelState: Equatable, CustomStringConvertible { } } - var relay: SelectedRelay? { + var relays: SelectedRelays? { switch self { - case let .connected(relay, _), let .reconnecting(relay, _), let .negotiatingPostQuantumKey(relay, _): - relay - case let .connecting(relay, _): - relay + case let .connected(relays, _), let .reconnecting(relays, _), let .negotiatingPostQuantumKey(relays, _): + relays + case let .connecting(relays, _): + relays case .disconnecting, .disconnected, .waitingForConnectivity, .pendingReconnect, .error: nil } diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift index 6ef103f93cd2..c627f85fa360 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift @@ -145,9 +145,9 @@ final class TunnelControlView: UIView { updateSecureLabel(tunnelState: tunnelState) updateActionButtons(tunnelState: tunnelState) if tunnelState.isSecured { - updateTunnelRelay(tunnelRelay: tunnelState.relay) + updateTunnelRelays(tunnelRelays: tunnelState.relays) } else { - updateTunnelRelay(tunnelRelay: nil) + updateTunnelRelays(tunnelRelays: nil) } } @@ -224,17 +224,17 @@ final class TunnelControlView: UIView { connectButtonBlurView.isEnabled = shouldEnableButtons } - private func updateTunnelRelay(tunnelRelay: SelectedRelay?) { - if let tunnelRelay { + private func updateTunnelRelays(tunnelRelays: SelectedRelays?) { + if let tunnelRelays { cityLabel.attributedText = attributedStringForLocation( - string: tunnelRelay.location.city + string: tunnelRelays.exit.location.city // TODO: Multihop ) countryLabel.attributedText = attributedStringForLocation( - string: tunnelRelay.location.country + string: tunnelRelays.exit.location.country // TODO: Multihop ) connectionPanel.isHidden = false - connectionPanel.connectedRelayName = tunnelRelay.hostname + connectionPanel.connectedRelayName = tunnelRelays.exit.hostname // TODO: Multihop } else { countryLabel.attributedText = attributedStringForLocation(string: " ") cityLabel.attributedText = attributedStringForLocation(string: " ") diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlViewModel.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlViewModel.swift index 833583efd389..c0df319d2505 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlViewModel.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlViewModel.swift @@ -18,7 +18,7 @@ struct TunnelControlViewModel { let outgoingConnectionInfo: OutgoingConnectionInfo? var connectionPanel: ConnectionPanelData? { - guard let tunnelRelay = tunnelStatus.state.relay else { + guard let tunnelRelays = tunnelStatus.state.relays else { return nil } @@ -29,7 +29,7 @@ struct TunnelControlViewModel { } return ConnectionPanelData( - inAddress: "\(tunnelRelay.endpoint.ipv4Relay.ip)\(portAndTransport)", + inAddress: "\(tunnelRelays.exit.endpoint.ipv4Relay.ip)\(portAndTransport)", // TODO: Multihop outAddress: outgoingConnectionInfo?.outAddress ) } diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift index 36f853504768..b5d0dfab64bf 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift @@ -147,18 +147,18 @@ class TunnelViewController: UIViewController, RootContainment { private func updateMap(animated: Bool) { switch tunnelState { - case let .connecting(tunnelRelay, _): + case let .connecting(tunnelRelays, _): mapViewController.removeLocationMarker() contentView.setAnimatingActivity(true) - mapViewController.setCenter(tunnelRelay?.location.geoCoordinate, animated: animated) + mapViewController.setCenter(tunnelRelays?.exit.location.geoCoordinate, animated: animated) // TODO: Multihop - case let .reconnecting(tunnelRelay, _), let .negotiatingPostQuantumKey(tunnelRelay, _): + case let .reconnecting(tunnelRelays, _), let .negotiatingPostQuantumKey(tunnelRelays, _): mapViewController.removeLocationMarker() contentView.setAnimatingActivity(true) - mapViewController.setCenter(tunnelRelay.location.geoCoordinate, animated: animated) + mapViewController.setCenter(tunnelRelays.exit.location.geoCoordinate, animated: animated) // TODO: Multihop - case let .connected(tunnelRelay, _): - let center = tunnelRelay.location.geoCoordinate + case let .connected(tunnelRelays, _): + let center = tunnelRelays.exit.location.geoCoordinate // TODO: Multihop mapViewController.setCenter(center, animated: animated) { self.contentView.setAnimatingActivity(false) diff --git a/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift b/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift index b538b910d8d2..6184756f4631 100644 --- a/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift +++ b/ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift @@ -6,8 +6,8 @@ // Copyright © 2024 Mullvad VPN AB. All rights reserved. // -import MullvadTypes import MullvadMockData +import MullvadTypes @testable import PacketTunnelCore @testable import PacketTunnelCoreTests import WireGuardKitTypes @@ -15,19 +15,18 @@ import XCTest final class PacketTunnelActorReducerTests: XCTestCase { // swiftlint:disable:next force_try - let selectedRelay = try! RelaySelectorStub + let selectedRelays = try! RelaySelectorStub .nonFallible() .selectRelays(with: RelayConstraints(), connectionAttemptCount: 0) - .exit // TODO: Multihop func makeConnectionData(keyPolicy: State.KeyPolicy = .useCurrent) -> State.ConnectionData { State.ConnectionData( - selectedRelay: selectedRelay, + selectedRelays: selectedRelays, relayConstraints: RelayConstraints(), keyPolicy: keyPolicy, networkReachability: .reachable, connectionAttemptCount: 0, - connectedEndpoint: selectedRelay.endpoint, + connectedEndpoint: selectedRelays.exit.endpoint, // TODO: Multihop transportLayer: .udp, remotePort: 12345, isPostQuantum: false @@ -55,13 +54,13 @@ final class PacketTunnelActorReducerTests: XCTestCase { // When let effects = PacketTunnelActor.Reducer.reduce( &state, - .start(StartOptions(launchSource: .app, selectedRelay: selectedRelay)) + .start(StartOptions(launchSource: .app, selectedRelays: selectedRelays)) ) // Then XCTAssertEqual(effects, [ .startDefaultPathObserver, .startTunnelMonitor, - .startConnection(.preSelected(selectedRelay)), + .startConnection(.preSelected(selectedRelays)), ]) } diff --git a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnelInteractor.swift b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnelInteractor.swift index 622c5269ad2e..3da521592243 100644 --- a/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnelInteractor.swift +++ b/ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnelInteractor.swift @@ -14,9 +14,9 @@ import MullvadSettings class MockTunnelInteractor: TunnelInteractor { var isConfigurationLoaded: Bool - var settings: MullvadSettings.LatestTunnelSettings + var settings: LatestTunnelSettings - var deviceState: MullvadSettings.DeviceState + var deviceState: DeviceState var onUpdateTunnelStatus: ((TunnelStatus) -> Void)? @@ -24,8 +24,8 @@ class MockTunnelInteractor: TunnelInteractor { init( isConfigurationLoaded: Bool, - settings: MullvadSettings.LatestTunnelSettings, - deviceState: MullvadSettings.DeviceState, + settings: LatestTunnelSettings, + deviceState: DeviceState, onUpdateTunnelStatus: ((TunnelStatus) -> Void)? = nil ) { self.isConfigurationLoaded = isConfigurationLoaded @@ -59,9 +59,9 @@ class MockTunnelInteractor: TunnelInteractor { func setConfigurationLoaded() {} - func setSettings(_ settings: MullvadSettings.LatestTunnelSettings, persist: Bool) {} + func setSettings(_ settings: LatestTunnelSettings, persist: Bool) {} - func setDeviceState(_ deviceState: MullvadSettings.DeviceState, persist: Bool) {} + func setDeviceState(_ deviceState: DeviceState, persist: Bool) {} func removeLastUsedAccount() {} @@ -73,7 +73,7 @@ class MockTunnelInteractor: TunnelInteractor { struct NotImplementedError: Error {} - func selectRelay() throws -> SelectedRelay { + func selectRelays() throws -> SelectedRelays { throw NotImplementedError() } } diff --git a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift index ebefeee7868a..cf81a3b1b41a 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift @@ -207,9 +207,9 @@ extension PacketTunnelProvider { var parsedOptions = StartOptions(launchSource: tunnelOptions.isOnDemand() ? .onDemand : .app) do { - if let selectedRelay = try tunnelOptions.getSelectedRelay() { + if let selectedRelays = try tunnelOptions.getSelectedRelays() { parsedOptions.launchSource = .app - parsedOptions.selectedRelay = selectedRelay + parsedOptions.selectedRelays = selectedRelays } else if !tunnelOptions.isOnDemand() { parsedOptions.launchSource = .system } diff --git a/ios/PacketTunnelCore/Actor/ObservedState.swift b/ios/PacketTunnelCore/Actor/ObservedState.swift index 6975191e0497..43d99fdfea6b 100644 --- a/ios/PacketTunnelCore/Actor/ObservedState.swift +++ b/ios/PacketTunnelCore/Actor/ObservedState.swift @@ -27,7 +27,7 @@ public enum ObservedState: Equatable, Codable { /// A serializable representation of internal connection state. public struct ObservedConnectionState: Equatable, Codable { - public var selectedRelay: SelectedRelay + public var selectedRelays: SelectedRelays public var relayConstraints: RelayConstraints public var networkReachability: NetworkReachability public var connectionAttemptCount: UInt @@ -41,7 +41,7 @@ public struct ObservedConnectionState: Equatable, Codable { } public init( - selectedRelay: SelectedRelay, + selectedRelays: SelectedRelays, relayConstraints: RelayConstraints, networkReachability: NetworkReachability, connectionAttemptCount: UInt, @@ -50,7 +50,7 @@ public struct ObservedConnectionState: Equatable, Codable { lastKeyRotation: Date? = nil, isPostQuantum: Bool ) { - self.selectedRelay = selectedRelay + self.selectedRelays = selectedRelays self.relayConstraints = relayConstraints self.networkReachability = networkReachability self.connectionAttemptCount = connectionAttemptCount @@ -95,7 +95,7 @@ extension State.ConnectionData { /// Map `State.ConnectionData` to `ObservedConnectionState`. var observedConnectionState: ObservedConnectionState { ObservedConnectionState( - selectedRelay: selectedRelay, + selectedRelays: selectedRelays, relayConstraints: relayConstraints, networkReachability: networkReachability, connectionAttemptCount: connectionAttemptCount, diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift index d8a5a8772c50..30348546f173 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift @@ -16,10 +16,10 @@ extension PacketTunnelActor { */ internal func tryStartPostQuantumNegotiation( withSettings settings: Settings, - nextRelay: NextRelay, + nextRelays: NextRelays, reason: ActorReconnectReason ) async throws { - if let connectionState = try obfuscateConnection(nextRelay: nextRelay, settings: settings, reason: reason) { + if let connectionState = try obfuscateConnection(nextRelays: nextRelays, settings: settings, reason: reason) { let selectedEndpoint = connectionState.connectedEndpoint let activeKey = activeKey(from: connectionState, in: settings) @@ -44,18 +44,18 @@ extension PacketTunnelActor { internal func postQuantumConnect(with key: PreSharedKey, privateKey: PrivateKey) async { guard // It is important to select the same relay that was saved in the connection state as the key negotiation happened with this specific relay. - let selectedRelay = state.connectionData?.selectedRelay, + let selectedRelays = state.connectionData?.selectedRelays, let settings: Settings = try? settingsReader.read(), let connectionState = try? obfuscateConnection( - nextRelay: .preSelected(selectedRelay), + nextRelays: .preSelected(selectedRelays), settings: settings, reason: .userInitiated ) else { logger.error("Could not create connection state in PostQuantumConnect") - let nextRelay: NextRelay = (state.connectionData?.selectedRelay).map { .preSelected($0) } ?? .current - eventChannel.send(.reconnect(nextRelay)) + let nextRelays: NextRelays = (state.connectionData?.selectedRelays).map { .preSelected($0) } ?? .current + eventChannel.send(.reconnect(nextRelays)) return } @@ -76,7 +76,7 @@ extension PacketTunnelActor { try? await tunnelAdapter.start(configuration: configurationBuilder.makeConfiguration()) // Resume tunnel monitoring and use IPv4 gateway as a probe address. - tunnelMonitor.start(probeAddress: connectionState.selectedRelay.endpoint.ipv4Gateway) + tunnelMonitor.start(probeAddress: connectionState.selectedRelays.exit.endpoint.ipv4Gateway) // TODO: Multihop // Restart default path observer and notify the observer with the current path that might have changed while // path observer was paused. startDefaultPathObserver(notifyObserverWithCurrentPath: false) diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+Public.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+Public.swift index 5ba42a0bd203..160fd9bbe6a3 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+Public.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+Public.swift @@ -36,10 +36,10 @@ extension PacketTunnelActor { /** Tell actor to reconnect the tunnel. - - Parameter nextRelay: next relay to connect to. + - Parameter nextRelays: next relays to connect to. */ - public nonisolated func reconnect(to nextRelay: NextRelay, reconnectReason: ActorReconnectReason) { - eventChannel.send(.reconnect(nextRelay, reason: reconnectReason)) + public nonisolated func reconnect(to nextRelays: NextRelays, reconnectReason: ActorReconnectReason) { + eventChannel.send(.reconnect(nextRelays, reason: reconnectReason)) } /** diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift index f3bc9cdc5a35..715cfd840dc3 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift @@ -110,16 +110,16 @@ public actor PacketTunnelActor { tunnelMonitor.stop() case let .updateTunnelMonitorPath(networkPath): handleDefaultPathChange(networkPath) - case let .startConnection(nextRelay): + case let .startConnection(nextRelays): do { - try await tryStart(nextRelay: nextRelay) + try await tryStart(nextRelays: nextRelays) } catch { logger.error(error: error, message: "Failed to start the tunnel.") await setErrorStateInternal(with: error) } - case let .restartConnection(nextRelay, reason): + case let .restartConnection(nextRelays, reason): do { - try await tryStart(nextRelay: nextRelay, reason: reason) + try await tryStart(nextRelays: nextRelays, reason: reason) } catch { logger.error(error: error, message: "Failed to reconnect the tunnel.") await setErrorStateInternal(with: error) @@ -168,7 +168,7 @@ extension PacketTunnelActor { setTunnelMonitorEventHandler() do { - try await tryStart(nextRelay: options.selectedRelay.map { .preSelected($0) } ?? .random) + try await tryStart(nextRelays: options.selectedRelays.map { .preSelected($0) } ?? .random) } catch { logger.error(error: error, message: "Failed to start the tunnel.") @@ -206,13 +206,13 @@ extension PacketTunnelActor { } /** - Reconnect tunnel to new relay. Enters error state on failure. + Reconnect tunnel to new relays. Enters error state on failure. - Parameters: - - nextRelay: next relay to connect to + - nextRelay: next relays to connect to - reason: reason for reconnect */ - private func reconnect(to nextRelay: NextRelay, reason: ActorReconnectReason) async { + private func reconnect(to nextRelays: NextRelays, reason: ActorReconnectReason) async { do { switch state { // There is no connection monitoring going on when exchanging keys. @@ -227,7 +227,7 @@ extension PacketTunnelActor { tunnelMonitor.stop() } - try await tryStart(nextRelay: nextRelay, reason: reason) + try await tryStart(nextRelays: nextRelays, reason: reason) case .disconnected, .disconnecting, .initial: break @@ -246,15 +246,15 @@ extension PacketTunnelActor { - Start either a direct connection or the post-quantum key negotiation process, depending on settings. */ private func tryStart( - nextRelay: NextRelay, + nextRelays: NextRelays, reason: ActorReconnectReason = .userInitiated ) async throws { let settings: Settings = try settingsReader.read() if settings.quantumResistance.isEnabled { - try await tryStartPostQuantumNegotiation(withSettings: settings, nextRelay: nextRelay, reason: reason) + try await tryStartPostQuantumNegotiation(withSettings: settings, nextRelays: nextRelays, reason: reason) } else { - try await tryStartConnection(withSettings: settings, nextRelay: nextRelay, reason: reason) + try await tryStartConnection(withSettings: settings, nextRelays: nextRelays, reason: reason) } } @@ -269,15 +269,15 @@ extension PacketTunnelActor { - Reactivate default path observation (disabled when configuring tunnel adapter) - Parameters: - - nextRelay: which relay should be selected next. + - nextRelays: which relays should be selected next. - reason: reason for reconnect */ private func tryStartConnection( withSettings settings: Settings, - nextRelay: NextRelay, + nextRelays: NextRelays, reason: ActorReconnectReason ) async throws { - guard let connectionState = try obfuscateConnection(nextRelay: nextRelay, settings: settings, reason: reason), + guard let connectionState = try obfuscateConnection(nextRelays: nextRelays, settings: settings, reason: reason), let targetState = state.targetStateForReconnect else { return } let activeKey = activeKey(from: connectionState, in: settings) @@ -316,21 +316,21 @@ extension PacketTunnelActor { try await tunnelAdapter.start(configuration: configurationBuilder.makeConfiguration()) // Resume tunnel monitoring and use IPv4 gateway as a probe address. - tunnelMonitor.start(probeAddress: connectionState.selectedRelay.endpoint.ipv4Gateway) + tunnelMonitor.start(probeAddress: connectionState.selectedRelays.exit.endpoint.ipv4Gateway) // TODO: Multihop } /** - Derive `ConnectionState` from current `state` updating it with new relay and settings. + Derive `ConnectionState` from current `state` updating it with new relays and settings. - Parameters: - - nextRelay: relay preference that should be used when selecting next relay. + - nextRelays: relay preference that should be used when selecting next relays. - settings: current settings - reason: reason for reconnect - Returns: New connection state or `nil` if current state is at or past `.disconnecting` phase. */ internal func makeConnectionState( - nextRelay: NextRelay, + nextRelays: NextRelays, settings: Settings, reason: ActorReconnectReason ) throws -> State.ConnectionData? { @@ -338,11 +338,11 @@ extension PacketTunnelActor { var networkReachability = defaultPathObserver.defaultPath?.networkReachability ?? .undetermined var lastKeyRotation: Date? - let callRelaySelector = { [self] maybeCurrentRelay, connectionCount in - try self.selectRelay( - nextRelay: nextRelay, + let callRelaySelector = { [self] maybeCurrentRelays, connectionCount in + try self.selectRelays( + nextRelays: nextRelays, relayConstraints: settings.relayConstraints, - currentRelay: maybeCurrentRelay, + currentRelays: maybeCurrentRelays, connectionAttemptCount: connectionCount ) } @@ -355,11 +355,11 @@ extension PacketTunnelActor { if reason == .connectionLoss { connectionState.incrementAttemptCount() } - let selectedRelay = try callRelaySelector( - connectionState.selectedRelay, + let selectedRelays = try callRelaySelector( + connectionState.selectedRelays, connectionState.connectionAttemptCount ) - connectionState.selectedRelay = selectedRelay + connectionState.selectedRelays = selectedRelays connectionState.relayConstraints = settings.relayConstraints return connectionState case var .connecting(connectionState), var .reconnecting(connectionState): @@ -368,11 +368,11 @@ extension PacketTunnelActor { } fallthrough case var .connected(connectionState): - let selectedRelay = try callRelaySelector( - connectionState.selectedRelay, + let selectedRelays = try callRelaySelector( + connectionState.selectedRelays, connectionState.connectionAttemptCount ) - connectionState.selectedRelay = selectedRelay + connectionState.selectedRelays = selectedRelays connectionState.relayConstraints = settings.relayConstraints connectionState.currentKey = settings.privateKey return connectionState @@ -383,18 +383,18 @@ extension PacketTunnelActor { case .disconnecting, .disconnected: return nil } - let selectedRelay = try callRelaySelector(nil, 0) + let selectedRelays = try callRelaySelector(nil, 0) return State.ConnectionData( - selectedRelay: selectedRelay, + selectedRelays: selectedRelays, relayConstraints: settings.relayConstraints, currentKey: settings.privateKey, keyPolicy: keyPolicy, networkReachability: networkReachability, connectionAttemptCount: 0, lastKeyRotation: lastKeyRotation, - connectedEndpoint: selectedRelay.endpoint, + connectedEndpoint: selectedRelays.exit.endpoint, // TODO: Multihop transportLayer: .udp, - remotePort: selectedRelay.endpoint.ipv4Relay.port, + remotePort: selectedRelays.exit.endpoint.ipv4Relay.port, // TODO: Multihop isPostQuantum: settings.quantumResistance.isEnabled ) } @@ -409,22 +409,22 @@ extension PacketTunnelActor { } internal func obfuscateConnection( - nextRelay: NextRelay, + nextRelays: NextRelays, settings: Settings, reason: ActorReconnectReason ) throws -> State.ConnectionData? { - guard let connectionState = try makeConnectionState(nextRelay: nextRelay, settings: settings, reason: reason) + guard let connectionState = try makeConnectionState(nextRelays: nextRelays, settings: settings, reason: reason) else { return nil } let obfuscatedEndpoint = protocolObfuscator.obfuscate( - connectionState.selectedRelay.endpoint, + connectionState.selectedRelays.exit.endpoint, // TODO: Multihop settings: settings, - retryAttempts: connectionState.selectedRelay.retryAttempts + retryAttempts: connectionState.selectedRelays.exit.retryAttempts // TODO: Multihop ) let transportLayer = protocolObfuscator.transportLayer.map { $0 } ?? .udp return State.ConnectionData( - selectedRelay: connectionState.selectedRelay, + selectedRelays: connectionState.selectedRelays, relayConstraints: connectionState.relayConstraints, currentKey: settings.privateKey, keyPolicy: connectionState.keyPolicy, @@ -439,28 +439,28 @@ extension PacketTunnelActor { } /** - Select next relay to connect to based on `NextRelay` and other input parameters. + Select next relay to connect to based on `NextRelays` and other input parameters. - Parameters: - - nextRelay: next relay to connect to. + - nextRelays: next relays to connect to. - relayConstraints: relay constraints. - - currentRelay: currently selected relay. + - currentRelays: currently selected relays. - connectionAttemptCount: number of failed connection attempts so far. - - Returns: selector result that contains the credentials of the next relay that the tunnel should connect to. + - Returns: selector result that contains the credentials of the next relays that the tunnel should connect to. */ - private func selectRelay( - nextRelay: NextRelay, + private func selectRelays( + nextRelays: NextRelays, relayConstraints: RelayConstraints, - currentRelay: SelectedRelay?, + currentRelays: SelectedRelays?, connectionAttemptCount: UInt - ) throws -> SelectedRelay { - switch nextRelay { + ) throws -> SelectedRelays { + switch nextRelays { case .current: - if let currentRelay { - return currentRelay + if let currentRelays { + return currentRelays } else { - // Fallthrough to .random when current relay is not set. + // Fallthrough to .random when current relays are not set. fallthrough } @@ -468,10 +468,10 @@ extension PacketTunnelActor { return try relaySelector.selectRelays( with: relayConstraints, connectionAttemptCount: connectionAttemptCount - ).exit // TODO: Multihop + ) - case let .preSelected(selectedRelay): - return selectedRelay + case let .preSelected(selectedRelays): + return selectedRelays } } } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift index 21e2aca702f3..fd731a32e150 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift @@ -19,7 +19,7 @@ extension PacketTunnelActor { case stop /// Reconnect tunnel. - case reconnect(NextRelay, reason: ActorReconnectReason = .userInitiated) + case reconnect(NextRelays, reason: ActorReconnectReason = .userInitiated) /// Enter blocked state. case error(BlockedStateReason) @@ -46,14 +46,14 @@ extension PacketTunnelActor { return "start" case .stop: return "stop" - case let .reconnect(nextRelay, stopTunnelMonitor): - switch nextRelay { + case let .reconnect(nextRelays, stopTunnelMonitor): + switch nextRelays { case .current: return "reconnect(current, \(stopTunnelMonitor))" case .random: return "reconnect(random, \(stopTunnelMonitor))" - case let .preSelected(selectedRelay): - return "reconnect(\(selectedRelay.hostname), \(stopTunnelMonitor))" + case let .preSelected(selectedRelays): + return "reconnect(\(selectedRelays.exit.hostname), \(stopTunnelMonitor))" // TODO: Multihop } case let .error(reason): return "error(\(reason))" diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActorProtocol.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActorProtocol.swift index df34f768cb80..02729d449c01 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActorProtocol.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActorProtocol.swift @@ -11,6 +11,6 @@ import Foundation public protocol PacketTunnelActorProtocol { var observedState: ObservedState { get async } - func reconnect(to nextRelay: NextRelay, reconnectReason: ActorReconnectReason) + func reconnect(to nextRelays: NextRelays, reconnectReason: ActorReconnectReason) func notifyKeyRotation(date: Date?) } diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActorReducer.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActorReducer.swift index 200da62fffab..6d4056b68338 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActorReducer.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActorReducer.swift @@ -17,10 +17,10 @@ extension PacketTunnelActor { case startTunnelMonitor case stopTunnelMonitor case updateTunnelMonitorPath(NetworkPath) - case startConnection(NextRelay) - case restartConnection(NextRelay, ActorReconnectReason) + case startConnection(NextRelays) + case restartConnection(NextRelays, ActorReconnectReason) // trigger a reconnect, which becomes several effects depending on the state - case reconnect(NextRelay) + case reconnect(NextRelays) case stopTunnelAdapter case configureForErrorState(BlockedStateReason) case cacheActiveKey(Date?) @@ -58,7 +58,7 @@ extension PacketTunnelActor { return [ .startDefaultPathObserver, .startTunnelMonitor, - .startConnection(options.selectedRelay.map { .preSelected($0) } ?? .random), + .startConnection(options.selectedRelays.map { .preSelected($0) } ?? .random), ] case .stop: return subreducerForStop(&state) @@ -124,7 +124,7 @@ extension PacketTunnelActor { fileprivate static func subreducerForReconnect( _ state: State, _ reason: ActorReconnectReason, - _ nextRelay: NextRelay + _ nextRelays: NextRelays ) -> [PacketTunnelActor.Effect] { switch state { case .disconnected, .disconnecting, .initial: @@ -133,9 +133,9 @@ extension PacketTunnelActor { return [] case .connecting, .connected, .reconnecting, .error, .negotiatingPostQuantumKey: if reason == .userInitiated { - return [.stopTunnelMonitor, .restartConnection(nextRelay, reason)] + return [.stopTunnelMonitor, .restartConnection(nextRelays, reason)] } else { - return [.restartConnection(nextRelay, reason)] + return [.restartConnection(nextRelays, reason)] } } } diff --git a/ios/PacketTunnelCore/Actor/StartOptions.swift b/ios/PacketTunnelCore/Actor/StartOptions.swift index 0e484ef58fdd..4c8ad7587891 100644 --- a/ios/PacketTunnelCore/Actor/StartOptions.swift +++ b/ios/PacketTunnelCore/Actor/StartOptions.swift @@ -14,20 +14,20 @@ public struct StartOptions { /// The system that triggered the launch of packet tunnel. public var launchSource: LaunchSource - /// Pre-selected relay received from UI when available. - public var selectedRelay: SelectedRelay? + /// Pre-selected relays received from UI when available. + public var selectedRelays: SelectedRelays? /// Designated initializer. - public init(launchSource: LaunchSource, selectedRelay: SelectedRelay? = nil) { + public init(launchSource: LaunchSource, selectedRelays: SelectedRelays? = nil) { self.launchSource = launchSource - self.selectedRelay = selectedRelay + self.selectedRelays = selectedRelays } /// Returns a brief description suitable for output to tunnel provider log. public func logFormat() -> String { var s = "Start the tunnel via \(launchSource)" - if let selectedRelay { - s += ", connect to \(selectedRelay.hostname)" + if let selectedRelays { + s += ", connect to \(selectedRelays.exit.hostname)" // TODO: Multihop } s += "." return s diff --git a/ios/PacketTunnelCore/Actor/State+Extensions.swift b/ios/PacketTunnelCore/Actor/State+Extensions.swift index be1f05d52dc6..69d6579a9db9 100644 --- a/ios/PacketTunnelCore/Actor/State+Extensions.swift +++ b/ios/PacketTunnelCore/Actor/State+Extensions.swift @@ -47,7 +47,7 @@ extension State { func logFormat() -> String { switch self { case let .connecting(connState), let .connected(connState), let .reconnecting(connState): - let hostname = connState.selectedRelay.hostname + let hostname = connState.selectedRelays.exit.hostname // TODO: Multihop return """ \(name) to \(hostname), \ diff --git a/ios/PacketTunnelCore/Actor/State.swift b/ios/PacketTunnelCore/Actor/State.swift index 0aae1ac602d1..0ae4c79e3ea6 100644 --- a/ios/PacketTunnelCore/Actor/State.swift +++ b/ios/PacketTunnelCore/Actor/State.swift @@ -110,8 +110,8 @@ extension State { /// Data associated with states that hold connection data. struct ConnectionData: Equatable, StateAssociatedData { - /// Current selected relay. - public var selectedRelay: SelectedRelay + /// Current selected relays. + public var selectedRelays: SelectedRelays /// Last relay constraints read from settings. /// This is primarily used by packet tunnel for updating constraints in tunnel provider. @@ -229,15 +229,15 @@ extension State.BlockingData { } /// Describes which relay the tunnel should connect to next. -public enum NextRelay: Equatable, Codable { - /// Select next relay randomly. +public enum NextRelays: Equatable, Codable { + /// Select next relays randomly. case random - /// Use currently selected relay, fallback to random if not set. + /// Use currently selected relays, fallback to random if not set. case current - /// Use pre-selected relay. - case preSelected(SelectedRelay) + /// Use pre-selected relays. + case preSelected(SelectedRelays) } /// Describes the reason for reconnection request. diff --git a/ios/PacketTunnelCore/IPC/PacketTunnelOptions.swift b/ios/PacketTunnelCore/IPC/PacketTunnelOptions.swift index ad632baa16f3..79bc030706f8 100644 --- a/ios/PacketTunnelCore/IPC/PacketTunnelOptions.swift +++ b/ios/PacketTunnelCore/IPC/PacketTunnelOptions.swift @@ -14,7 +14,7 @@ public struct PacketTunnelOptions { private enum Keys: String { /// 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 selectedRelay = "selected-relay" + case selectedRelays = "selected-relays" /// Option key that holds an `NSNumber` value, which is when set to `1` indicates that the tunnel was started by the system. /// System automatically provides that flag to the tunnel. @@ -35,14 +35,14 @@ public struct PacketTunnelOptions { _rawOptions = rawOptions } - public func getSelectedRelay() throws -> SelectedRelay? { - guard let data = _rawOptions[Keys.selectedRelay.rawValue] as? Data else { return nil } + public func getSelectedRelays() throws -> SelectedRelays? { + guard let data = _rawOptions[Keys.selectedRelays.rawValue] as? Data else { return nil } - return try Self.decode(SelectedRelay.self, data) + return try Self.decode(SelectedRelays.self, data) } - public mutating func setSelectedRelay(_ value: SelectedRelay) throws { - _rawOptions[Keys.selectedRelay.rawValue] = try Self.encode(value) as NSData + public mutating func setSelectedRelays(_ value: SelectedRelays) throws { + _rawOptions[Keys.selectedRelays.rawValue] = try Self.encode(value) as NSData } public func isOnDemand() -> Bool { diff --git a/ios/PacketTunnelCore/IPC/TunnelProviderMessage.swift b/ios/PacketTunnelCore/IPC/TunnelProviderMessage.swift index 70626744379e..2b1126e8db54 100644 --- a/ios/PacketTunnelCore/IPC/TunnelProviderMessage.swift +++ b/ios/PacketTunnelCore/IPC/TunnelProviderMessage.swift @@ -11,7 +11,7 @@ import Foundation /// Enum describing supported app messages handled by packet tunnel provider. public enum TunnelProviderMessage: Codable, CustomStringConvertible { /// Request the tunnel to reconnect. - case reconnectTunnel(NextRelay) + case reconnectTunnel(NextRelays) /// Request the tunnel status. case getTunnelStatus diff --git a/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift b/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift index dc85adcaa71c..680b438f8395 100644 --- a/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift +++ b/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift @@ -95,15 +95,18 @@ final class AppMessageHandlerTests: XCTestCase { numberOfFailedAttempts: 0 ) - let selectedRelay = SelectedRelay( - endpoint: match.endpoint, - hostname: match.relay.hostname, - location: match.location, - retryAttempts: 0 + let selectedRelays = SelectedRelays( + entry: nil, + exit: SelectedRelay( + endpoint: match.endpoint, + hostname: match.relay.hostname, + location: match.location, + retryAttempts: 0 + ) ) _ = try? await appMessageHandler.handleAppMessage( - TunnelProviderMessage.reconnectTunnel(.preSelected(selectedRelay)).encode() + TunnelProviderMessage.reconnectTunnel(.preSelected(selectedRelays)).encode() ) await fulfillment(of: [reconnectExpectation], timeout: .UnitTest.timeout) diff --git a/ios/PacketTunnelCoreTests/EventChannelTests.swift b/ios/PacketTunnelCoreTests/EventChannelTests.swift index 3cdd0f7b0d15..59d798a8a262 100644 --- a/ios/PacketTunnelCoreTests/EventChannelTests.swift +++ b/ios/PacketTunnelCoreTests/EventChannelTests.swift @@ -90,7 +90,7 @@ extension AsyncSequence { /// Simplified version of `Event` that can be used in tests and easily compared against. enum SimplifiedEvent: Equatable { - case start, stop, reconnect(NextRelay), switchKey, other + case start, stop, reconnect(NextRelays), switchKey, other } extension PacketTunnelActor.Event { diff --git a/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActorStub.swift b/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActorStub.swift index 1c3c1533ae6e..d526f1f168b9 100644 --- a/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActorStub.swift +++ b/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActorStub.swift @@ -23,7 +23,7 @@ struct PacketTunnelActorStub: PacketTunnelActorProtocol { } } - func reconnect(to nextRelay: PacketTunnelCore.NextRelay, reconnectReason: ActorReconnectReason) { + func reconnect(to nextRelays: NextRelays, reconnectReason: ActorReconnectReason) { reconnectExpectation?.fulfill() }