@desklink/host 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -17
- package/dist/engineProcess.d.ts +5 -0
- package/dist/engineProcess.d.ts.map +1 -1
- package/dist/engineProcess.js +5 -3
- package/dist/engineProcess.js.map +1 -1
- package/engine/Cargo.lock +6 -8
- package/engine/Cargo.toml +13 -1
- package/engine/src/clipboard.rs +0 -34
- package/engine/src/convert.rs +0 -170
- package/engine/src/cursor.rs +0 -23
- package/engine/src/input.rs +0 -65
- package/engine/src/input_mac.rs +0 -11
- package/engine/src/keeper.rs +0 -137
- package/engine/src/keymap.rs +0 -107
- package/engine/src/keymap_mac.rs +0 -25
- package/engine/src/mac.rs +0 -28
- package/engine/src/peer.rs +224 -0
- package/engine/src/portal.rs +0 -18
- package/engine/src/protocol.rs +0 -162
- package/engine/src/x11.rs +0 -13
- package/engine/vendor/rtc-ice/Cargo.toml +137 -0
- package/engine/vendor/rtc-ice/DESKLINK-PATCH.md +59 -0
- package/engine/vendor/rtc-ice/LICENSE-APACHE +201 -0
- package/engine/vendor/rtc-ice/LICENSE-MIT +21 -0
- package/engine/vendor/rtc-ice/README.md +30 -0
- package/engine/vendor/rtc-ice/examples/ping_pong.rs +376 -0
- package/engine/vendor/rtc-ice/src/agent/agent_config.rs +126 -0
- package/engine/vendor/rtc-ice/src/agent/agent_proto.rs +172 -0
- package/engine/vendor/rtc-ice/src/agent/agent_selector.rs +566 -0
- package/engine/vendor/rtc-ice/src/agent/agent_stats.rs +292 -0
- package/engine/vendor/rtc-ice/src/agent/agent_test.rs +3388 -0
- package/engine/vendor/rtc-ice/src/agent/mod.rs +1662 -0
- package/engine/vendor/rtc-ice/src/attributes/control/control_test.rs +168 -0
- package/engine/vendor/rtc-ice/src/attributes/control/mod.rs +142 -0
- package/engine/vendor/rtc-ice/src/attributes/mod.rs +6 -0
- package/engine/vendor/rtc-ice/src/attributes/priority/mod.rs +37 -0
- package/engine/vendor/rtc-ice/src/attributes/priority/priority_test.rs +39 -0
- package/engine/vendor/rtc-ice/src/attributes/use_candidate/mod.rs +33 -0
- package/engine/vendor/rtc-ice/src/attributes/use_candidate/use_candidate_test.rs +19 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_host.rs +53 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_pair.rs +215 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_pair_test.rs +201 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_peer_reflexive.rs +49 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_relay.rs +53 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_relay_test.rs +114 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive.rs +53 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive_test.rs +91 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_test.rs +540 -0
- package/engine/vendor/rtc-ice/src/candidate/mod.rs +679 -0
- package/engine/vendor/rtc-ice/src/lib.rs +85 -0
- package/engine/vendor/rtc-ice/src/mdns/mdns_test.rs +150 -0
- package/engine/vendor/rtc-ice/src/mdns/mod.rs +69 -0
- package/engine/vendor/rtc-ice/src/network_type/mod.rs +162 -0
- package/engine/vendor/rtc-ice/src/network_type/network_type_test.rs +95 -0
- package/engine/vendor/rtc-ice/src/rand/mod.rs +91 -0
- package/engine/vendor/rtc-ice/src/rand/rand_test.rs +115 -0
- package/engine/vendor/rtc-ice/src/state/mod.rs +106 -0
- package/engine/vendor/rtc-ice/src/state/state_test.rs +46 -0
- package/engine/vendor/rtc-ice/src/stats/mod.rs +166 -0
- package/engine/vendor/rtc-ice/src/tcp_type/mod.rs +47 -0
- package/engine/vendor/rtc-ice/src/tcp_type/tcp_type_test.rs +18 -0
- package/engine/vendor/rtc-ice/src/url/mod.rs +266 -0
- package/engine/vendor/rtc-ice/src/url/url_test.rs +142 -0
- package/package.json +8 -3
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
//! ICE candidates: the addresses an agent can be reached at.
|
|
2
|
+
//!
|
|
3
|
+
//! A [`Candidate`](crate::candidate::Candidate) pairs a transport address with a [`CandidateType`](crate::candidate::CandidateType) — host, server-reflexive,
|
|
4
|
+
//! peer-reflexive or relay — and the bookkeeping ICE needs: a priority, a foundation, and
|
|
5
|
+
//! last-sent/last-received times that feed consent freshness.
|
|
6
|
+
//!
|
|
7
|
+
//! Type drives priority, and priority drives check order: host candidates are tried first
|
|
8
|
+
//! because they need no traversal, relay candidates last because they always cost an extra hop.
|
|
9
|
+
//! The [`foundation`](crate::candidate::Candidate::foundation) groups candidates that share a base and transport,
|
|
10
|
+
//! so redundant checks can be skipped.
|
|
11
|
+
//!
|
|
12
|
+
//! Each type has its own constructor module (`candidate_host`, `candidate_relay`, …), all
|
|
13
|
+
//! built on the shared [`CandidateConfig`](crate::candidate::CandidateConfig).
|
|
14
|
+
|
|
15
|
+
#[cfg(test)]
|
|
16
|
+
mod candidate_pair_test;
|
|
17
|
+
#[cfg(test)]
|
|
18
|
+
mod candidate_test;
|
|
19
|
+
|
|
20
|
+
//TODO: #[cfg(test)]
|
|
21
|
+
//TODO: mod candidate_relay_test;
|
|
22
|
+
/*TODO: #[cfg(test)]
|
|
23
|
+
TODO: mod candidate_server_reflexive_test;
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/// Host candidates: an address on a local interface.
|
|
27
|
+
pub mod candidate_host;
|
|
28
|
+
/// A local/remote candidate pair and its check state.
|
|
29
|
+
pub mod candidate_pair;
|
|
30
|
+
/// Peer-reflexive candidates, learned from an inbound check's source address.
|
|
31
|
+
pub mod candidate_peer_reflexive;
|
|
32
|
+
/// Relay candidates, allocated on a TURN server.
|
|
33
|
+
pub mod candidate_relay;
|
|
34
|
+
/// Server-reflexive candidates, learned from a STUN Binding response.
|
|
35
|
+
pub mod candidate_server_reflexive;
|
|
36
|
+
|
|
37
|
+
use crate::network_type::NetworkType;
|
|
38
|
+
use crate::tcp_type::TcpType;
|
|
39
|
+
use crc::{CRC_32_ISCSI, Crc};
|
|
40
|
+
use serde::{Deserialize, Serialize};
|
|
41
|
+
use shared::error::*;
|
|
42
|
+
use std::fmt;
|
|
43
|
+
use std::net::{IpAddr, SocketAddr};
|
|
44
|
+
use std::time::Instant;
|
|
45
|
+
|
|
46
|
+
use crate::candidate::candidate_host::CandidateHostConfig;
|
|
47
|
+
use crate::candidate::candidate_peer_reflexive::CandidatePeerReflexiveConfig;
|
|
48
|
+
use crate::candidate::candidate_relay::CandidateRelayConfig;
|
|
49
|
+
use crate::candidate::candidate_server_reflexive::CandidateServerReflexiveConfig;
|
|
50
|
+
use crate::network_type::determine_network_type;
|
|
51
|
+
|
|
52
|
+
pub(crate) const RECEIVE_MTU: usize = 8192;
|
|
53
|
+
pub(crate) const DEFAULT_LOCAL_PREFERENCE: u16 = 65535;
|
|
54
|
+
|
|
55
|
+
/// Indicates that the candidate is used for RTP.
|
|
56
|
+
pub(crate) const COMPONENT_RTP: u16 = 1;
|
|
57
|
+
/// Indicates that the candidate is used for RTCP.
|
|
58
|
+
pub(crate) const COMPONENT_RTCP: u16 = 0;
|
|
59
|
+
|
|
60
|
+
/// Represents the type of candidate `CandidateType` enum.
|
|
61
|
+
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
62
|
+
#[non_exhaustive]
|
|
63
|
+
pub enum CandidateType {
|
|
64
|
+
#[default]
|
|
65
|
+
#[serde(rename = "unspecified")]
|
|
66
|
+
/// No candidate type was set.
|
|
67
|
+
Unspecified,
|
|
68
|
+
#[serde(rename = "host")]
|
|
69
|
+
/// An address on one of this host's own interfaces.
|
|
70
|
+
///
|
|
71
|
+
/// Highest priority: reachable without traversal when both peers share a network.
|
|
72
|
+
Host,
|
|
73
|
+
#[serde(rename = "srflx")]
|
|
74
|
+
/// This host's address as seen by a STUN server — its public mapping through the NAT.
|
|
75
|
+
ServerReflexive,
|
|
76
|
+
#[serde(rename = "prflx")]
|
|
77
|
+
/// An address learned from a peer's inbound connectivity check.
|
|
78
|
+
///
|
|
79
|
+
/// Discovered during checking rather than gathering, when a NAT maps a different port per
|
|
80
|
+
/// destination.
|
|
81
|
+
PeerReflexive,
|
|
82
|
+
#[serde(rename = "relay")]
|
|
83
|
+
/// An address allocated on a TURN server, which forwards on this host's behalf.
|
|
84
|
+
///
|
|
85
|
+
/// Lowest priority: it always costs an extra hop.
|
|
86
|
+
Relay,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// String makes CandidateType printable
|
|
90
|
+
impl fmt::Display for CandidateType {
|
|
91
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
92
|
+
let s = match *self {
|
|
93
|
+
CandidateType::Host => "host",
|
|
94
|
+
CandidateType::ServerReflexive => "srflx",
|
|
95
|
+
CandidateType::PeerReflexive => "prflx",
|
|
96
|
+
CandidateType::Relay => "relay",
|
|
97
|
+
CandidateType::Unspecified => "Unknown candidate type",
|
|
98
|
+
};
|
|
99
|
+
write!(f, "{s}")
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
impl CandidateType {
|
|
104
|
+
/// Returns the preference weight of a `CandidateType`.
|
|
105
|
+
///
|
|
106
|
+
/// 4.1.2.2. Guidelines for Choosing Type and Local Preferences
|
|
107
|
+
/// The RECOMMENDED values are 126 for host candidates, 100
|
|
108
|
+
/// for server reflexive candidates, 110 for peer reflexive candidates,
|
|
109
|
+
/// and 0 for relayed candidates.
|
|
110
|
+
#[must_use]
|
|
111
|
+
pub const fn preference(self) -> u16 {
|
|
112
|
+
match self {
|
|
113
|
+
Self::Host => 126,
|
|
114
|
+
Self::PeerReflexive => 110,
|
|
115
|
+
Self::ServerReflexive => 100,
|
|
116
|
+
Self::Relay | CandidateType::Unspecified => 0,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
pub(crate) fn contains_candidate_type(
|
|
122
|
+
candidate_type: CandidateType,
|
|
123
|
+
candidate_type_list: &[CandidateType],
|
|
124
|
+
) -> bool {
|
|
125
|
+
if candidate_type_list.is_empty() {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
for ct in candidate_type_list {
|
|
129
|
+
if *ct == candidate_type {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
false
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/// Convey transport addresses related to the candidate, useful for diagnostics and other purposes.
|
|
137
|
+
#[derive(PartialEq, Eq, Debug, Clone)]
|
|
138
|
+
pub struct CandidateRelatedAddress {
|
|
139
|
+
/// The address of the related candidate — the base this one was derived from.
|
|
140
|
+
/// The candidate's address.
|
|
141
|
+
pub address: String,
|
|
142
|
+
/// The port of the related candidate.
|
|
143
|
+
/// The candidate's port.
|
|
144
|
+
pub port: u16,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// String makes CandidateRelatedAddress printable
|
|
148
|
+
impl fmt::Display for CandidateRelatedAddress {
|
|
149
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
150
|
+
write!(f, " related {}:{}", self.address, self.port)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#[derive(Default)]
|
|
155
|
+
/// The fields common to every candidate type, used when constructing one.
|
|
156
|
+
pub struct CandidateConfig {
|
|
157
|
+
/// A unique identifier for this candidate; generated when left empty.
|
|
158
|
+
pub candidate_id: String,
|
|
159
|
+
/// The transport, `udp` or `tcp`.
|
|
160
|
+
pub network: String,
|
|
161
|
+
/// The candidate's address.
|
|
162
|
+
pub address: String,
|
|
163
|
+
/// The candidate's port.
|
|
164
|
+
pub port: u16,
|
|
165
|
+
/// The RTP component id: `1` for RTP, `2` for RTCP when not multiplexed.
|
|
166
|
+
pub component: u16,
|
|
167
|
+
/// The candidate priority; computed from the type and local preference when zero.
|
|
168
|
+
pub priority: u32,
|
|
169
|
+
/// The foundation, which groups candidates that share a base and transport.
|
|
170
|
+
///
|
|
171
|
+
/// Pairs with the same foundation are checked together, so redundant checks are avoided.
|
|
172
|
+
pub foundation: String,
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
#[derive(Clone, Debug)]
|
|
176
|
+
/// One ICE candidate: a transport address this agent can be reached at, or can reach a peer
|
|
177
|
+
/// at, together with its type, priority and liveness bookkeeping.
|
|
178
|
+
pub struct Candidate {
|
|
179
|
+
pub(crate) id: String,
|
|
180
|
+
pub(crate) network_type: NetworkType,
|
|
181
|
+
pub(crate) candidate_type: CandidateType,
|
|
182
|
+
|
|
183
|
+
pub(crate) component: u16,
|
|
184
|
+
pub(crate) address: String,
|
|
185
|
+
pub(crate) port: u16,
|
|
186
|
+
pub(crate) related_address: Option<CandidateRelatedAddress>,
|
|
187
|
+
pub(crate) tcp_type: TcpType,
|
|
188
|
+
|
|
189
|
+
pub(crate) resolved_addr: SocketAddr,
|
|
190
|
+
|
|
191
|
+
/// When traffic was last sent on this candidate, or `None` if none ever has been.
|
|
192
|
+
pub(crate) last_sent: Option<Instant>,
|
|
193
|
+
/// When traffic was last received on this candidate, or `None` if none ever has been.
|
|
194
|
+
pub(crate) last_received: Option<Instant>,
|
|
195
|
+
|
|
196
|
+
pub(crate) foundation_override: String,
|
|
197
|
+
pub(crate) priority_override: u32,
|
|
198
|
+
|
|
199
|
+
pub(crate) network: String,
|
|
200
|
+
|
|
201
|
+
pub(crate) url: Option<String>,
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
impl Default for Candidate {
|
|
205
|
+
fn default() -> Self {
|
|
206
|
+
Self {
|
|
207
|
+
id: String::new(),
|
|
208
|
+
network_type: NetworkType::Unspecified,
|
|
209
|
+
candidate_type: CandidateType::default(),
|
|
210
|
+
|
|
211
|
+
component: 0,
|
|
212
|
+
address: String::new(),
|
|
213
|
+
port: 0,
|
|
214
|
+
related_address: None,
|
|
215
|
+
tcp_type: TcpType::default(),
|
|
216
|
+
|
|
217
|
+
resolved_addr: SocketAddr::new(IpAddr::from([0, 0, 0, 0]), 0),
|
|
218
|
+
|
|
219
|
+
last_sent: None,
|
|
220
|
+
last_received: None,
|
|
221
|
+
|
|
222
|
+
foundation_override: String::new(),
|
|
223
|
+
priority_override: 0,
|
|
224
|
+
network: String::new(),
|
|
225
|
+
|
|
226
|
+
url: None,
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// String makes the candidateBase printable
|
|
232
|
+
impl fmt::Display for Candidate {
|
|
233
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
234
|
+
if let Some(related_address) = self.related_address() {
|
|
235
|
+
write!(
|
|
236
|
+
f,
|
|
237
|
+
"{} {} {}:{}{}",
|
|
238
|
+
self.network_type(),
|
|
239
|
+
self.candidate_type(),
|
|
240
|
+
self.address(),
|
|
241
|
+
self.port(),
|
|
242
|
+
related_address,
|
|
243
|
+
)
|
|
244
|
+
} else {
|
|
245
|
+
write!(
|
|
246
|
+
f,
|
|
247
|
+
"{} {} {}:{}",
|
|
248
|
+
self.network_type(),
|
|
249
|
+
self.candidate_type(),
|
|
250
|
+
self.address(),
|
|
251
|
+
self.port(),
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
impl Candidate {
|
|
258
|
+
/// The candidate's foundation, computed from its type, base address and transport.
|
|
259
|
+
///
|
|
260
|
+
/// A foundation groups equivalent candidates; it is deterministic bookkeeping rather than a
|
|
261
|
+
/// secret, random identifier. CRC-32C is therefore intentional here.
|
|
262
|
+
pub fn foundation(&self) -> String {
|
|
263
|
+
if !self.foundation_override.is_empty() {
|
|
264
|
+
return self.foundation_override.clone();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
let mut buf = vec![];
|
|
268
|
+
buf.extend_from_slice(self.candidate_type().to_string().as_bytes());
|
|
269
|
+
buf.extend_from_slice(self.address.as_bytes());
|
|
270
|
+
buf.extend_from_slice(self.network_type().to_string().as_bytes());
|
|
271
|
+
|
|
272
|
+
let checksum = Crc::<u32>::new(&CRC_32_ISCSI).checksum(&buf);
|
|
273
|
+
|
|
274
|
+
format!("{checksum}")
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/// Returns Candidate ID.
|
|
278
|
+
pub fn id(&self) -> &str {
|
|
279
|
+
self.id.as_str()
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/// Returns candidate component.
|
|
283
|
+
pub fn component(&self) -> u16 {
|
|
284
|
+
self.component
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/// Sets candidate component.
|
|
288
|
+
pub fn set_component(&mut self, component: u16) {
|
|
289
|
+
self.component = component;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/// When traffic was last received on this candidate.
|
|
293
|
+
///
|
|
294
|
+
/// `None` until the first packet arrives. A freshly constructed or freshly parsed candidate
|
|
295
|
+
/// has not received anything, and previously said it had — it was seeded with the
|
|
296
|
+
/// construction instant, which also meant every candidate constructor needed a clock.
|
|
297
|
+
pub fn last_received(&self) -> Option<Instant> {
|
|
298
|
+
self.last_received
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/// When traffic was last sent on this candidate, or `None` if none ever has been.
|
|
302
|
+
pub fn last_sent(&self) -> Option<Instant> {
|
|
303
|
+
self.last_sent
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/// Returns candidate NetworkType.
|
|
307
|
+
pub fn network_type(&self) -> NetworkType {
|
|
308
|
+
self.network_type
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/// Returns Candidate Address.
|
|
312
|
+
pub fn address(&self) -> &str {
|
|
313
|
+
self.address.as_str()
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/// Returns Candidate Port.
|
|
317
|
+
pub fn port(&self) -> u16 {
|
|
318
|
+
self.port
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/// Computes the priority for this ICE Candidate.
|
|
322
|
+
pub fn priority(&self) -> u32 {
|
|
323
|
+
if self.priority_override != 0 {
|
|
324
|
+
return self.priority_override;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// The local preference MUST be an integer from 0 (lowest preference) to
|
|
328
|
+
// 65535 (highest preference) inclusive. When there is only a single IP
|
|
329
|
+
// address, this value SHOULD be set to 65535. If there are multiple
|
|
330
|
+
// candidates for a particular component for a particular data stream
|
|
331
|
+
// that have the same type, the local preference MUST be unique for each
|
|
332
|
+
// one.
|
|
333
|
+
(1 << 24) * u32::from(self.candidate_type().preference())
|
|
334
|
+
+ (1 << 8) * u32::from(self.local_preference())
|
|
335
|
+
+ (256 - u32::from(self.component()))
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/// Returns `Option<CandidateRelatedAddress>`.
|
|
339
|
+
pub fn related_address(&self) -> Option<CandidateRelatedAddress> {
|
|
340
|
+
self.related_address.as_ref().cloned()
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/// Returns candidate type.
|
|
344
|
+
pub fn candidate_type(&self) -> CandidateType {
|
|
345
|
+
self.candidate_type
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/// The TCP role for ICE-TCP candidates; `Unspecified` for UDP.
|
|
349
|
+
pub fn tcp_type(&self) -> TcpType {
|
|
350
|
+
self.tcp_type
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/// The STUN or TURN server this candidate was gathered from, if any.
|
|
354
|
+
pub fn url(&self) -> Option<&str> {
|
|
355
|
+
self.url.as_deref()
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/// Returns the string representation of the ICECandidate.
|
|
359
|
+
pub fn marshal(&self) -> String {
|
|
360
|
+
let mut val = format!(
|
|
361
|
+
"{} {} {} {} {} {} typ {}",
|
|
362
|
+
self.foundation(),
|
|
363
|
+
self.component(),
|
|
364
|
+
self.network_type().network_short(),
|
|
365
|
+
self.priority(),
|
|
366
|
+
self.address(),
|
|
367
|
+
self.port(),
|
|
368
|
+
self.candidate_type()
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
if self.tcp_type != TcpType::Unspecified {
|
|
372
|
+
val += format!(" tcptype {}", self.tcp_type()).as_str();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if let Some(related_address) = self.related_address() {
|
|
376
|
+
val += format!(
|
|
377
|
+
" raddr {} rport {}",
|
|
378
|
+
related_address.address, related_address.port,
|
|
379
|
+
)
|
|
380
|
+
.as_str();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
val
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/// The candidate's socket address.
|
|
387
|
+
pub fn addr(&self) -> SocketAddr {
|
|
388
|
+
self.resolved_addr
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/// Returns the candidate's base address: the local transport address the
|
|
392
|
+
/// candidate was derived from, i.e. the address packets for this candidate
|
|
393
|
+
/// must be sent from (RFC 8445 §5.1.1).
|
|
394
|
+
///
|
|
395
|
+
/// For server-reflexive and peer-reflexive candidates this is the related
|
|
396
|
+
/// (host) address; for host and relay candidates the base is the candidate
|
|
397
|
+
/// address itself.
|
|
398
|
+
pub fn base_addr(&self) -> SocketAddr {
|
|
399
|
+
match self.candidate_type {
|
|
400
|
+
CandidateType::ServerReflexive | CandidateType::PeerReflexive => self
|
|
401
|
+
.related_address
|
|
402
|
+
.as_ref()
|
|
403
|
+
.and_then(|ra| {
|
|
404
|
+
ra.address
|
|
405
|
+
.parse::<IpAddr>()
|
|
406
|
+
.ok()
|
|
407
|
+
.map(|ip| SocketAddr::new(ip, ra.port))
|
|
408
|
+
})
|
|
409
|
+
.unwrap_or(self.resolved_addr),
|
|
410
|
+
_ => self.resolved_addr,
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/// Records traffic on this candidate, updating its last-sent or last-received time.
|
|
415
|
+
///
|
|
416
|
+
/// Feeds consent freshness — a pair that stops seeing traffic is eventually abandoned.
|
|
417
|
+
pub fn seen(&mut self, now: Instant, outbound: bool) {
|
|
418
|
+
if outbound {
|
|
419
|
+
self.set_last_sent(now);
|
|
420
|
+
} else {
|
|
421
|
+
self.set_last_received(now);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/// Used to compare two candidateBases.
|
|
426
|
+
pub fn equal(&self, other: &Candidate) -> bool {
|
|
427
|
+
self.network_type() == other.network_type()
|
|
428
|
+
&& self.candidate_type() == other.candidate_type()
|
|
429
|
+
&& self.address() == other.address()
|
|
430
|
+
&& self.port() == other.port()
|
|
431
|
+
&& self.tcp_type() == other.tcp_type()
|
|
432
|
+
&& self.related_address() == other.related_address()
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/// Returns true if this candidate can be paired with `other` according to
|
|
436
|
+
/// ICE candidate pairing rules.
|
|
437
|
+
///
|
|
438
|
+
/// Candidates must share the same network type (protocol and address family)
|
|
439
|
+
/// and have compatible TCP types (RFC 6544). UDP candidates use
|
|
440
|
+
/// `TcpType::Unspecified`.
|
|
441
|
+
pub(crate) fn can_pair_with(&self, other: &Candidate) -> bool {
|
|
442
|
+
if self.network_type() != other.network_type() {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
match (self.tcp_type(), other.tcp_type()) {
|
|
447
|
+
(TcpType::Active, TcpType::Passive) => true,
|
|
448
|
+
(TcpType::Passive, TcpType::Active) => true,
|
|
449
|
+
(TcpType::SimultaneousOpen, TcpType::SimultaneousOpen) => true,
|
|
450
|
+
(TcpType::Unspecified, TcpType::Unspecified) => true, // UDP candidates
|
|
451
|
+
_ => false,
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/// Sets the resolved IP, deriving the network type from it.
|
|
456
|
+
///
|
|
457
|
+
/// # Errors
|
|
458
|
+
///
|
|
459
|
+
/// Fails if `ip`'s family does not match this candidate's network type.
|
|
460
|
+
pub fn set_ip(&mut self, ip: &IpAddr) -> Result<()> {
|
|
461
|
+
self.network_type = determine_network_type(&self.network, ip)?;
|
|
462
|
+
self.resolved_addr = SocketAddr::new(*ip, self.port); //TODO: create_addr(network_type, *ip, self.port);
|
|
463
|
+
Ok(())
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
impl Candidate {
|
|
468
|
+
/// Records that traffic was received on this candidate at `now`.
|
|
469
|
+
pub fn set_last_received(&mut self, now: Instant) {
|
|
470
|
+
self.last_received = Some(now);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/// Records that traffic was sent on this candidate at `now`.
|
|
474
|
+
pub fn set_last_sent(&mut self, now: Instant) {
|
|
475
|
+
self.last_sent = Some(now);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/// Returns the local preference for this candidate.
|
|
479
|
+
pub fn local_preference(&self) -> u16 {
|
|
480
|
+
if self.network_type().is_tcp() {
|
|
481
|
+
// RFC 6544, section 4.2
|
|
482
|
+
//
|
|
483
|
+
// In Section 4.1.2.1 of [RFC5245], a recommended formula for UDP ICE
|
|
484
|
+
// candidate prioritization is defined. For TCP candidates, the same
|
|
485
|
+
// formula and candidate type preferences SHOULD be used, and the
|
|
486
|
+
// RECOMMENDED type preferences for the new candidate types defined in
|
|
487
|
+
// this document (see Section 5) are 105 for NAT-assisted candidates and
|
|
488
|
+
// 75 for UDP-tunneled candidates.
|
|
489
|
+
//
|
|
490
|
+
// (...)
|
|
491
|
+
//
|
|
492
|
+
// With TCP candidates, the local preference part of the recommended
|
|
493
|
+
// priority formula is updated to also include the directionality
|
|
494
|
+
// (active, passive, or simultaneous-open) of the TCP connection. The
|
|
495
|
+
// RECOMMENDED local preference is then defined as:
|
|
496
|
+
//
|
|
497
|
+
// local preference = (2^13) * direction-pref + other-pref
|
|
498
|
+
//
|
|
499
|
+
// The direction-pref MUST be between 0 and 7 (both inclusive), with 7
|
|
500
|
+
// being the most preferred. The other-pref MUST be between 0 and 8191
|
|
501
|
+
// (both inclusive), with 8191 being the most preferred. It is
|
|
502
|
+
// RECOMMENDED that the host, UDP-tunneled, and relayed TCP candidates
|
|
503
|
+
// have the direction-pref assigned as follows: 6 for active, 4 for
|
|
504
|
+
// passive, and 2 for S-O. For the NAT-assisted and server reflexive
|
|
505
|
+
// candidates, the RECOMMENDED values are: 6 for S-O, 4 for active, and
|
|
506
|
+
// 2 for passive.
|
|
507
|
+
//
|
|
508
|
+
// (...)
|
|
509
|
+
//
|
|
510
|
+
// If any two candidates have the same type-preference and direction-
|
|
511
|
+
// pref, they MUST have a unique other-pref. With this specification,
|
|
512
|
+
// this usually only happens with multi-homed hosts, in which case
|
|
513
|
+
// other-pref is the preference for the particular IP address from which
|
|
514
|
+
// the candidate was obtained. When there is only a single IP address,
|
|
515
|
+
// this value SHOULD be set to the maximum allowed value (8191).
|
|
516
|
+
let other_pref: u16 = 8191;
|
|
517
|
+
|
|
518
|
+
let direction_pref: u16 = match self.candidate_type() {
|
|
519
|
+
CandidateType::Host | CandidateType::Relay => match self.tcp_type() {
|
|
520
|
+
TcpType::Active => 6,
|
|
521
|
+
TcpType::Passive => 4,
|
|
522
|
+
TcpType::SimultaneousOpen => 2,
|
|
523
|
+
TcpType::Unspecified => 0,
|
|
524
|
+
},
|
|
525
|
+
CandidateType::PeerReflexive | CandidateType::ServerReflexive => {
|
|
526
|
+
match self.tcp_type() {
|
|
527
|
+
TcpType::SimultaneousOpen => 6,
|
|
528
|
+
TcpType::Active => 4,
|
|
529
|
+
TcpType::Passive => 2,
|
|
530
|
+
TcpType::Unspecified => 0,
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
CandidateType::Unspecified => 0,
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
(1 << 13) * direction_pref + other_pref
|
|
537
|
+
} else {
|
|
538
|
+
DEFAULT_LOCAL_PREFERENCE
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/// Creates a Candidate from its string representation.
|
|
544
|
+
pub fn unmarshal_candidate(raw: &str) -> Result<Candidate> {
|
|
545
|
+
let split: Vec<&str> = raw.split_whitespace().collect();
|
|
546
|
+
if split.len() < 8 {
|
|
547
|
+
return Err(Error::Other(format!(
|
|
548
|
+
"{:?} ({})",
|
|
549
|
+
Error::ErrAttributeTooShortIceCandidate,
|
|
550
|
+
split.len()
|
|
551
|
+
)));
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Foundation
|
|
555
|
+
let foundation = split[0].to_owned();
|
|
556
|
+
|
|
557
|
+
// Component
|
|
558
|
+
let component: u16 = split[1].parse()?;
|
|
559
|
+
|
|
560
|
+
// Network
|
|
561
|
+
let network = split[2].to_owned();
|
|
562
|
+
|
|
563
|
+
// Priority
|
|
564
|
+
let priority: u32 = split[3].parse()?;
|
|
565
|
+
|
|
566
|
+
// Address
|
|
567
|
+
let address = split[4].to_owned();
|
|
568
|
+
|
|
569
|
+
// Port
|
|
570
|
+
let port: u16 = split[5].parse()?;
|
|
571
|
+
|
|
572
|
+
let typ = split[7];
|
|
573
|
+
|
|
574
|
+
let mut rel_addr = String::new();
|
|
575
|
+
let mut rel_port = 0;
|
|
576
|
+
let mut tcp_type = TcpType::Unspecified;
|
|
577
|
+
|
|
578
|
+
if split.len() > 8 {
|
|
579
|
+
let split2 = &split[8..];
|
|
580
|
+
|
|
581
|
+
if split2[0] == "raddr" {
|
|
582
|
+
if split2.len() < 4 {
|
|
583
|
+
return Err(Error::Other(format!(
|
|
584
|
+
"{:?}: incorrect length",
|
|
585
|
+
Error::ErrParseRelatedAddr
|
|
586
|
+
)));
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// RelatedAddress
|
|
590
|
+
split2[1].clone_into(&mut rel_addr);
|
|
591
|
+
|
|
592
|
+
// RelatedPort
|
|
593
|
+
rel_port = split2[3].parse()?;
|
|
594
|
+
} else if split2[0] == "tcptype" {
|
|
595
|
+
if split2.len() < 2 {
|
|
596
|
+
return Err(Error::Other(format!(
|
|
597
|
+
"{:?}: incorrect length",
|
|
598
|
+
Error::ErrParseType
|
|
599
|
+
)));
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
tcp_type = TcpType::from(split2[1]);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
match typ {
|
|
607
|
+
"host" => {
|
|
608
|
+
let config = CandidateHostConfig {
|
|
609
|
+
base_config: CandidateConfig {
|
|
610
|
+
network,
|
|
611
|
+
address,
|
|
612
|
+
port,
|
|
613
|
+
component,
|
|
614
|
+
priority,
|
|
615
|
+
foundation,
|
|
616
|
+
..CandidateConfig::default()
|
|
617
|
+
},
|
|
618
|
+
tcp_type,
|
|
619
|
+
};
|
|
620
|
+
config.new_candidate_host()
|
|
621
|
+
}
|
|
622
|
+
"srflx" => {
|
|
623
|
+
let config = CandidateServerReflexiveConfig {
|
|
624
|
+
base_config: CandidateConfig {
|
|
625
|
+
network,
|
|
626
|
+
address,
|
|
627
|
+
port,
|
|
628
|
+
component,
|
|
629
|
+
priority,
|
|
630
|
+
foundation,
|
|
631
|
+
..CandidateConfig::default()
|
|
632
|
+
},
|
|
633
|
+
rel_addr,
|
|
634
|
+
rel_port,
|
|
635
|
+
url: None,
|
|
636
|
+
};
|
|
637
|
+
config.new_candidate_server_reflexive()
|
|
638
|
+
}
|
|
639
|
+
"prflx" => {
|
|
640
|
+
let config = CandidatePeerReflexiveConfig {
|
|
641
|
+
base_config: CandidateConfig {
|
|
642
|
+
network,
|
|
643
|
+
address,
|
|
644
|
+
port,
|
|
645
|
+
component,
|
|
646
|
+
priority,
|
|
647
|
+
foundation,
|
|
648
|
+
..CandidateConfig::default()
|
|
649
|
+
},
|
|
650
|
+
rel_addr,
|
|
651
|
+
rel_port,
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
config.new_candidate_peer_reflexive()
|
|
655
|
+
}
|
|
656
|
+
"relay" => {
|
|
657
|
+
let config = CandidateRelayConfig {
|
|
658
|
+
base_config: CandidateConfig {
|
|
659
|
+
network,
|
|
660
|
+
address,
|
|
661
|
+
port,
|
|
662
|
+
component,
|
|
663
|
+
priority,
|
|
664
|
+
foundation,
|
|
665
|
+
..CandidateConfig::default()
|
|
666
|
+
},
|
|
667
|
+
rel_addr,
|
|
668
|
+
rel_port,
|
|
669
|
+
url: None,
|
|
670
|
+
};
|
|
671
|
+
config.new_candidate_relay()
|
|
672
|
+
}
|
|
673
|
+
_ => Err(Error::Other(format!(
|
|
674
|
+
"{:?} ({})",
|
|
675
|
+
Error::ErrUnknownCandidateType,
|
|
676
|
+
typ
|
|
677
|
+
))),
|
|
678
|
+
}
|
|
679
|
+
}
|