diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2019-12-03 16:34:09 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2019-12-03 16:34:09 +0100 |
| commit | 62550b67880da2ffdca33d6dd35c1caeada51b75 (patch) | |
| tree | b72d89228bd71d4d06b8d6f7f48a2558199d38cc | |
| parent | f76cd5763dee647ea811c074113d7ab670b4f93d (diff) | |
| parent | 84d7504d7b83f4249919a05f480bb52b14d95d8c (diff) | |
| download | mullvadvpn-62550b67880da2ffdca33d6dd35c1caeada51b75.tar.xz mullvadvpn-62550b67880da2ffdca33d6dd35c1caeada51b75.zip | |
Merge branch 'packet-tunnel-ipc'
| -rw-r--r-- | ios/MullvadVPN/PacketTunnelIpc.swift | 147 | ||||
| -rw-r--r-- | ios/MullvadVPN/ReplaceNilWithError.swift | 24 |
2 files changed, 171 insertions, 0 deletions
diff --git a/ios/MullvadVPN/PacketTunnelIpc.swift b/ios/MullvadVPN/PacketTunnelIpc.swift new file mode 100644 index 0000000000..4da14d4051 --- /dev/null +++ b/ios/MullvadVPN/PacketTunnelIpc.swift @@ -0,0 +1,147 @@ +// +// PacketTunnelIpc.swift +// MullvadVPN +// +// Created by pronebird on 01/11/2019. +// Copyright © 2019 Amagicom AB. All rights reserved. +// + +import Combine +import Foundation +import NetworkExtension + +/// A enum describing the kinds of requests that `PacketTunnelProvider` handles +enum PacketTunnelRequest: Int, Codable { + /// Request the tunnel to reload the configuration + case reloadConfiguration + + /// Request the tunnel to return the connection information + case tunnelInformation +} + +enum PacketTunnelIpcError: Error { + /// A failure to encode the request + case encoding(Error) + + /// A failure to decode the response + case decoding(Error) + + /// A failure to send the IPC request + case send(Error) + + /// A failure that's raised when the IPC response does not contain any data however the decoder + /// expected to receive data for decoding + case nilResponse + + var localizedDescription: String { + switch self { + case .encoding(let error): + return "Encoding failure: \(error.localizedDescription)" + case .decoding(let error): + return "Decoding failure: \(error.localizedDescription)" + case .send(let error): + return "Submission failure: \(error.localizedDescription)" + case .nilResponse: + return "Unexpected nil response from the tunnel" + } + } +} + +/// A struct that holds the basic information regarding the tunnel connection +struct TunnelConnectionInfo: Codable, Equatable { + let ipv4Relay: String + let ipv6Relay: String? + let hostname: String +} + +extension TunnelConnectionInfo: CustomDebugStringConvertible { + var debugDescription: String { + return "{ ipv4Relay: \(String(reflecting: ipv4Relay)), " + + "ipv6Relay: \(String(reflecting: ipv6Relay)), " + + "hostname: \(String(reflecting: hostname)) }" + } +} + +enum PacketTunnelIpcHandlerError: Error { + /// A failure to encode the request + case encoding(Error) + + /// A failure to decode the response + case decoding(Error) + + /// A failure to process the request + case processing(Error) +} + +enum PacketTunnelIpcHandler {} + +extension PacketTunnelIpcHandler { + + static func decodeRequest(messageData: Data) -> AnyPublisher<PacketTunnelRequest, PacketTunnelIpcHandlerError> { + return Just(messageData) + .setFailureType(to: PacketTunnelIpcHandlerError.self) + .decode(type: PacketTunnelRequest.self, decoder: JSONDecoder()) + .mapError { PacketTunnelIpcHandlerError.decoding($0) } + .eraseToAnyPublisher() + } + + static func encodeResponse<T>(response: T) -> AnyPublisher<Data, PacketTunnelIpcHandlerError> where T: Encodable { + return Just(response) + .setFailureType(to: PacketTunnelIpcHandlerError.self) + .encode(encoder: JSONEncoder()) + .mapError { PacketTunnelIpcHandlerError.encoding($0) } + .eraseToAnyPublisher() + } +} + +class PacketTunnelIpc { + let session: NETunnelProviderSession + + init(session: NETunnelProviderSession) { + self.session = session + } + + func reloadConfiguration() -> AnyPublisher<(), PacketTunnelIpcError> { + return send(message: .reloadConfiguration) + } + + func getTunnelInformation() -> AnyPublisher<TunnelConnectionInfo, PacketTunnelIpcError> { + return send(message: .tunnelInformation) + } + + private func send(message: PacketTunnelRequest) -> AnyPublisher<(), PacketTunnelIpcError> { + return sendWithoutDecoding(message: message) + .map { _ in () }.eraseToAnyPublisher() + } + + private func send<T>(message: PacketTunnelRequest) -> AnyPublisher<T, PacketTunnelIpcError> where T: Decodable { + return sendWithoutDecoding(message: message) + .replaceNil(with: .nilResponse) + .decode(type: T.self, decoder: JSONDecoder()) + .mapError { PacketTunnelIpcError.decoding($0) } + .eraseToAnyPublisher() + } + + private func sendWithoutDecoding(message: PacketTunnelRequest) -> AnyPublisher<Data?, PacketTunnelIpcError> { + return Just(message) + .setFailureType(to: PacketTunnelIpcError.self) + .encode(encoder: JSONEncoder()) + .mapError { PacketTunnelIpcError.encoding($0) } + .flatMap(self.sendProviderMessage) + .mapError { PacketTunnelIpcError.send($0) } + .eraseToAnyPublisher() + } + + private func sendProviderMessage(_ messageData: Data) -> Future<Data?, Error> { + return Future { (fulfill) in + do { + try self.session.sendProviderMessage(messageData, responseHandler: { (response) in + fulfill(.success(response)) + }) + } catch { + fulfill(.failure(error)) + } + } + } + +} diff --git a/ios/MullvadVPN/ReplaceNilWithError.swift b/ios/MullvadVPN/ReplaceNilWithError.swift new file mode 100644 index 0000000000..4097b007f0 --- /dev/null +++ b/ios/MullvadVPN/ReplaceNilWithError.swift @@ -0,0 +1,24 @@ +// +// ReplaceNilWithError.swift +// MullvadVPN +// +// Created by pronebird on 19/11/2019. +// Copyright © 2019 Amagicom AB. All rights reserved. +// + +import Combine +import Foundation + +extension Publisher { + + /// Replace nil elements with the provided error + func replaceNil<T>(with error: Failure) -> Publishers.FlatMap<Result<T, Failure>.Publisher, Self> + where Output == T?, Failure: Error { + return flatMap { (output: T?) -> Result<T, Failure>.Publisher in + let result: Result<T, Failure> = output.flatMap { .success($0) } ?? .failure(error) + + return result.publisher + } + } + +} |
