summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJon Petersson <jon.petersson@kvadrat.se>2024-06-10 16:14:39 +0200
committerEmīls <emils@mullvad.net>2024-07-11 16:53:24 +0200
commit5a0554fc315c31f2aa7955bf0ef9fdc9b1acff5e (patch)
treeb4628f49c1d4fb4dc5f641524a621f85f9c1cb91
parent67e9e0ef08723cd991659a106398cbe0cb88493e (diff)
downloadmullvadvpn-5a0554fc315c31f2aa7955bf0ef9fdc9b1acff5e.tar.xz
mullvadvpn-5a0554fc315c31f2aa7955bf0ef9fdc9b1acff5e.zip
Add general support for multiple selected relays
-rw-r--r--ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift2
-rw-r--r--ios/MullvadREST/Relay/RelaySelector+Wireguard.swift4
-rw-r--r--ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift32
-rw-r--r--ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift8
-rw-r--r--ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift8
-rw-r--r--ios/MullvadVPN/TunnelManager/Tunnel+Messaging.swift6
-rw-r--r--ios/MullvadVPN/TunnelManager/TunnelInteractor.swift2
-rw-r--r--ios/MullvadVPN/TunnelManager/TunnelManager.swift8
-rw-r--r--ios/MullvadVPN/TunnelManager/TunnelState+UI.swift12
-rw-r--r--ios/MullvadVPN/TunnelManager/TunnelState.swift40
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift14
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/TunnelControlViewModel.swift4
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift12
-rw-r--r--ios/MullvadVPNTests/MullvadVPN/PacketTunnelCore/PacketTunnelActorReducerTests.swift13
-rw-r--r--ios/MullvadVPNTests/MullvadVPN/TunnelManager/MockTunnelInteractor.swift14
-rw-r--r--ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift4
-rw-r--r--ios/PacketTunnelCore/Actor/ObservedState.swift8
-rw-r--r--ios/PacketTunnelCore/Actor/PacketTunnelActor+PostQuantum.swift14
-rw-r--r--ios/PacketTunnelCore/Actor/PacketTunnelActor+Public.swift6
-rw-r--r--ios/PacketTunnelCore/Actor/PacketTunnelActor.swift106
-rw-r--r--ios/PacketTunnelCore/Actor/PacketTunnelActorCommand.swift10
-rw-r--r--ios/PacketTunnelCore/Actor/PacketTunnelActorProtocol.swift2
-rw-r--r--ios/PacketTunnelCore/Actor/PacketTunnelActorReducer.swift14
-rw-r--r--ios/PacketTunnelCore/Actor/StartOptions.swift12
-rw-r--r--ios/PacketTunnelCore/Actor/State+Extensions.swift2
-rw-r--r--ios/PacketTunnelCore/Actor/State.swift14
-rw-r--r--ios/PacketTunnelCore/IPC/PacketTunnelOptions.swift12
-rw-r--r--ios/PacketTunnelCore/IPC/TunnelProviderMessage.swift2
-rw-r--r--ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift15
-rw-r--r--ios/PacketTunnelCoreTests/EventChannelTests.swift2
-rw-r--r--ios/PacketTunnelCoreTests/Mocks/PacketTunnelActorStub.swift2
31 files changed, 203 insertions, 201 deletions
diff --git a/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift b/ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift
index 2fe06dafe3..f2f8952df4 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 382479ee20..1e61156941 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<UserSelectedRelays>,
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<REST.ServerRelay>],
relays: REST.ServerRelaysResponse,
diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift
index bc3ce91307..08b49d4b05 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 4957af7c52..b605b85b47 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 cd9e8b7a88..bb125db5ab 100644
--- a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift
+++ b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift
@@ -72,12 +72,12 @@ class StartTunnelOperation: ResultOperation<Void> {
}
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<Void> {
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 5299a281cc..04a231c5c4 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, Error>) -> 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 ef76cd8b85..3b6735bd39 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 4e4d44cd4c..d6d4be4d06 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 eefb1db415..3422c8602d 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 43ae78e17d..2c5a6109b6 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 6ef103f93c..c627f85fa3 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 833583efd3..c0df319d25 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 36f8535047..b5d0dfab64 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 b538b910d8..6184756f46 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 622c5269ad..3da5215922 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 ebefeee786..cf81a3b1b4 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 6975191e04..43d99fdfea 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 d8a5a8772c..30348546f1 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 5ba42a0bd2..160fd9bbe6 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 f3bc9cdc5a..715cfd840d 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 21e2aca702..fd731a32e1 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 df34f768cb..02729d449c 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 200da62fff..6d4056b683 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 0e484ef58f..4c8ad75878 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 be1f05d52d..69d6579a9d 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 0aae1ac602..0ae4c79e3e 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 ad632baa16..79bc030706 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 7062674437..2b1126e8db 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 dc85adcaa7..680b438f83 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 3cdd0f7b0d..59d798a8a2 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 1c3c1533ae..d526f1f168 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()
}