@desklink/host 0.5.2 → 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 (77) hide show
  1. package/README.md +45 -18
  2. package/bin/desklink-host.mjs +5 -1
  3. package/dist/bridge.d.ts +7 -0
  4. package/dist/bridge.d.ts.map +1 -1
  5. package/dist/bridge.js +55 -7
  6. package/dist/bridge.js.map +1 -1
  7. package/dist/engineProcess.d.ts +9 -2
  8. package/dist/engineProcess.d.ts.map +1 -1
  9. package/dist/engineProcess.js +26 -15
  10. package/dist/engineProcess.js.map +1 -1
  11. package/dist/protocol.d.ts +1 -1
  12. package/dist/protocol.d.ts.map +1 -1
  13. package/dist/protocol.js +1 -1
  14. package/dist/protocol.js.map +1 -1
  15. package/docs/BOUNDARY.md +4 -1
  16. package/docs/PROTOCOL.md +20 -5
  17. package/engine/Cargo.lock +6 -8
  18. package/engine/Cargo.toml +13 -1
  19. package/engine/src/clipboard.rs +0 -34
  20. package/engine/src/convert.rs +0 -170
  21. package/engine/src/cursor.rs +0 -23
  22. package/engine/src/input.rs +0 -65
  23. package/engine/src/input_mac.rs +0 -11
  24. package/engine/src/keeper.rs +0 -137
  25. package/engine/src/keymap.rs +0 -107
  26. package/engine/src/keymap_mac.rs +0 -25
  27. package/engine/src/mac.rs +0 -28
  28. package/engine/src/main.rs +3 -2
  29. package/engine/src/peer.rs +231 -1
  30. package/engine/src/portal.rs +0 -18
  31. package/engine/src/protocol.rs +0 -162
  32. package/engine/src/session.rs +37 -1
  33. package/engine/src/x11.rs +0 -13
  34. package/engine/vendor/rtc-ice/Cargo.toml +137 -0
  35. package/engine/vendor/rtc-ice/DESKLINK-PATCH.md +59 -0
  36. package/engine/vendor/rtc-ice/LICENSE-APACHE +201 -0
  37. package/engine/vendor/rtc-ice/LICENSE-MIT +21 -0
  38. package/engine/vendor/rtc-ice/README.md +30 -0
  39. package/engine/vendor/rtc-ice/examples/ping_pong.rs +376 -0
  40. package/engine/vendor/rtc-ice/src/agent/agent_config.rs +126 -0
  41. package/engine/vendor/rtc-ice/src/agent/agent_proto.rs +172 -0
  42. package/engine/vendor/rtc-ice/src/agent/agent_selector.rs +566 -0
  43. package/engine/vendor/rtc-ice/src/agent/agent_stats.rs +292 -0
  44. package/engine/vendor/rtc-ice/src/agent/agent_test.rs +3388 -0
  45. package/engine/vendor/rtc-ice/src/agent/mod.rs +1662 -0
  46. package/engine/vendor/rtc-ice/src/attributes/control/control_test.rs +168 -0
  47. package/engine/vendor/rtc-ice/src/attributes/control/mod.rs +142 -0
  48. package/engine/vendor/rtc-ice/src/attributes/mod.rs +6 -0
  49. package/engine/vendor/rtc-ice/src/attributes/priority/mod.rs +37 -0
  50. package/engine/vendor/rtc-ice/src/attributes/priority/priority_test.rs +39 -0
  51. package/engine/vendor/rtc-ice/src/attributes/use_candidate/mod.rs +33 -0
  52. package/engine/vendor/rtc-ice/src/attributes/use_candidate/use_candidate_test.rs +19 -0
  53. package/engine/vendor/rtc-ice/src/candidate/candidate_host.rs +53 -0
  54. package/engine/vendor/rtc-ice/src/candidate/candidate_pair.rs +215 -0
  55. package/engine/vendor/rtc-ice/src/candidate/candidate_pair_test.rs +201 -0
  56. package/engine/vendor/rtc-ice/src/candidate/candidate_peer_reflexive.rs +49 -0
  57. package/engine/vendor/rtc-ice/src/candidate/candidate_relay.rs +53 -0
  58. package/engine/vendor/rtc-ice/src/candidate/candidate_relay_test.rs +114 -0
  59. package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive.rs +53 -0
  60. package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive_test.rs +91 -0
  61. package/engine/vendor/rtc-ice/src/candidate/candidate_test.rs +540 -0
  62. package/engine/vendor/rtc-ice/src/candidate/mod.rs +679 -0
  63. package/engine/vendor/rtc-ice/src/lib.rs +85 -0
  64. package/engine/vendor/rtc-ice/src/mdns/mdns_test.rs +150 -0
  65. package/engine/vendor/rtc-ice/src/mdns/mod.rs +69 -0
  66. package/engine/vendor/rtc-ice/src/network_type/mod.rs +162 -0
  67. package/engine/vendor/rtc-ice/src/network_type/network_type_test.rs +95 -0
  68. package/engine/vendor/rtc-ice/src/rand/mod.rs +91 -0
  69. package/engine/vendor/rtc-ice/src/rand/rand_test.rs +115 -0
  70. package/engine/vendor/rtc-ice/src/state/mod.rs +106 -0
  71. package/engine/vendor/rtc-ice/src/state/state_test.rs +46 -0
  72. package/engine/vendor/rtc-ice/src/stats/mod.rs +166 -0
  73. package/engine/vendor/rtc-ice/src/tcp_type/mod.rs +47 -0
  74. package/engine/vendor/rtc-ice/src/tcp_type/tcp_type_test.rs +18 -0
  75. package/engine/vendor/rtc-ice/src/url/mod.rs +266 -0
  76. package/engine/vendor/rtc-ice/src/url/url_test.rs +142 -0
  77. package/package.json +8 -3
@@ -0,0 +1,566 @@
1
+ use crate::agent::Agent;
2
+ use log::{debug, error, trace, warn};
3
+ use std::net::SocketAddr;
4
+ use std::time::Instant;
5
+ use stun::attributes::*;
6
+ use stun::fingerprint::*;
7
+ use stun::integrity::*;
8
+ use stun::message::*;
9
+ use stun::textattrs::*;
10
+
11
+ use crate::attributes::{control::*, priority::*, use_candidate::*};
12
+ use crate::candidate::{candidate_pair::*, *};
13
+
14
+ trait ControllingSelector {
15
+ fn start(&mut self, now: Instant);
16
+ fn contact_candidates(&mut self, now: Instant);
17
+ fn ping_candidate(&mut self, now: Instant, local_index: usize, remote_index: usize);
18
+ fn handle_success_response(
19
+ &mut self,
20
+ now: Instant,
21
+ m: &Message,
22
+ local_index: usize,
23
+ remote_index: usize,
24
+ remote_addr: SocketAddr,
25
+ );
26
+ fn handle_binding_request(
27
+ &mut self,
28
+ now: Instant,
29
+ m: &Message,
30
+ local_index: usize,
31
+ remote_index: usize,
32
+ );
33
+ }
34
+
35
+ trait ControlledSelector {
36
+ fn start(&mut self, now: Instant);
37
+ fn contact_candidates(&mut self, now: Instant);
38
+ fn ping_candidate(&mut self, now: Instant, local_index: usize, remote_index: usize);
39
+ fn handle_success_response(
40
+ &mut self,
41
+ now: Instant,
42
+ m: &Message,
43
+ local_index: usize,
44
+ remote_index: usize,
45
+ remote_addr: SocketAddr,
46
+ );
47
+ fn handle_binding_request(
48
+ &mut self,
49
+ now: Instant,
50
+ m: &Message,
51
+ local_index: usize,
52
+ remote_index: usize,
53
+ );
54
+ }
55
+
56
+ impl Agent {
57
+ /// Whether `index` has been waiting long enough to be nominated, as of `now`.
58
+ ///
59
+ /// `now` is supplied by the caller rather than sampled here so that one nomination decision
60
+ /// makes one time observation: both halves of a pair are tested against the same instant.
61
+ fn is_nominatable(&self, now: Instant, index: usize, is_local: bool) -> bool {
62
+ let c = if is_local {
63
+ &self.local_candidates[index]
64
+ } else {
65
+ &self.remote_candidates[index]
66
+ };
67
+ let min_wait = match c.candidate_type() {
68
+ CandidateType::Host => self.host_acceptance_min_wait,
69
+ CandidateType::ServerReflexive => self.srflx_acceptance_min_wait,
70
+ CandidateType::PeerReflexive => self.prflx_acceptance_min_wait,
71
+ CandidateType::Relay => self.relay_acceptance_min_wait,
72
+ CandidateType::Unspecified => {
73
+ error!(
74
+ "is_nominatable invalid candidate type {}",
75
+ c.candidate_type()
76
+ );
77
+ return false;
78
+ }
79
+ };
80
+ now.saturating_duration_since(self.start_time) > min_wait
81
+ }
82
+
83
+ fn nominate_pair(&mut self, now: Instant) {
84
+ let result = {
85
+ let Some(remote_credentials) = &self.ufrag_pwd.remote_credentials else {
86
+ error!("ufrag_pwd.remote_credentials is none");
87
+ return;
88
+ };
89
+ if let Some(pair_index) = &self.nominated_pair {
90
+ let pair = &self.candidate_pairs[*pair_index];
91
+ // The controlling agent MUST include the USE-CANDIDATE attribute in
92
+ // order to nominate a candidate pair (Section 8.1.1). The controlled
93
+ // agent MUST NOT include the USE-CANDIDATE attribute in a Binding
94
+ // request.
95
+
96
+ let (msg, result) = {
97
+ let username = remote_credentials.ufrag.clone()
98
+ + ":"
99
+ + self.ufrag_pwd.local_credentials.ufrag.as_str();
100
+ let mut msg = Message::new();
101
+ let result = msg.build(&[
102
+ Box::new(BINDING_REQUEST),
103
+ Box::new(TransactionId::new()),
104
+ Box::new(Username::new(ATTR_USERNAME, username)),
105
+ Box::<UseCandidateAttr>::default(),
106
+ Box::new(AttrControlling(self.tie_breaker)),
107
+ Box::new(PriorityAttr(pair.local_priority)),
108
+ Box::new(MessageIntegrity::new_short_term_integrity_with_provider(
109
+ remote_credentials.pwd.clone(),
110
+ self.crypto_provider.crypto(),
111
+ )),
112
+ Box::new(FINGERPRINT),
113
+ ]);
114
+ (msg, result)
115
+ };
116
+
117
+ if let Err(err) = result {
118
+ error!("{}", err);
119
+ None
120
+ } else {
121
+ trace!(
122
+ "ping STUN (nominate candidate pair from {} to {}",
123
+ self.local_candidates[pair.local_index],
124
+ self.remote_candidates[pair.remote_index],
125
+ );
126
+ let local = pair.local_index;
127
+ let remote = pair.remote_index;
128
+ Some((msg, local, remote))
129
+ }
130
+ } else {
131
+ None
132
+ }
133
+ };
134
+
135
+ if let Some((msg, local, remote)) = result {
136
+ self.send_binding_request(now, &msg, local, remote);
137
+ }
138
+ }
139
+
140
+ pub(crate) fn start(&mut self, now: Instant) {
141
+ if self.is_controlling {
142
+ ControllingSelector::start(self, now);
143
+ } else {
144
+ ControlledSelector::start(self, now);
145
+ }
146
+ }
147
+
148
+ pub(crate) fn contact_candidates(&mut self, now: Instant) {
149
+ if self.is_controlling {
150
+ ControllingSelector::contact_candidates(self, now);
151
+ } else {
152
+ ControlledSelector::contact_candidates(self, now);
153
+ }
154
+ }
155
+
156
+ pub(crate) fn ping_candidate(&mut self, now: Instant, local_index: usize, remote_index: usize) {
157
+ trace!("[{}]: ping_candidate", self.get_name());
158
+
159
+ if self.is_controlling {
160
+ ControllingSelector::ping_candidate(self, now, local_index, remote_index);
161
+ } else {
162
+ ControlledSelector::ping_candidate(self, now, local_index, remote_index);
163
+ }
164
+ }
165
+
166
+ pub(crate) fn handle_success_response(
167
+ &mut self,
168
+ now: Instant,
169
+ m: &Message,
170
+ local_index: usize,
171
+ remote_index: usize,
172
+ remote_addr: SocketAddr,
173
+ ) {
174
+ if self.is_controlling {
175
+ ControllingSelector::handle_success_response(
176
+ self,
177
+ now,
178
+ m,
179
+ local_index,
180
+ remote_index,
181
+ remote_addr,
182
+ );
183
+ } else {
184
+ ControlledSelector::handle_success_response(
185
+ self,
186
+ now,
187
+ m,
188
+ local_index,
189
+ remote_index,
190
+ remote_addr,
191
+ );
192
+ }
193
+ }
194
+
195
+ pub(crate) fn handle_binding_request(
196
+ &mut self,
197
+ now: Instant,
198
+ m: &Message,
199
+ local_index: usize,
200
+ remote_index: usize,
201
+ ) {
202
+ if self.is_controlling {
203
+ ControllingSelector::handle_binding_request(self, now, m, local_index, remote_index);
204
+ } else {
205
+ ControlledSelector::handle_binding_request(self, now, m, local_index, remote_index);
206
+ }
207
+ }
208
+ }
209
+
210
+ impl ControllingSelector for Agent {
211
+ fn start(&mut self, now: Instant) {
212
+ self.nominated_pair = None;
213
+ self.start_time = now;
214
+ }
215
+
216
+ fn contact_candidates(&mut self, now: Instant) {
217
+ // A lite selector should not contact candidates
218
+ if self.lite {
219
+ // This only happens if both peers are lite. See RFC 8445 S6.1.1 and S6.2
220
+ trace!("now falling back to full agent");
221
+ }
222
+
223
+ let nominated_pair_is_some = self.nominated_pair.is_some();
224
+
225
+ if self.get_selected_pair().is_some() {
226
+ if self.validate_selected_pair(now) {
227
+ self.check_keepalive(now);
228
+ }
229
+ } else if nominated_pair_is_some {
230
+ self.nominate_pair(now);
231
+ } else {
232
+ let has_nominated_pair = if let Some(pair_index) = self.get_best_valid_candidate_pair()
233
+ {
234
+ let p = self.candidate_pairs[pair_index];
235
+ self.is_nominatable(now, p.local_index, true)
236
+ && self.is_nominatable(now, p.remote_index, false)
237
+ } else {
238
+ false
239
+ };
240
+
241
+ if has_nominated_pair {
242
+ if let Some(pair_index) = self.get_best_valid_candidate_pair() {
243
+ let p = &mut self.candidate_pairs[pair_index];
244
+ trace!(
245
+ "Nominatable pair found, nominating ({}, {})",
246
+ self.local_candidates[p.local_index],
247
+ self.remote_candidates[p.remote_index],
248
+ );
249
+ p.nominated = true;
250
+ self.nominated_pair = Some(pair_index);
251
+ }
252
+
253
+ self.nominate_pair(now);
254
+ } else {
255
+ self.ping_all_candidates(now);
256
+ }
257
+ }
258
+ }
259
+
260
+ fn ping_candidate(&mut self, now: Instant, local_index: usize, remote_index: usize) {
261
+ let (msg, result) = {
262
+ let Some(remote_credentials) = &self.ufrag_pwd.remote_credentials else {
263
+ error!("ufrag_pwd.remote_credentials is none");
264
+ return;
265
+ };
266
+
267
+ let username = remote_credentials.ufrag.clone()
268
+ + ":"
269
+ + self.ufrag_pwd.local_credentials.ufrag.as_str();
270
+ let mut msg = Message::new();
271
+ let result = msg.build(&[
272
+ Box::new(BINDING_REQUEST),
273
+ Box::new(TransactionId::new()),
274
+ Box::new(Username::new(ATTR_USERNAME, username)),
275
+ Box::new(AttrControlling(self.tie_breaker)),
276
+ Box::new(PriorityAttr(self.local_candidates[local_index].priority())),
277
+ Box::new(MessageIntegrity::new_short_term_integrity_with_provider(
278
+ remote_credentials.pwd.clone(),
279
+ self.crypto_provider.crypto(),
280
+ )),
281
+ Box::new(FINGERPRINT),
282
+ ]);
283
+ (msg, result)
284
+ };
285
+
286
+ if let Err(err) = result {
287
+ error!("{}", err);
288
+ } else {
289
+ self.send_binding_request(now, &msg, local_index, remote_index);
290
+ }
291
+ }
292
+
293
+ fn handle_success_response(
294
+ &mut self,
295
+ now: Instant,
296
+ m: &Message,
297
+ local_index: usize,
298
+ remote_index: usize,
299
+ remote_addr: SocketAddr,
300
+ ) {
301
+ if let Some(pending_request) = self.handle_inbound_binding_success(now, m.transaction_id) {
302
+ let transaction_addr = pending_request.destination;
303
+
304
+ // Assert that NAT is not symmetric
305
+ // https://tools.ietf.org/html/rfc8445#section-7.2.5.2.1
306
+ if transaction_addr != remote_addr {
307
+ debug!(
308
+ "discard message: transaction source and destination does not match expected({}), actual({})",
309
+ transaction_addr, remote_index
310
+ );
311
+ return;
312
+ }
313
+
314
+ trace!(
315
+ "inbound STUN (SuccessResponse) from {} to {}",
316
+ self.remote_candidates[remote_index], self.local_candidates[local_index]
317
+ );
318
+ let selected_pair_is_none = self.get_selected_pair().is_none();
319
+
320
+ if let Some(pair_index) = self.find_pair(local_index, remote_index) {
321
+ let p = &mut self.candidate_pairs[pair_index];
322
+ p.state = CandidatePairState::Succeeded;
323
+
324
+ // Calculate RTT and track response received
325
+ let rtt = now.duration_since(pending_request.timestamp);
326
+ p.on_response_received(rtt);
327
+
328
+ trace!(
329
+ "Found valid candidate pair: {} (local_addr {} <-> remote_addr {}), p.state: {}, isUseCandidate: {}, {}, rtt: {:.3}ms",
330
+ *p,
331
+ self.local_candidates[p.local_index].addr(),
332
+ self.remote_candidates[p.remote_index].addr(),
333
+ p.state,
334
+ pending_request.is_use_candidate,
335
+ selected_pair_is_none,
336
+ rtt.as_millis()
337
+ );
338
+ if pending_request.is_use_candidate && selected_pair_is_none {
339
+ self.set_selected_pair(Some(now), Some(pair_index));
340
+ }
341
+ } else {
342
+ // This shouldn't happen
343
+ error!("Success response from invalid candidate pair");
344
+ }
345
+ } else {
346
+ warn!(
347
+ "discard message from ({}), unknown TransactionID 0x{:?}",
348
+ self.remote_candidates[remote_index], m.transaction_id
349
+ );
350
+ }
351
+ }
352
+
353
+ fn handle_binding_request(
354
+ &mut self,
355
+ now: Instant,
356
+ m: &Message,
357
+ local_index: usize,
358
+ remote_index: usize,
359
+ ) {
360
+ self.send_binding_success(now, m, local_index, remote_index);
361
+ trace!("controllingSelector: sendBindingSuccess");
362
+
363
+ if let Some(pair_index) = self.find_pair(local_index, remote_index) {
364
+ // Track request received on the candidate pair
365
+ self.candidate_pairs[pair_index].on_request_received();
366
+
367
+ let p = &self.candidate_pairs[pair_index];
368
+ let nominated_pair_is_none = self.nominated_pair.is_none();
369
+
370
+ trace!(
371
+ "controllingSelector: after findPair {}, p.state: {}, {}",
372
+ p,
373
+ p.state,
374
+ nominated_pair_is_none,
375
+ //self.get_selected_pair().await.is_none() //, {}
376
+ );
377
+ if p.state == CandidatePairState::Succeeded
378
+ && nominated_pair_is_none
379
+ && self.get_selected_pair().is_none()
380
+ {
381
+ if let Some(best_pair_index) = self.get_best_available_pair() {
382
+ trace!(
383
+ "controllingSelector: getBestAvailableCandidatePair {}",
384
+ best_pair_index
385
+ );
386
+ if best_pair_index == pair_index
387
+ && self.is_nominatable(now, p.local_index, true)
388
+ && self.is_nominatable(now, p.remote_index, false)
389
+ {
390
+ trace!(
391
+ "The candidate ({}, {}) is the best candidate available, marking it as nominated",
392
+ p.local_index, p.remote_index
393
+ );
394
+ self.nominated_pair = Some(pair_index);
395
+ self.nominate_pair(now);
396
+ }
397
+ } else {
398
+ trace!("No best pair available");
399
+ }
400
+ }
401
+ } else {
402
+ trace!("controllingSelector: addPair");
403
+ self.add_pair(local_index, remote_index);
404
+ // Track request received on newly created pair
405
+ if let Some(pair_index) = self.find_pair(local_index, remote_index) {
406
+ self.candidate_pairs[pair_index].on_request_received();
407
+ }
408
+ }
409
+ }
410
+ }
411
+
412
+ impl ControlledSelector for Agent {
413
+ fn start(&mut self, _now: Instant) {}
414
+
415
+ fn contact_candidates(&mut self, now: Instant) {
416
+ // A lite selector should not contact candidates
417
+ if self.lite {
418
+ self.validate_selected_pair(now);
419
+ } else if self.get_selected_pair().is_some() {
420
+ if self.validate_selected_pair(now) {
421
+ self.check_keepalive(now);
422
+ }
423
+ } else {
424
+ self.ping_all_candidates(now);
425
+ }
426
+ }
427
+
428
+ fn ping_candidate(&mut self, now: Instant, local_index: usize, remote_index: usize) {
429
+ let (msg, result) = {
430
+ let Some(remote_credentials) = &self.ufrag_pwd.remote_credentials else {
431
+ error!("ufrag_pwd.remote_credentials is none");
432
+ return;
433
+ };
434
+
435
+ let username = remote_credentials.ufrag.clone()
436
+ + ":"
437
+ + self.ufrag_pwd.local_credentials.ufrag.as_str();
438
+ let mut msg = Message::new();
439
+ let result = msg.build(&[
440
+ Box::new(BINDING_REQUEST),
441
+ Box::new(TransactionId::new()),
442
+ Box::new(Username::new(ATTR_USERNAME, username)),
443
+ Box::new(AttrControlled(self.tie_breaker)),
444
+ Box::new(PriorityAttr(self.local_candidates[local_index].priority())),
445
+ Box::new(MessageIntegrity::new_short_term_integrity_with_provider(
446
+ remote_credentials.pwd.clone(),
447
+ self.crypto_provider.crypto(),
448
+ )),
449
+ Box::new(FINGERPRINT),
450
+ ]);
451
+ (msg, result)
452
+ };
453
+
454
+ if let Err(err) = result {
455
+ error!("{}", err);
456
+ } else {
457
+ self.send_binding_request(now, &msg, local_index, remote_index);
458
+ }
459
+ }
460
+
461
+ fn handle_success_response(
462
+ &mut self,
463
+ now: Instant,
464
+ m: &Message,
465
+ local_index: usize,
466
+ remote_index: usize,
467
+ remote_addr: SocketAddr,
468
+ ) {
469
+ // https://tools.ietf.org/html/rfc8445#section-7.3.1.5
470
+ // If the controlled agent does not accept the request from the
471
+ // controlling agent, the controlled agent MUST reject the nomination
472
+ // request with an appropriate error code response (e.g., 400)
473
+ // [RFC5389].
474
+
475
+ if let Some(pending_request) = self.handle_inbound_binding_success(now, m.transaction_id) {
476
+ let transaction_addr = pending_request.destination;
477
+
478
+ // Assert that NAT is not symmetric
479
+ // https://tools.ietf.org/html/rfc8445#section-7.2.5.2.1
480
+ if transaction_addr != remote_addr {
481
+ debug!(
482
+ "discard message: transaction source and destination does not match expected({}), actual({})",
483
+ transaction_addr, remote_index
484
+ );
485
+ return;
486
+ }
487
+
488
+ trace!(
489
+ "inbound STUN (SuccessResponse) from {} to {}",
490
+ self.remote_candidates[remote_index], self.local_candidates[local_index]
491
+ );
492
+
493
+ if let Some(pair_index) = self.find_pair(local_index, remote_index) {
494
+ let p = &mut self.candidate_pairs[pair_index];
495
+ p.state = CandidatePairState::Succeeded;
496
+
497
+ // Calculate RTT and track response received
498
+ let rtt = now.duration_since(pending_request.timestamp);
499
+ p.on_response_received(rtt);
500
+
501
+ trace!(
502
+ "Found valid candidate pair: {} (local_addr {} <-> remote_addr {}), rtt: {:.3}ms",
503
+ *p,
504
+ self.local_candidates[p.local_index].addr(),
505
+ self.remote_candidates[p.remote_index].addr(),
506
+ rtt.as_millis()
507
+ );
508
+ } else {
509
+ // This shouldn't happen
510
+ error!("Success response from invalid candidate pair");
511
+ }
512
+ } else {
513
+ warn!(
514
+ "discard message from ({}), unknown TransactionID 0x{:?}",
515
+ self.remote_candidates[remote_index], m.transaction_id
516
+ );
517
+ }
518
+ }
519
+
520
+ fn handle_binding_request(
521
+ &mut self,
522
+ now: Instant,
523
+ m: &Message,
524
+ local_index: usize,
525
+ remote_index: usize,
526
+ ) {
527
+ if self.find_pair(local_index, remote_index).is_none() {
528
+ self.add_pair(local_index, remote_index);
529
+ }
530
+
531
+ if let Some(pair_index) = self.find_pair(local_index, remote_index) {
532
+ // Track request received on the candidate pair
533
+ self.candidate_pairs[pair_index].on_request_received();
534
+
535
+ let p = &self.candidate_pairs[pair_index];
536
+ let use_candidate = m.contains(ATTR_USE_CANDIDATE);
537
+ if use_candidate {
538
+ // https://tools.ietf.org/html/rfc8445#section-7.3.1.5
539
+
540
+ if p.state == CandidatePairState::Succeeded {
541
+ // If the state of this pair is Succeeded, it means that the check
542
+ // previously sent by this pair produced a successful response and
543
+ // generated a valid pair (Section 7.2.5.3.2). The agent sets the
544
+ // nominated flag value of the valid pair to true.
545
+ if self.get_selected_pair().is_none() {
546
+ self.set_selected_pair(Some(now), Some(pair_index));
547
+ }
548
+ self.send_binding_success(now, m, local_index, remote_index);
549
+ } else {
550
+ // If the received Binding request triggered a new check to be
551
+ // enqueued in the triggered-check queue (Section 7.3.1.4), once the
552
+ // check is sent and if it generates a successful response, and
553
+ // generates a valid pair, the agent sets the nominated flag of the
554
+ // pair to true. If the request fails (Section 7.2.5.2), the agent
555
+ // MUST remove the candidate pair from the valid list, set the
556
+ // candidate pair state to Failed, and set the checklist state to
557
+ // Failed.
558
+ self.ping_candidate(now, local_index, remote_index);
559
+ }
560
+ } else {
561
+ self.send_binding_success(now, m, local_index, remote_index);
562
+ self.ping_candidate(now, local_index, remote_index);
563
+ }
564
+ }
565
+ }
566
+ }