summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2023-06-20 16:23:41 +0200
committerAndrej Mihajlov <and@mullvad.net>2023-06-20 16:23:41 +0200
commit7cbccbc9ff029bf77d301e9ee871a101889017b2 (patch)
treee3f2a78b9e512c1d6ea5559a08a3914cb0ef3ca3
parent152dfd869ff3db5c8b81cc3ed5a82355f396e70f (diff)
parent69b45ee945ec3dc2e9611c39af6cfc49398f0da3 (diff)
downloadmullvadvpn-7cbccbc9ff029bf77d301e9ee871a101889017b2.tar.xz
mullvadvpn-7cbccbc9ff029bf77d301e9ee871a101889017b2.zip
Merge branch 'cache-successful-shadowsocks-relay-and-api-endpoints-for-ios-165'
-rw-r--r--ios/MullvadREST/AddressCache.swift5
-rw-r--r--ios/MullvadREST/RESTNetworkOperation.swift42
-rw-r--r--ios/MullvadREST/RESTProxy.swift4
-rw-r--r--ios/MullvadREST/RESTProxyFactory.swift2
-rw-r--r--ios/MullvadREST/RESTTransport.swift10
-rw-r--r--ios/MullvadREST/RESTTransportStrategy.swift12
-rw-r--r--ios/MullvadRESTTests/TransportStrategyTests.swift25
-rw-r--r--ios/MullvadTransport/TransportProvider.swift100
-rw-r--r--ios/MullvadTransport/shadowsocks-proxy/build.sh6
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj4
-rw-r--r--ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift5
-rw-r--r--ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelTransportProvider.swift27
-rw-r--r--ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift7
-rw-r--r--ios/MullvadVPN/TransportMonitor/TransportMonitor.swift19
-rw-r--r--ios/RelaySelector/RelaySelector.swift4
-rw-r--r--ios/TunnelProviderMessaging/ProxyURLRequest.swift4
-rw-r--r--ios/TunnelProviderMessaging/URLRequestProxy.swift13
17 files changed, 152 insertions, 137 deletions
diff --git a/ios/MullvadREST/AddressCache.swift b/ios/MullvadREST/AddressCache.swift
index 8279b1c263..da27798c9d 100644
--- a/ios/MullvadREST/AddressCache.swift
+++ b/ios/MullvadREST/AddressCache.swift
@@ -73,11 +73,6 @@ extension REST {
return currentEndpoint
}
- public func selectNextEndpoint(_ failedEndpoint: AnyIPEndpoint) -> AnyIPEndpoint {
- // This function currently acts as a convoluted no-op. It will be soon deleted.
- return getCurrentEndpoint()
- }
-
/// Updates the available endpoints to use
///
/// Only the first available endpoint is kept, the rest are discarded.
diff --git a/ios/MullvadREST/RESTNetworkOperation.swift b/ios/MullvadREST/RESTNetworkOperation.swift
index 41072de713..372991ed8d 100644
--- a/ios/MullvadREST/RESTNetworkOperation.swift
+++ b/ios/MullvadREST/RESTNetworkOperation.swift
@@ -17,7 +17,7 @@ extension REST {
private let responseHandler: AnyResponseHandler<Success>
private let logger: Logger
- private let transportProvider: () -> RESTTransportProvider?
+ private let transportProvider: () -> RESTTransport?
private let addressCacheStore: AddressCache
private var networkTask: Cancellable?
@@ -30,7 +30,6 @@ extension REST {
private var retryDelayIterator: AnyIterator<Duration>
private var retryTimer: DispatchSourceTimer?
private var retryCount = 0
- private var transportStrategy = TransportStrategy()
init(
name: String,
@@ -141,12 +140,7 @@ extension REST {
private func didReceiveURLRequest(_ restRequest: REST.Request, endpoint: AnyIPEndpoint) {
dispatchPrecondition(condition: .onQueue(dispatchQueue))
- let suggestedTransport = transportStrategy.connectionTransport()
- let transportProvider = transportProvider()
- let transport = suggestedTransport == .useShadowsocks
- ? transportProvider?.shadowsocksTransport()
- : transportProvider?.transport()
-
+ let transport = transportProvider()
guard let transport else {
logger.error("Failed to obtain transport.")
finish(result: .failure(REST.Error.transport(NoTransportError())))
@@ -175,7 +169,6 @@ extension REST {
self.didReceiveURLResponse(
httpResponse,
- transport: transport,
data: data,
endpoint: endpoint
)
@@ -202,34 +195,19 @@ extension REST {
) {
dispatchPrecondition(condition: .onQueue(dispatchQueue))
- if let urlError = error as? URLError {
- switch urlError.code {
- case .cancelled:
- finish(result: .failure(OperationError.cancelled))
- return
-
- case .notConnectedToInternet, .internationalRoamingOff, .callIsActive:
- break
-
- default:
- if !REST.isStagingEnvironment {
- _ = addressCacheStore.selectNextEndpoint(endpoint)
- transportStrategy.didFail()
- }
- }
+ if case URLError.cancelled = error {
+ finish(result: .failure(OperationError.cancelled))
+ } else {
+ logger.error(
+ error: error,
+ message: "Failed to perform request to \(endpoint) using \(transport.name)."
+ )
+ retryRequest(with: error)
}
-
- logger.error(
- error: error,
- message: "Failed to perform request to \(endpoint) using \(transport.name)."
- )
-
- retryRequest(with: error)
}
private func didReceiveURLResponse(
_ response: HTTPURLResponse,
- transport: RESTTransport,
data: Data,
endpoint: AnyIPEndpoint
) {
diff --git a/ios/MullvadREST/RESTProxy.swift b/ios/MullvadREST/RESTProxy.swift
index b252d2e33f..5c8a14df81 100644
--- a/ios/MullvadREST/RESTProxy.swift
+++ b/ios/MullvadREST/RESTProxy.swift
@@ -67,11 +67,11 @@ extension REST {
}
public class ProxyConfiguration {
- public let transportProvider: () -> RESTTransportProvider?
+ public let transportProvider: () -> RESTTransport?
public let addressCacheStore: AddressCache
public init(
- transportProvider: @escaping () -> RESTTransportProvider?,
+ transportProvider: @escaping () -> RESTTransport?,
addressCacheStore: AddressCache
) {
self.transportProvider = transportProvider
diff --git a/ios/MullvadREST/RESTProxyFactory.swift b/ios/MullvadREST/RESTProxyFactory.swift
index 8d2bba41d3..6bc793a722 100644
--- a/ios/MullvadREST/RESTProxyFactory.swift
+++ b/ios/MullvadREST/RESTProxyFactory.swift
@@ -13,7 +13,7 @@ extension REST {
public let configuration: AuthProxyConfiguration
public class func makeProxyFactory(
- transportProvider: @escaping () -> RESTTransportProvider?,
+ transportProvider: @escaping () -> RESTTransport?,
addressCache: AddressCache
) -> ProxyFactory {
let basicConfiguration = REST.ProxyConfiguration(
diff --git a/ios/MullvadREST/RESTTransport.swift b/ios/MullvadREST/RESTTransport.swift
index 8b6854c486..54b5e561d6 100644
--- a/ios/MullvadREST/RESTTransport.swift
+++ b/ios/MullvadREST/RESTTransport.swift
@@ -16,13 +16,3 @@ public protocol RESTTransport {
completion: @escaping (Data?, URLResponse?, Error?) -> Void
) -> Cancellable
}
-
-public protocol RESTTransportProvider {
- /// Requests a new transport
- /// - Returns: A transport layer
- func transport() -> RESTTransport?
-
- /// Requests a Shadowsocks transport
- /// - Returns: A transport layer that proxies the requests to a local Shadowsocks proxy instance
- func shadowsocksTransport() -> RESTTransport?
-}
diff --git a/ios/MullvadREST/RESTTransportStrategy.swift b/ios/MullvadREST/RESTTransportStrategy.swift
index c04384a552..114fe12f64 100644
--- a/ios/MullvadREST/RESTTransportStrategy.swift
+++ b/ios/MullvadREST/RESTTransportStrategy.swift
@@ -8,7 +8,7 @@
import Foundation
-public struct TransportStrategy: Codable {
+public struct TransportStrategy: Codable, Equatable {
/// The different transports suggested by the strategy
public enum Transport {
/// Suggests using a direct connection
@@ -21,7 +21,9 @@ public struct TransportStrategy: Codable {
///
/// A value of `0` means a direct transport suggestion, a value of `1` or `2` means a Shadowsocks transport
/// suggestion.
- private var connectionAttempts: UInt
+ ///
+ /// `internal` instead of `private` for testing purposes.
+ internal var connectionAttempts: UInt
public init() {
connectionAttempts = 0
@@ -31,9 +33,9 @@ public struct TransportStrategy: Codable {
///
/// Every third failure results in a direct transport suggestion.
public mutating func didFail() {
- connectionAttempts += 1
- // Avoid overflowing by resetting back to 0 every 3rd failure
- connectionAttempts = connectionAttempts.isMultiple(of: 3) ? 0 : connectionAttempts
+ let (partial, isOverflow) = connectionAttempts.addingReportingOverflow(1)
+ // UInt.max is a multiple of 3, go directly to 1 when overflowing
+ connectionAttempts = isOverflow ? 1 : partial
}
/// The suggested connection transport
diff --git a/ios/MullvadRESTTests/TransportStrategyTests.swift b/ios/MullvadRESTTests/TransportStrategyTests.swift
index 31eb449d2f..7767762a3f 100644
--- a/ios/MullvadRESTTests/TransportStrategyTests.swift
+++ b/ios/MullvadRESTTests/TransportStrategyTests.swift
@@ -6,19 +6,19 @@
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
//
-import MullvadREST
+@testable import MullvadREST
import XCTest
final class TransportStrategyTests: XCTestCase {
func testEveryThirdConnectionAttemptsIsDirect() {
+ loopStrategyTest(with: TransportStrategy())
+ }
+
+ func testOverflowingConnectionAttempts() {
var strategy = TransportStrategy()
+ strategy.connectionAttempts = UInt.max
- for index in 0 ... 12 {
- let expectedResult: TransportStrategy.Transport
- expectedResult = index.isMultiple(of: 3) ? .useURLSession : .useShadowsocks
- XCTAssertEqual(strategy.connectionTransport(), expectedResult)
- strategy.didFail()
- }
+ loopStrategyTest(with: strategy)
}
func testLoadingFromCacheDoesNotImpactStrategy() throws {
@@ -37,4 +37,15 @@ final class TransportStrategyTests: XCTestCase {
reloadedStrategy.didFail()
XCTAssertEqual(reloadedStrategy.connectionTransport(), .useURLSession)
}
+
+ private func loopStrategyTest(with strategy: TransportStrategy) {
+ var strategy = strategy
+
+ for index in 0 ... 12 {
+ let expectedResult: TransportStrategy.Transport
+ expectedResult = index.isMultiple(of: 3) ? .useURLSession : .useShadowsocks
+ XCTAssertEqual(strategy.connectionTransport(), expectedResult)
+ strategy.didFail()
+ }
+ }
}
diff --git a/ios/MullvadTransport/TransportProvider.swift b/ios/MullvadTransport/TransportProvider.swift
index 786f34a2b2..cb24300153 100644
--- a/ios/MullvadTransport/TransportProvider.swift
+++ b/ios/MullvadTransport/TransportProvider.swift
@@ -13,30 +13,36 @@ import MullvadTypes
import RelayCache
import RelaySelector
-public final class TransportProvider: RESTTransportProvider {
+public final class TransportProvider: RESTTransport {
private let urlSessionTransport: URLSessionTransport
private let relayCache: RelayCache
private let logger = Logger(label: "TransportProvider")
private let addressCache: REST.AddressCache
private let shadowsocksCache: ShadowsocksConfigurationCache
+ private var transportStrategy: TransportStrategy
+
+ private var currentTransport: RESTTransport?
+ private let parallelRequestsMutex = NSLock()
public init(
urlSessionTransport: URLSessionTransport,
relayCache: RelayCache,
addressCache: REST.AddressCache,
- shadowsocksCache: ShadowsocksConfigurationCache
+ shadowsocksCache: ShadowsocksConfigurationCache,
+ transportStrategy: TransportStrategy = .init()
) {
self.urlSessionTransport = urlSessionTransport
self.relayCache = relayCache
self.addressCache = addressCache
self.shadowsocksCache = shadowsocksCache
+ self.transportStrategy = transportStrategy
}
- public func transport() -> RESTTransport? {
- urlSessionTransport
- }
+ // MARK: -
+
+ // MARK: RESTTransport implementation
- public func shadowsocksTransport() -> RESTTransport? {
+ private func shadowsocks() -> RESTTransport? {
do {
let shadowsocksConfiguration = try shadowsocksConfiguration()
@@ -57,8 +63,6 @@ public final class TransportProvider: RESTTransportProvider {
/// Returns the last used shadowsocks configuration, otherwise a new randomized configuration.
private func shadowsocksConfiguration() throws -> ShadowsocksConfiguration {
// If a previous shadowsocks configuration was in cache, return it directly.
- // There is no previous configuration either if this is the first time this code ran
- // Or because the previous shadowsocks configuration was invalid, therefore generate a new one.
do {
return try shadowsocksCache.read()
} catch {
@@ -91,4 +95,84 @@ public final class TransportProvider: RESTTransportProvider {
return newConfiguration
}
+
+ // MARK: -
+
+ // MARK: RESTTransport implementation
+
+ public var name: String { currentTransport?.name ?? "TransportProvider" }
+
+ public func sendRequest(
+ _ request: URLRequest,
+ completion: @escaping (Data?, URLResponse?, Error?) -> Void
+ ) -> Cancellable {
+ parallelRequestsMutex.lock()
+ defer {
+ parallelRequestsMutex.unlock()
+ }
+
+ let currentStrategy = transportStrategy
+ guard let transport = makeTransport() else { return AnyCancellable() }
+
+ let failureCompletionHandler: (Data?, URLResponse?, Error?)
+ -> Void = { [weak self] data, response, error in
+ guard let self else { return }
+
+ if let error = error as? URLError, error.shouldResetNetworkTransport {
+ resetTransportMatching(currentStrategy)
+ }
+ completion(data, response, error)
+ }
+
+ return transport.sendRequest(request, completion: failureCompletionHandler)
+ }
+
+ /// When several requests fail at the same time, prevents the `transportStrategy` from switching multiple times.
+ ///
+ /// The `strategy` is checked against the `transportStrategy`. When several requests are made and fail in parallel,
+ /// only the first failure will pass the equality check.
+ /// Subsequent failures will not cause the strategy to change several times in a quick fashion.
+ /// - Parameter strategy: The strategy object used when sending a request
+ private func resetTransportMatching(_ strategy: TransportStrategy) {
+ parallelRequestsMutex.lock()
+ defer { parallelRequestsMutex.unlock() }
+
+ if strategy == transportStrategy {
+ transportStrategy.didFail()
+ currentTransport = nil
+ }
+ }
+
+ /// Sets and returns the `currentTransport` according to the suggestion from `transportStrategy`
+ ///
+ /// > Warning: Do not lock the `parallelRequestsMutex` in this method
+ ///
+ /// - Returns: A `RESTTransport` object to make a connection
+ private func makeTransport() -> RESTTransport? {
+ if currentTransport == nil {
+ switch transportStrategy.connectionTransport() {
+ case .useShadowsocks:
+ currentTransport = shadowsocks()
+ case .useURLSession:
+ currentTransport = urlSessionTransport
+ }
+ }
+ return currentTransport
+ }
+}
+
+private extension URLError {
+ /// Whether the transport selection should be reset.
+ ///
+ /// `true` if the network request
+ /// * Was not cancelled
+ /// * Was not done during a phone call
+ /// * Was made when internet connection was available
+ /// * Was made in a context with data roaming, but international roaming was turned off
+ var shouldResetNetworkTransport: Bool {
+ code != .cancelled &&
+ code != .notConnectedToInternet &&
+ code != .internationalRoamingOff &&
+ code != .callIsActive
+ }
}
diff --git a/ios/MullvadTransport/shadowsocks-proxy/build.sh b/ios/MullvadTransport/shadowsocks-proxy/build.sh
index 7617bc91c8..2a39185a14 100644
--- a/ios/MullvadTransport/shadowsocks-proxy/build.sh
+++ b/ios/MullvadTransport/shadowsocks-proxy/build.sh
@@ -1,5 +1,7 @@
#!/usr/bin/env bash
+set -euvx
+
if [ "$#" -ne 1 ]
then
echo "Usage (note: only call inside xcode!):"
@@ -11,12 +13,10 @@ fi
FFI_TARGET=$1
RELFLAG=
-if [[ "$CONFIGURATION" -eq "Release" ]]; then
+if [[ "$CONFIGURATION" == "Release" ]]; then
RELFLAG=--release
fi
-set -euvx
-
if [[ -n "${DEVELOPER_SDK_DIR:-}" ]]; then
# Assume we're in Xcode, which means we're probably cross-compiling.
# In this case, we need to add an extra library search path for build scripts and proc-macros,
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index 1b9482ee7b..4a248cc5d1 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -398,7 +398,6 @@
A97F1F442A1F4E1A00ECEFDE /* MullvadTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = A97F1F432A1F4E1A00ECEFDE /* MullvadTransport.h */; settings = {ATTRIBUTES = (Public, ); }; };
A97F1F472A1F4E1A00ECEFDE /* MullvadTransport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A97F1F412A1F4E1A00ECEFDE /* MullvadTransport.framework */; };
A97F1F482A1F4E1A00ECEFDE /* MullvadTransport.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A97F1F412A1F4E1A00ECEFDE /* MullvadTransport.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
- A97FF54B2A0B7AD000900996 /* SimulatorTunnelTransportProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97FF54A2A0B7AD000900996 /* SimulatorTunnelTransportProvider.swift */; };
A97FF5502A0D2FFC00900996 /* NSFileCoordinator+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97FF54F2A0D2FFC00900996 /* NSFileCoordinator+Extensions.swift */; };
A9A8A8EB2A262AB30086D569 /* FileCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A8A8EA2A262AB30086D569 /* FileCache.swift */; };
A9B2CF722A1F64CD0013CC6C /* MullvadREST.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06799ABC28F98E1D00ACD94E /* MullvadREST.framework */; };
@@ -1130,7 +1129,6 @@
A9467E8A2A2E0317000DC21F /* ShadowsocksConfigurationCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowsocksConfigurationCache.swift; sourceTree = "<group>"; };
A97F1F412A1F4E1A00ECEFDE /* MullvadTransport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MullvadTransport.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A97F1F432A1F4E1A00ECEFDE /* MullvadTransport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MullvadTransport.h; sourceTree = "<group>"; };
- A97FF54A2A0B7AD000900996 /* SimulatorTunnelTransportProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimulatorTunnelTransportProvider.swift; sourceTree = "<group>"; };
A97FF54F2A0D2FFC00900996 /* NSFileCoordinator+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSFileCoordinator+Extensions.swift"; sourceTree = "<group>"; };
A9A8A8EA2A262AB30086D569 /* FileCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileCache.swift; sourceTree = "<group>"; };
A9CF11FC2A0518E7001D9565 /* AddressCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressCacheTests.swift; sourceTree = "<group>"; };
@@ -1672,7 +1670,6 @@
children = (
58BA693023EADA6A009DC256 /* SimulatorTunnelProvider.swift */,
587A01FB23F1F0BE00B68763 /* SimulatorTunnelProviderHost.swift */,
- A97FF54A2A0B7AD000900996 /* SimulatorTunnelTransportProvider.swift */,
);
path = SimulatorTunnelProvider;
sourceTree = "<group>";
@@ -2982,7 +2979,6 @@
587C93002986E2B600FB9664 /* TermsOfServiceCoordinator.swift in Sources */,
5864AF0929C78850005B0CD9 /* PreferencesCellFactory.swift in Sources */,
587B7536266528A200DEF7E9 /* NotificationManager.swift in Sources */,
- A97FF54B2A0B7AD000900996 /* SimulatorTunnelTransportProvider.swift in Sources */,
5820EDA9288FE064006BF4E4 /* DeviceManagementInteractor.swift in Sources */,
58FB865A26EA214400F188BC /* RelayCacheTrackerObserver.swift in Sources */,
58ACF64D26567A5000ACE4B7 /* CustomSwitch.swift in Sources */,
diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift
index bc2772ee83..b347d080d1 100644
--- a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift
+++ b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift
@@ -22,7 +22,6 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate {
private var selectorResult: RelaySelectorResult?
private let urlRequestProxy: URLRequestProxy
private let relayCacheTracker: RelayCacheTracker
- private let simulatorTransportProvider: SimulatorTunnelTransportProvider
private let providerLogger = Logger(label: "SimulatorTunnelProviderHost")
private let dispatchQueue = DispatchQueue(label: "SimulatorTunnelProviderHostQueue")
@@ -32,12 +31,10 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate {
let urlSession = REST.makeURLSession()
let urlSessionTransport = URLSessionTransport(urlSession: urlSession)
- let simulatorTransportProvider = SimulatorTunnelTransportProvider(urlSessionTransport: urlSessionTransport)
- self.simulatorTransportProvider = simulatorTransportProvider
self.urlRequestProxy = URLRequestProxy(
dispatchQueue: dispatchQueue,
- transportProvider: { simulatorTransportProvider }
+ transportProvider: { urlSessionTransport }
)
}
diff --git a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelTransportProvider.swift b/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelTransportProvider.swift
deleted file mode 100644
index 87f5cf62e8..0000000000
--- a/ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelTransportProvider.swift
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-// SimulatorTunnelTransportProvider.swift
-// MullvadVPN
-//
-// Created by Marco Nikic on 2023-05-10.
-// Copyright © 2023 Mullvad VPN AB. All rights reserved.
-//
-
-import Foundation
-import MullvadREST
-import MullvadTransport
-
-final class SimulatorTunnelTransportProvider: RESTTransportProvider {
- private let urlSessionTransport: URLSessionTransport
-
- init(urlSessionTransport: URLSessionTransport) {
- self.urlSessionTransport = urlSessionTransport
- }
-
- func transport() -> RESTTransport? {
- urlSessionTransport
- }
-
- func shadowsocksTransport() -> RESTTransport? {
- urlSessionTransport
- }
-}
diff --git a/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift b/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift
index ebb0acefb0..b1c3fea1e7 100644
--- a/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift
+++ b/ios/MullvadVPN/TransportMonitor/PacketTunnelTransport.swift
@@ -19,11 +19,9 @@ struct PacketTunnelTransport: RESTTransport {
}
let tunnel: Tunnel
- let useShadowsocksTransport: Bool
- init(tunnel: Tunnel, useShadowsocksTransport: Bool) {
+ init(tunnel: Tunnel) {
self.tunnel = tunnel
- self.useShadowsocksTransport = useShadowsocksTransport
}
func sendRequest(
@@ -32,8 +30,7 @@ struct PacketTunnelTransport: RESTTransport {
) -> Cancellable {
let proxyRequest = ProxyURLRequest(
id: UUID(),
- urlRequest: request,
- useShadowsocksTransport: useShadowsocksTransport
+ urlRequest: request
)
// If the URL provided to the proxy request was invalid, indicate failure via `.badURL` and return a no-op.
diff --git a/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift b/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift
index ebc24913b2..395b4e1eaf 100644
--- a/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift
+++ b/ios/MullvadVPN/TransportMonitor/TransportMonitor.swift
@@ -10,10 +10,11 @@ import Foundation
import MullvadLogging
import MullvadREST
import MullvadTransport
+import MullvadTypes
import RelayCache
import RelaySelector
-final class TransportMonitor: RESTTransportProvider {
+final class TransportMonitor: RESTTransport {
private let tunnelManager: TunnelManager
private let tunnelStore: TunnelStore
private let transportProvider: TransportProvider
@@ -28,12 +29,11 @@ final class TransportMonitor: RESTTransportProvider {
self.transportProvider = transportProvider
}
- public func transport() -> RESTTransport? {
- return selectTransport(transportProvider.transport(), useShadowsocksTransport: false)
- }
+ var name: String { selectTransport(transportProvider).name }
- public func shadowsocksTransport() -> RESTTransport? {
- return selectTransport(transportProvider.shadowsocksTransport(), useShadowsocksTransport: true)
+ func sendRequest(_ request: URLRequest, completion: @escaping (Data?, URLResponse?, Error?) -> Void) -> Cancellable
+ {
+ selectTransport(transportProvider).sendRequest(request, completion: completion)
}
// MARK: -
@@ -48,10 +48,8 @@ final class TransportMonitor: RESTTransportProvider {
///
/// - Parameters:
/// - transport: The transport to use if there is no tunnel, or if it shouldn't be bypassed
- /// - useShadowsocksTransport: A hint for enforcing a Shadowsocks transport when proxying a request via an
- /// available `Tunnel`
/// - Returns: A transport to use for sending an `URLRequest`
- private func selectTransport(_ transport: RESTTransport?, useShadowsocksTransport: Bool) -> RESTTransport? {
+ private func selectTransport(_ transport: RESTTransport) -> RESTTransport {
let tunnel = tunnelStore.getPersistentTunnels().first { tunnel in
return tunnel.status == .connecting ||
tunnel.status == .reasserting ||
@@ -60,8 +58,7 @@ final class TransportMonitor: RESTTransportProvider {
if let tunnel, shouldByPassVPN(tunnel: tunnel) {
return PacketTunnelTransport(
- tunnel: tunnel,
- useShadowsocksTransport: useShadowsocksTransport
+ tunnel: tunnel
)
}
return transport
diff --git a/ios/RelaySelector/RelaySelector.swift b/ios/RelaySelector/RelaySelector.swift
index 956461751b..8c9c7a6915 100644
--- a/ios/RelaySelector/RelaySelector.swift
+++ b/ios/RelaySelector/RelaySelector.swift
@@ -21,10 +21,12 @@ public enum RelaySelector {
}
/// Return a random Shadowsocks bridge relay, or `nil` if no relay were found.
+ ///
+ /// Non `active` relays are filtered out.
/// - Parameter relays: The list of relays to randomly select from
/// - Returns: A Shadowsocks relay or `nil` if no relay were found.
public static func getShadowsocksRelay(relays: REST.ServerRelaysResponse) -> REST.BridgeRelay? {
- relays.bridge.relays.randomElement()
+ relays.bridge.relays.filter { $0.active }.randomElement()
}
/**
diff --git a/ios/TunnelProviderMessaging/ProxyURLRequest.swift b/ios/TunnelProviderMessaging/ProxyURLRequest.swift
index cf392eee12..4ff7bd72eb 100644
--- a/ios/TunnelProviderMessaging/ProxyURLRequest.swift
+++ b/ios/TunnelProviderMessaging/ProxyURLRequest.swift
@@ -15,7 +15,6 @@ public struct ProxyURLRequest: Codable {
public let method: String?
public let httpBody: Data?
public let httpHeaders: [String: String]?
- public let useShadowsocksTransport: Bool
public var urlRequest: URLRequest {
var urlRequest = URLRequest(url: url)
@@ -25,7 +24,7 @@ public struct ProxyURLRequest: Codable {
return urlRequest
}
- public init?(id: UUID, urlRequest: URLRequest, useShadowsocksTransport: Bool = false) {
+ public init?(id: UUID, urlRequest: URLRequest) {
guard let urlRequestUrl = urlRequest.url else { return nil }
self.id = id
@@ -33,6 +32,5 @@ public struct ProxyURLRequest: Codable {
method = urlRequest.httpMethod
httpBody = urlRequest.httpBody
httpHeaders = urlRequest.allHTTPHeaderFields
- self.useShadowsocksTransport = useShadowsocksTransport
}
}
diff --git a/ios/TunnelProviderMessaging/URLRequestProxy.swift b/ios/TunnelProviderMessaging/URLRequestProxy.swift
index defa7822e4..7fe2e060cf 100644
--- a/ios/TunnelProviderMessaging/URLRequestProxy.swift
+++ b/ios/TunnelProviderMessaging/URLRequestProxy.swift
@@ -15,14 +15,14 @@ public final class URLRequestProxy {
/// Serial queue used for synchronizing access to class members.
private let dispatchQueue: DispatchQueue
- private let transportProvider: () -> RESTTransportProvider?
+ private let transportProvider: () -> RESTTransport?
/// List of all proxied network requests bypassing VPN.
private var proxiedRequests: [UUID: Cancellable] = [:]
public init(
dispatchQueue: DispatchQueue,
- transportProvider: @escaping () -> RESTTransportProvider?
+ transportProvider: @escaping () -> RESTTransport?
) {
self.dispatchQueue = dispatchQueue
self.transportProvider = transportProvider
@@ -33,14 +33,9 @@ public final class URLRequestProxy {
completionHandler: @escaping (ProxyURLResponse) -> Void
) {
dispatchQueue.async {
- // Instruct the Packet Tunnel to try to reach the API via the local shadow socks proxy instance if needed
- let transportProvider = self.transportProvider()
- let transport = proxyRequest.useShadowsocksTransport
- ? transportProvider?.shadowsocksTransport()
- : transportProvider?.transport()
- guard let transport else { return }
+ guard let transportProvider = self.transportProvider() else { return }
// The task sent by `transport.sendRequest` comes in an already resumed state
- let task = transport.sendRequest(proxyRequest.urlRequest) { [weak self] data, response, error in
+ let task = transportProvider.sendRequest(proxyRequest.urlRequest) { [weak self] data, response, error in
guard let self else { return }
// However there is no guarantee about which queue the execution resumes on
// Use `dispatchQueue` to guarantee thread safe access to `proxiedRequests`