-
Notifications
You must be signed in to change notification settings - Fork 389
/
Copy pathTunnel+Messaging.swift
129 lines (109 loc) · 4.13 KB
/
Tunnel+Messaging.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//
// Tunnel+Messaging.swift
// MullvadVPN
//
// Created by pronebird on 16/09/2021.
// Copyright © 2021 Mullvad VPN AB. All rights reserved.
//
import Foundation
import MullvadREST
import MullvadTypes
import Operations
import PacketTunnelCore
/// Shared operation queue used for IPC requests.
private let operationQueue = AsyncOperationQueue()
/// Shared queue used by IPC operations.
private let dispatchQueue = DispatchQueue(label: "Tunnel.dispatchQueue")
/// Timeout for proxy requests.
private let proxyRequestTimeout = REST.defaultAPINetworkTimeout + 2
extension TunnelProtocol {
/// Request packet tunnel process to reconnect the tunnel with the given relays.
func reconnectTunnel(
to nextRelays: NextRelays,
completionHandler: @escaping (Result<Void, Error>) -> Void
) -> Cancellable {
let operation = SendTunnelProviderMessageOperation(
dispatchQueue: dispatchQueue,
backgroundTaskProvider: backgroundTaskProvider,
tunnel: self,
message: .reconnectTunnel(nextRelays),
decoderHandler: { _ in () },
completionHandler: completionHandler
)
operationQueue.addOperation(operation)
return operation
}
/// Request status from packet tunnel process.
func getTunnelStatus(
completionHandler: @escaping (Result<ObservedState, Error>) -> Void
) -> Cancellable {
let decoderHandler: (Data?) throws -> ObservedState = { data in
if let data {
return try TunnelProviderReply<ObservedState>(messageData: data).value
} else {
throw EmptyTunnelProviderResponseError()
}
}
let operation = SendTunnelProviderMessageOperation(
dispatchQueue: dispatchQueue,
backgroundTaskProvider: backgroundTaskProvider,
tunnel: self,
message: .getTunnelStatus,
decoderHandler: decoderHandler,
completionHandler: completionHandler
)
operationQueue.addOperation(operation)
return operation
}
/// Send HTTP request via packet tunnel process bypassing VPN.
func sendRequest(
_ proxyRequest: ProxyURLRequest,
completionHandler: @escaping (Result<ProxyURLResponse, Error>) -> Void
) -> Cancellable {
let decoderHandler: (Data?) throws -> ProxyURLResponse = { data in
if let data {
return try TunnelProviderReply<ProxyURLResponse>(messageData: data).value
} else {
throw EmptyTunnelProviderResponseError()
}
}
let operation = SendTunnelProviderMessageOperation(
dispatchQueue: dispatchQueue,
backgroundTaskProvider: backgroundTaskProvider,
tunnel: self,
message: .sendURLRequest(proxyRequest),
timeout: proxyRequestTimeout,
decoderHandler: decoderHandler,
completionHandler: completionHandler
)
operation.onCancel { [weak self] _ in
guard let self else { return }
let cancelOperation = SendTunnelProviderMessageOperation(
dispatchQueue: dispatchQueue,
backgroundTaskProvider: backgroundTaskProvider,
tunnel: self,
message: .cancelURLRequest(proxyRequest.id),
decoderHandler: decoderHandler,
completionHandler: nil
)
operationQueue.addOperation(cancelOperation)
}
operationQueue.addOperation(operation)
return operation
}
/// Notify tunnel about private key rotation.
func notifyKeyRotation(
completionHandler: @escaping (Result<Void, Error>) -> Void
) -> Cancellable {
let operation = SendTunnelProviderMessageOperation(
dispatchQueue: dispatchQueue,
backgroundTaskProvider: backgroundTaskProvider,
tunnel: self,
message: .privateKeyRotation,
decoderHandler: { _ in () },
completionHandler: completionHandler
)
operationQueue.addOperation(operation)
return operation
}
}