@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.
- package/README.md +45 -18
- package/bin/desklink-host.mjs +5 -1
- package/dist/bridge.d.ts +7 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +55 -7
- package/dist/bridge.js.map +1 -1
- package/dist/engineProcess.d.ts +9 -2
- package/dist/engineProcess.d.ts.map +1 -1
- package/dist/engineProcess.js +26 -15
- package/dist/engineProcess.js.map +1 -1
- package/dist/protocol.d.ts +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +1 -1
- package/dist/protocol.js.map +1 -1
- package/docs/BOUNDARY.md +4 -1
- package/docs/PROTOCOL.md +20 -5
- 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/main.rs +3 -2
- package/engine/src/peer.rs +231 -1
- package/engine/src/portal.rs +0 -18
- package/engine/src/protocol.rs +0 -162
- package/engine/src/session.rs +37 -1
- 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,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
|
+
}
|