@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.
Files changed (64) hide show
  1. package/README.md +25 -17
  2. package/dist/engineProcess.d.ts +5 -0
  3. package/dist/engineProcess.d.ts.map +1 -1
  4. package/dist/engineProcess.js +5 -3
  5. package/dist/engineProcess.js.map +1 -1
  6. package/engine/Cargo.lock +6 -8
  7. package/engine/Cargo.toml +13 -1
  8. package/engine/src/clipboard.rs +0 -34
  9. package/engine/src/convert.rs +0 -170
  10. package/engine/src/cursor.rs +0 -23
  11. package/engine/src/input.rs +0 -65
  12. package/engine/src/input_mac.rs +0 -11
  13. package/engine/src/keeper.rs +0 -137
  14. package/engine/src/keymap.rs +0 -107
  15. package/engine/src/keymap_mac.rs +0 -25
  16. package/engine/src/mac.rs +0 -28
  17. package/engine/src/peer.rs +224 -0
  18. package/engine/src/portal.rs +0 -18
  19. package/engine/src/protocol.rs +0 -162
  20. package/engine/src/x11.rs +0 -13
  21. package/engine/vendor/rtc-ice/Cargo.toml +137 -0
  22. package/engine/vendor/rtc-ice/DESKLINK-PATCH.md +59 -0
  23. package/engine/vendor/rtc-ice/LICENSE-APACHE +201 -0
  24. package/engine/vendor/rtc-ice/LICENSE-MIT +21 -0
  25. package/engine/vendor/rtc-ice/README.md +30 -0
  26. package/engine/vendor/rtc-ice/examples/ping_pong.rs +376 -0
  27. package/engine/vendor/rtc-ice/src/agent/agent_config.rs +126 -0
  28. package/engine/vendor/rtc-ice/src/agent/agent_proto.rs +172 -0
  29. package/engine/vendor/rtc-ice/src/agent/agent_selector.rs +566 -0
  30. package/engine/vendor/rtc-ice/src/agent/agent_stats.rs +292 -0
  31. package/engine/vendor/rtc-ice/src/agent/agent_test.rs +3388 -0
  32. package/engine/vendor/rtc-ice/src/agent/mod.rs +1662 -0
  33. package/engine/vendor/rtc-ice/src/attributes/control/control_test.rs +168 -0
  34. package/engine/vendor/rtc-ice/src/attributes/control/mod.rs +142 -0
  35. package/engine/vendor/rtc-ice/src/attributes/mod.rs +6 -0
  36. package/engine/vendor/rtc-ice/src/attributes/priority/mod.rs +37 -0
  37. package/engine/vendor/rtc-ice/src/attributes/priority/priority_test.rs +39 -0
  38. package/engine/vendor/rtc-ice/src/attributes/use_candidate/mod.rs +33 -0
  39. package/engine/vendor/rtc-ice/src/attributes/use_candidate/use_candidate_test.rs +19 -0
  40. package/engine/vendor/rtc-ice/src/candidate/candidate_host.rs +53 -0
  41. package/engine/vendor/rtc-ice/src/candidate/candidate_pair.rs +215 -0
  42. package/engine/vendor/rtc-ice/src/candidate/candidate_pair_test.rs +201 -0
  43. package/engine/vendor/rtc-ice/src/candidate/candidate_peer_reflexive.rs +49 -0
  44. package/engine/vendor/rtc-ice/src/candidate/candidate_relay.rs +53 -0
  45. package/engine/vendor/rtc-ice/src/candidate/candidate_relay_test.rs +114 -0
  46. package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive.rs +53 -0
  47. package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive_test.rs +91 -0
  48. package/engine/vendor/rtc-ice/src/candidate/candidate_test.rs +540 -0
  49. package/engine/vendor/rtc-ice/src/candidate/mod.rs +679 -0
  50. package/engine/vendor/rtc-ice/src/lib.rs +85 -0
  51. package/engine/vendor/rtc-ice/src/mdns/mdns_test.rs +150 -0
  52. package/engine/vendor/rtc-ice/src/mdns/mod.rs +69 -0
  53. package/engine/vendor/rtc-ice/src/network_type/mod.rs +162 -0
  54. package/engine/vendor/rtc-ice/src/network_type/network_type_test.rs +95 -0
  55. package/engine/vendor/rtc-ice/src/rand/mod.rs +91 -0
  56. package/engine/vendor/rtc-ice/src/rand/rand_test.rs +115 -0
  57. package/engine/vendor/rtc-ice/src/state/mod.rs +106 -0
  58. package/engine/vendor/rtc-ice/src/state/state_test.rs +46 -0
  59. package/engine/vendor/rtc-ice/src/stats/mod.rs +166 -0
  60. package/engine/vendor/rtc-ice/src/tcp_type/mod.rs +47 -0
  61. package/engine/vendor/rtc-ice/src/tcp_type/tcp_type_test.rs +18 -0
  62. package/engine/vendor/rtc-ice/src/url/mod.rs +266 -0
  63. package/engine/vendor/rtc-ice/src/url/url_test.rs +142 -0
  64. 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
+ }