@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,215 @@
|
|
|
1
|
+
//! Candidate pairs and their check state.
|
|
2
|
+
//!
|
|
3
|
+
//! ICE forms a pair from each compatible local/remote candidate combination and works through
|
|
4
|
+
//! them in priority order. A pair's combined priority is computed from both sides' priorities with
|
|
5
|
+
//! the controlling agent's dominating, so both agents derive the same ordering.
|
|
6
|
+
//!
|
|
7
|
+
//! [`CandidatePairState`](crate::candidate::candidate_pair::CandidatePairState) tracks how far a pair has got: waiting, in progress, succeeded or
|
|
8
|
+
//! failed. The controlling agent nominates one of the succeeded pairs, and that pair carries the
|
|
9
|
+
//! media.
|
|
10
|
+
use serde::{Deserialize, Serialize};
|
|
11
|
+
use std::fmt;
|
|
12
|
+
use std::time::Duration;
|
|
13
|
+
|
|
14
|
+
/// Represent the ICE candidate pair state.
|
|
15
|
+
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
16
|
+
#[non_exhaustive]
|
|
17
|
+
pub enum CandidatePairState {
|
|
18
|
+
#[default]
|
|
19
|
+
#[serde(rename = "unspecified")]
|
|
20
|
+
/// No state was set.
|
|
21
|
+
Unspecified = 0,
|
|
22
|
+
|
|
23
|
+
/// Means a check has not been performed for this pair.
|
|
24
|
+
#[serde(rename = "waiting")]
|
|
25
|
+
Waiting = 1,
|
|
26
|
+
|
|
27
|
+
/// Means a check has been sent for this pair, but the transaction is in progress.
|
|
28
|
+
#[serde(rename = "in-progress")]
|
|
29
|
+
InProgress = 2,
|
|
30
|
+
|
|
31
|
+
/// Means a check for this pair was already done and failed, either never producing any response
|
|
32
|
+
/// or producing an unrecoverable failure response.
|
|
33
|
+
#[serde(rename = "failed")]
|
|
34
|
+
Failed = 3,
|
|
35
|
+
|
|
36
|
+
/// Means a check for this pair was already done and produced a successful result.
|
|
37
|
+
#[serde(rename = "succeeded")]
|
|
38
|
+
Succeeded = 4,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
impl From<u8> for CandidatePairState {
|
|
42
|
+
fn from(v: u8) -> Self {
|
|
43
|
+
match v {
|
|
44
|
+
1 => Self::Waiting,
|
|
45
|
+
2 => Self::InProgress,
|
|
46
|
+
3 => Self::Failed,
|
|
47
|
+
4 => Self::Succeeded,
|
|
48
|
+
_ => Self::Unspecified,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
impl fmt::Display for CandidatePairState {
|
|
54
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
55
|
+
let s = match *self {
|
|
56
|
+
Self::Waiting => "waiting",
|
|
57
|
+
Self::InProgress => "in-progress",
|
|
58
|
+
Self::Failed => "failed",
|
|
59
|
+
Self::Succeeded => "succeeded",
|
|
60
|
+
Self::Unspecified => "unspecified",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
write!(f, "{s}")
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// Represents a combination of a local and remote candidate.
|
|
68
|
+
#[derive(Clone, Copy)]
|
|
69
|
+
pub struct CandidatePair {
|
|
70
|
+
/// Index of the local candidate in the agent's list.
|
|
71
|
+
pub local_index: usize,
|
|
72
|
+
/// Index of the remote candidate in the agent's list.
|
|
73
|
+
pub remote_index: usize,
|
|
74
|
+
/// The local candidate's priority.
|
|
75
|
+
pub local_priority: u32,
|
|
76
|
+
/// The remote candidate's priority.
|
|
77
|
+
pub remote_priority: u32,
|
|
78
|
+
pub(crate) ice_role_controlling: bool,
|
|
79
|
+
pub(crate) binding_request_count: u16,
|
|
80
|
+
pub(crate) state: CandidatePairState,
|
|
81
|
+
pub(crate) nominated: bool,
|
|
82
|
+
|
|
83
|
+
// STUN transaction stats
|
|
84
|
+
/// Total number of STUN connectivity check requests sent (not including retransmissions).
|
|
85
|
+
pub(crate) requests_sent: u64,
|
|
86
|
+
/// Total number of STUN connectivity check requests received.
|
|
87
|
+
pub(crate) requests_received: u64,
|
|
88
|
+
/// Total number of STUN connectivity check responses sent.
|
|
89
|
+
pub(crate) responses_sent: u64,
|
|
90
|
+
/// Total number of STUN connectivity check responses received.
|
|
91
|
+
pub(crate) responses_received: u64,
|
|
92
|
+
/// Total number of consent freshness requests sent.
|
|
93
|
+
pub(crate) consent_requests_sent: u64,
|
|
94
|
+
|
|
95
|
+
// RTT tracking
|
|
96
|
+
/// Sum of all round trip time measurements.
|
|
97
|
+
pub(crate) total_round_trip_time: Duration,
|
|
98
|
+
/// Latest round trip time measured.
|
|
99
|
+
pub(crate) current_round_trip_time: Duration,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
impl fmt::Debug for CandidatePair {
|
|
103
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
104
|
+
write!(
|
|
105
|
+
f,
|
|
106
|
+
"prio {} (local, prio {}) {} <-> {} (remote, prio {})",
|
|
107
|
+
self.priority(),
|
|
108
|
+
self.local_priority,
|
|
109
|
+
self.local_index,
|
|
110
|
+
self.remote_index,
|
|
111
|
+
self.remote_priority,
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
impl fmt::Display for CandidatePair {
|
|
117
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
118
|
+
write!(
|
|
119
|
+
f,
|
|
120
|
+
"prio {} (local, prio {}) {} <-> {} (remote, prio {})",
|
|
121
|
+
self.priority(),
|
|
122
|
+
self.local_priority,
|
|
123
|
+
self.local_index,
|
|
124
|
+
self.remote_index,
|
|
125
|
+
self.remote_priority,
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
impl PartialEq for CandidatePair {
|
|
131
|
+
fn eq(&self, other: &Self) -> bool {
|
|
132
|
+
self.local_index == other.local_index && self.remote_index == other.remote_index
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
impl CandidatePair {
|
|
137
|
+
#[must_use]
|
|
138
|
+
/// Forms a pair from a local and a remote candidate.
|
|
139
|
+
///
|
|
140
|
+
/// `controlling` selects which priority dominates in the pair's combined priority.
|
|
141
|
+
pub fn new(
|
|
142
|
+
local_index: usize,
|
|
143
|
+
remote_index: usize,
|
|
144
|
+
local_priority: u32,
|
|
145
|
+
remote_priority: u32,
|
|
146
|
+
ice_role_controlling: bool,
|
|
147
|
+
) -> Self {
|
|
148
|
+
Self {
|
|
149
|
+
local_index,
|
|
150
|
+
remote_index,
|
|
151
|
+
local_priority,
|
|
152
|
+
remote_priority,
|
|
153
|
+
ice_role_controlling,
|
|
154
|
+
state: CandidatePairState::Waiting,
|
|
155
|
+
binding_request_count: 0,
|
|
156
|
+
nominated: false,
|
|
157
|
+
// STUN transaction stats
|
|
158
|
+
requests_sent: 0,
|
|
159
|
+
requests_received: 0,
|
|
160
|
+
responses_sent: 0,
|
|
161
|
+
responses_received: 0,
|
|
162
|
+
consent_requests_sent: 0,
|
|
163
|
+
// RTT tracking
|
|
164
|
+
total_round_trip_time: Duration::ZERO,
|
|
165
|
+
current_round_trip_time: Duration::ZERO,
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/// RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
|
|
170
|
+
/// Let G be the priority for the candidate provided by the controlling
|
|
171
|
+
/// agent. Let D be the priority for the candidate provided by the
|
|
172
|
+
/// controlled agent.
|
|
173
|
+
/// pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
|
|
174
|
+
pub fn priority(&self) -> u64 {
|
|
175
|
+
let (g, d) = if self.ice_role_controlling {
|
|
176
|
+
(self.local_priority, self.remote_priority)
|
|
177
|
+
} else {
|
|
178
|
+
(self.remote_priority, self.local_priority)
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// 1<<32 overflows uint32; and if both g && d are
|
|
182
|
+
// maxUint32, this result would overflow uint64
|
|
183
|
+
((1 << 32_u64) - 1) * u64::from(std::cmp::min(g, d))
|
|
184
|
+
+ 2 * u64::from(std::cmp::max(g, d))
|
|
185
|
+
+ u64::from(g > d)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/// Called when a STUN binding request is sent.
|
|
189
|
+
pub fn on_request_sent(&mut self) {
|
|
190
|
+
self.requests_sent += 1;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/// Called when a STUN binding request is received.
|
|
194
|
+
pub fn on_request_received(&mut self) {
|
|
195
|
+
self.requests_received += 1;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/// Called when a STUN binding success response is sent.
|
|
199
|
+
pub fn on_response_sent(&mut self) {
|
|
200
|
+
self.responses_sent += 1;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/// Called when a STUN binding success response is received.
|
|
204
|
+
/// Also updates RTT measurements.
|
|
205
|
+
pub fn on_response_received(&mut self, rtt: Duration) {
|
|
206
|
+
self.responses_received += 1;
|
|
207
|
+
self.current_round_trip_time = rtt;
|
|
208
|
+
self.total_round_trip_time += rtt;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/// Called when a consent freshness request is sent (keepalive).
|
|
212
|
+
pub fn on_consent_request_sent(&mut self) {
|
|
213
|
+
self.consent_requests_sent += 1;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use crate::candidate::candidate_host::CandidateHostConfig;
|
|
3
|
+
use crate::candidate::candidate_pair::CandidatePair;
|
|
4
|
+
use crate::candidate::candidate_peer_reflexive::CandidatePeerReflexiveConfig;
|
|
5
|
+
use crate::candidate::candidate_relay::CandidateRelayConfig;
|
|
6
|
+
use crate::candidate::candidate_server_reflexive::CandidateServerReflexiveConfig;
|
|
7
|
+
use crate::candidate::{Candidate, CandidateConfig};
|
|
8
|
+
|
|
9
|
+
pub(crate) fn host_candidate() -> Result<Candidate> {
|
|
10
|
+
CandidateHostConfig {
|
|
11
|
+
base_config: CandidateConfig {
|
|
12
|
+
network: "udp".to_owned(),
|
|
13
|
+
address: "0.0.0.0".to_owned(),
|
|
14
|
+
component: COMPONENT_RTP,
|
|
15
|
+
..Default::default()
|
|
16
|
+
},
|
|
17
|
+
..Default::default()
|
|
18
|
+
}
|
|
19
|
+
.new_candidate_host()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
pub(crate) fn prflx_candidate() -> Result<Candidate> {
|
|
23
|
+
CandidatePeerReflexiveConfig {
|
|
24
|
+
base_config: CandidateConfig {
|
|
25
|
+
network: "udp".to_owned(),
|
|
26
|
+
address: "0.0.0.0".to_owned(),
|
|
27
|
+
component: COMPONENT_RTP,
|
|
28
|
+
..Default::default()
|
|
29
|
+
},
|
|
30
|
+
..Default::default()
|
|
31
|
+
}
|
|
32
|
+
.new_candidate_peer_reflexive()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
pub(crate) fn srflx_candidate() -> Result<Candidate> {
|
|
36
|
+
CandidateServerReflexiveConfig {
|
|
37
|
+
base_config: CandidateConfig {
|
|
38
|
+
network: "udp".to_owned(),
|
|
39
|
+
address: "0.0.0.0".to_owned(),
|
|
40
|
+
component: COMPONENT_RTP,
|
|
41
|
+
..Default::default()
|
|
42
|
+
},
|
|
43
|
+
..Default::default()
|
|
44
|
+
}
|
|
45
|
+
.new_candidate_server_reflexive()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
pub(crate) fn relay_candidate() -> Result<Candidate> {
|
|
49
|
+
CandidateRelayConfig {
|
|
50
|
+
base_config: CandidateConfig {
|
|
51
|
+
network: "udp".to_owned(),
|
|
52
|
+
address: "0.0.0.0".to_owned(),
|
|
53
|
+
component: COMPONENT_RTP,
|
|
54
|
+
..Default::default()
|
|
55
|
+
},
|
|
56
|
+
..Default::default()
|
|
57
|
+
}
|
|
58
|
+
.new_candidate_relay()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#[test]
|
|
62
|
+
fn test_candidate_pair_priority() -> Result<()> {
|
|
63
|
+
const HOST_INDEX: usize = 0;
|
|
64
|
+
const PRFLX_INDEX: usize = 1;
|
|
65
|
+
const SRFLX_INDEX: usize = 2;
|
|
66
|
+
const RELAY_INDEX: usize = 3;
|
|
67
|
+
|
|
68
|
+
let candidates = vec![
|
|
69
|
+
host_candidate()?,
|
|
70
|
+
prflx_candidate()?,
|
|
71
|
+
srflx_candidate()?,
|
|
72
|
+
relay_candidate()?,
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
let tests = vec![
|
|
76
|
+
(
|
|
77
|
+
CandidatePair::new(
|
|
78
|
+
HOST_INDEX,
|
|
79
|
+
HOST_INDEX,
|
|
80
|
+
candidates[HOST_INDEX].priority(),
|
|
81
|
+
candidates[HOST_INDEX].priority(),
|
|
82
|
+
false,
|
|
83
|
+
),
|
|
84
|
+
9151314440652587007,
|
|
85
|
+
),
|
|
86
|
+
(
|
|
87
|
+
CandidatePair::new(
|
|
88
|
+
HOST_INDEX,
|
|
89
|
+
HOST_INDEX,
|
|
90
|
+
candidates[HOST_INDEX].priority(),
|
|
91
|
+
candidates[HOST_INDEX].priority(),
|
|
92
|
+
true,
|
|
93
|
+
),
|
|
94
|
+
9151314440652587007,
|
|
95
|
+
),
|
|
96
|
+
(
|
|
97
|
+
CandidatePair::new(
|
|
98
|
+
HOST_INDEX,
|
|
99
|
+
PRFLX_INDEX,
|
|
100
|
+
candidates[HOST_INDEX].priority(),
|
|
101
|
+
candidates[PRFLX_INDEX].priority(),
|
|
102
|
+
true,
|
|
103
|
+
),
|
|
104
|
+
7998392936314175488,
|
|
105
|
+
),
|
|
106
|
+
(
|
|
107
|
+
CandidatePair::new(
|
|
108
|
+
HOST_INDEX,
|
|
109
|
+
PRFLX_INDEX,
|
|
110
|
+
candidates[HOST_INDEX].priority(),
|
|
111
|
+
candidates[PRFLX_INDEX].priority(),
|
|
112
|
+
false,
|
|
113
|
+
),
|
|
114
|
+
7998392936314175487,
|
|
115
|
+
),
|
|
116
|
+
(
|
|
117
|
+
CandidatePair::new(
|
|
118
|
+
HOST_INDEX,
|
|
119
|
+
SRFLX_INDEX,
|
|
120
|
+
candidates[HOST_INDEX].priority(),
|
|
121
|
+
candidates[SRFLX_INDEX].priority(),
|
|
122
|
+
true,
|
|
123
|
+
),
|
|
124
|
+
7277816996102668288,
|
|
125
|
+
),
|
|
126
|
+
(
|
|
127
|
+
CandidatePair::new(
|
|
128
|
+
HOST_INDEX,
|
|
129
|
+
SRFLX_INDEX,
|
|
130
|
+
candidates[HOST_INDEX].priority(),
|
|
131
|
+
candidates[SRFLX_INDEX].priority(),
|
|
132
|
+
false,
|
|
133
|
+
),
|
|
134
|
+
7277816996102668287,
|
|
135
|
+
),
|
|
136
|
+
(
|
|
137
|
+
CandidatePair::new(
|
|
138
|
+
HOST_INDEX,
|
|
139
|
+
RELAY_INDEX,
|
|
140
|
+
candidates[HOST_INDEX].priority(),
|
|
141
|
+
candidates[RELAY_INDEX].priority(),
|
|
142
|
+
true,
|
|
143
|
+
),
|
|
144
|
+
72057593987596288,
|
|
145
|
+
),
|
|
146
|
+
(
|
|
147
|
+
CandidatePair::new(
|
|
148
|
+
HOST_INDEX,
|
|
149
|
+
RELAY_INDEX,
|
|
150
|
+
candidates[HOST_INDEX].priority(),
|
|
151
|
+
candidates[RELAY_INDEX].priority(),
|
|
152
|
+
false,
|
|
153
|
+
),
|
|
154
|
+
72057593987596287,
|
|
155
|
+
),
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
for (pair, want) in tests {
|
|
159
|
+
let got = pair.priority();
|
|
160
|
+
assert_eq!(
|
|
161
|
+
got, want,
|
|
162
|
+
"CandidatePair({pair}).Priority() = {got}, want {want}"
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
Ok(())
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
#[test]
|
|
170
|
+
fn test_candidate_pair_equality() -> Result<()> {
|
|
171
|
+
const HOST_INDEX: usize = 0;
|
|
172
|
+
const PRFLX_INDEX: usize = 1;
|
|
173
|
+
const SRFLX_INDEX: usize = 2;
|
|
174
|
+
const RELAY_INDEX: usize = 3;
|
|
175
|
+
|
|
176
|
+
let candidates = vec![
|
|
177
|
+
host_candidate()?,
|
|
178
|
+
prflx_candidate()?,
|
|
179
|
+
srflx_candidate()?,
|
|
180
|
+
relay_candidate()?,
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
let pair_a = CandidatePair::new(
|
|
184
|
+
HOST_INDEX,
|
|
185
|
+
SRFLX_INDEX,
|
|
186
|
+
candidates[HOST_INDEX].priority(),
|
|
187
|
+
candidates[SRFLX_INDEX].priority(),
|
|
188
|
+
true,
|
|
189
|
+
);
|
|
190
|
+
let pair_b = CandidatePair::new(
|
|
191
|
+
HOST_INDEX,
|
|
192
|
+
SRFLX_INDEX,
|
|
193
|
+
candidates[HOST_INDEX].priority(),
|
|
194
|
+
candidates[SRFLX_INDEX].priority(),
|
|
195
|
+
false,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
assert_eq!(pair_a, pair_b, "Expected {pair_a} to equal {pair_b}");
|
|
199
|
+
|
|
200
|
+
Ok(())
|
|
201
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use crate::network_type::determine_network_type;
|
|
3
|
+
use crate::rand::generate_cand_id;
|
|
4
|
+
use shared::error::*;
|
|
5
|
+
|
|
6
|
+
/// The config required to create a new `CandidatePeerReflexive`.
|
|
7
|
+
#[derive(Default)]
|
|
8
|
+
pub struct CandidatePeerReflexiveConfig {
|
|
9
|
+
/// The fields shared by every candidate type.
|
|
10
|
+
pub base_config: CandidateConfig,
|
|
11
|
+
|
|
12
|
+
/// The base address this candidate was derived from, reported as `raddr`.
|
|
13
|
+
pub rel_addr: String,
|
|
14
|
+
/// The base port, reported as `rport`.
|
|
15
|
+
pub rel_port: u16,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
impl CandidatePeerReflexiveConfig {
|
|
19
|
+
/// Creates a new peer reflective candidate.
|
|
20
|
+
pub fn new_candidate_peer_reflexive(self) -> Result<Candidate> {
|
|
21
|
+
let mut candidate_id = self.base_config.candidate_id;
|
|
22
|
+
if candidate_id.is_empty() {
|
|
23
|
+
candidate_id = generate_cand_id();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let ip: IpAddr = match self.base_config.address.parse() {
|
|
27
|
+
Ok(ip) => ip,
|
|
28
|
+
Err(_) => return Err(Error::ErrAddressParseFailed),
|
|
29
|
+
};
|
|
30
|
+
let network_type = determine_network_type(&self.base_config.network, &ip)?;
|
|
31
|
+
|
|
32
|
+
Ok(Candidate {
|
|
33
|
+
id: candidate_id,
|
|
34
|
+
network_type,
|
|
35
|
+
candidate_type: CandidateType::PeerReflexive,
|
|
36
|
+
address: self.base_config.address,
|
|
37
|
+
port: self.base_config.port,
|
|
38
|
+
resolved_addr: SocketAddr::new(ip, self.base_config.port),
|
|
39
|
+
component: self.base_config.component,
|
|
40
|
+
foundation_override: self.base_config.foundation,
|
|
41
|
+
priority_override: self.base_config.priority,
|
|
42
|
+
related_address: Some(CandidateRelatedAddress {
|
|
43
|
+
address: self.rel_addr,
|
|
44
|
+
port: self.rel_port,
|
|
45
|
+
}),
|
|
46
|
+
..Candidate::default()
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use crate::network_type::determine_network_type;
|
|
3
|
+
use crate::rand::generate_cand_id;
|
|
4
|
+
use shared::error::*;
|
|
5
|
+
|
|
6
|
+
/// The config required to create a new `CandidateRelay`.
|
|
7
|
+
#[derive(Default)]
|
|
8
|
+
pub struct CandidateRelayConfig {
|
|
9
|
+
/// The fields shared by every candidate type.
|
|
10
|
+
pub base_config: CandidateConfig,
|
|
11
|
+
|
|
12
|
+
/// The base address this candidate was derived from, reported as `raddr`.
|
|
13
|
+
pub rel_addr: String,
|
|
14
|
+
/// The base port, reported as `rport`.
|
|
15
|
+
pub rel_port: u16,
|
|
16
|
+
|
|
17
|
+
/// The server this candidate was gathered from.
|
|
18
|
+
pub url: Option<String>,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl CandidateRelayConfig {
|
|
22
|
+
/// Creates a new relay candidate.
|
|
23
|
+
pub fn new_candidate_relay(self) -> Result<Candidate> {
|
|
24
|
+
let mut candidate_id = self.base_config.candidate_id;
|
|
25
|
+
if candidate_id.is_empty() {
|
|
26
|
+
candidate_id = generate_cand_id();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let ip: IpAddr = match self.base_config.address.parse() {
|
|
30
|
+
Ok(ip) => ip,
|
|
31
|
+
Err(_) => return Err(Error::ErrAddressParseFailed),
|
|
32
|
+
};
|
|
33
|
+
let network_type = determine_network_type(&self.base_config.network, &ip)?;
|
|
34
|
+
|
|
35
|
+
Ok(Candidate {
|
|
36
|
+
id: candidate_id,
|
|
37
|
+
network_type,
|
|
38
|
+
candidate_type: CandidateType::Relay,
|
|
39
|
+
address: self.base_config.address,
|
|
40
|
+
port: self.base_config.port,
|
|
41
|
+
resolved_addr: SocketAddr::new(ip, self.base_config.port),
|
|
42
|
+
component: self.base_config.component,
|
|
43
|
+
foundation_override: self.base_config.foundation,
|
|
44
|
+
priority_override: self.base_config.priority,
|
|
45
|
+
related_address: Some(CandidateRelatedAddress {
|
|
46
|
+
address: self.rel_addr,
|
|
47
|
+
port: self.rel_port,
|
|
48
|
+
}),
|
|
49
|
+
url: self.url,
|
|
50
|
+
..Candidate::default()
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
use std::result::Result;
|
|
2
|
+
use std::time::Duration;
|
|
3
|
+
|
|
4
|
+
use tokio::net::UdpSocket;
|
|
5
|
+
use turn::auth::AuthHandler;
|
|
6
|
+
|
|
7
|
+
use super::*;
|
|
8
|
+
use crate::agent::agent_config::AgentConfig;
|
|
9
|
+
use crate::agent::agent_vnet_test::{connect_with_vnet, on_connected};
|
|
10
|
+
use crate::agent::Agent;
|
|
11
|
+
use crate::error::Error;
|
|
12
|
+
use crate::url::{ProtoType, SchemeType, Url};
|
|
13
|
+
|
|
14
|
+
pub(crate) struct OptimisticAuthHandler;
|
|
15
|
+
|
|
16
|
+
impl AuthHandler for OptimisticAuthHandler {
|
|
17
|
+
fn auth_handle(
|
|
18
|
+
&self,
|
|
19
|
+
_username: &str,
|
|
20
|
+
_realm: &str,
|
|
21
|
+
_src_addr: SocketAddr,
|
|
22
|
+
) -> Result<Vec<u8>, turn::Error> {
|
|
23
|
+
Ok(turn::auth::generate_auth_key(
|
|
24
|
+
"username",
|
|
25
|
+
"webrtc.rs",
|
|
26
|
+
"password",
|
|
27
|
+
))
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//use std::io::Write;
|
|
32
|
+
|
|
33
|
+
#[tokio::test]
|
|
34
|
+
async fn test_relay_only_connection() -> Result<(), Error> {
|
|
35
|
+
/*env_logger::Builder::new()
|
|
36
|
+
.format(|buf, record| {
|
|
37
|
+
writeln!(
|
|
38
|
+
buf,
|
|
39
|
+
"{}:{} [{}] {} - {}",
|
|
40
|
+
record.file().unwrap_or("unknown"),
|
|
41
|
+
record.line().unwrap_or(0),
|
|
42
|
+
record.level(),
|
|
43
|
+
chrono::Local::now().format("%H:%M:%S.%6f"),
|
|
44
|
+
record.args()
|
|
45
|
+
)
|
|
46
|
+
})
|
|
47
|
+
.filter(None, LevelFilter::Trace)
|
|
48
|
+
.init();*/
|
|
49
|
+
|
|
50
|
+
let server_listener = Arc::new(UdpSocket::bind("127.0.0.1:0").await?);
|
|
51
|
+
let server_port = server_listener.local_addr()?.port();
|
|
52
|
+
|
|
53
|
+
let server = turn::server::Server::new(turn::server::config::ServerConfig {
|
|
54
|
+
realm: "webrtc.rs".to_owned(),
|
|
55
|
+
auth_handler: Arc::new(OptimisticAuthHandler {}),
|
|
56
|
+
conn_configs: vec![turn::server::config::ConnConfig {
|
|
57
|
+
conn: server_listener,
|
|
58
|
+
relay_addr_generator: Box::new(turn::relay::relay_none::RelayAddressGeneratorNone {
|
|
59
|
+
address: "127.0.0.1".to_owned(),
|
|
60
|
+
net: Arc::new(util::vnet::net::Net::new(None)),
|
|
61
|
+
}),
|
|
62
|
+
}],
|
|
63
|
+
channel_bind_timeout: Duration::from_secs(0),
|
|
64
|
+
alloc_close_notify: None,
|
|
65
|
+
})
|
|
66
|
+
.await?;
|
|
67
|
+
|
|
68
|
+
let cfg0 = AgentConfig {
|
|
69
|
+
network_types: supported_network_types(),
|
|
70
|
+
urls: vec![Url {
|
|
71
|
+
scheme: SchemeType::Turn,
|
|
72
|
+
host: "127.0.0.1".to_owned(),
|
|
73
|
+
username: "username".to_owned(),
|
|
74
|
+
password: "password".to_owned(),
|
|
75
|
+
port: server_port,
|
|
76
|
+
proto: ProtoType::Udp,
|
|
77
|
+
}],
|
|
78
|
+
candidate_types: vec![CandidateType::Relay],
|
|
79
|
+
..Default::default()
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
let a_agent = Arc::new(Agent::new(cfg0).await?);
|
|
83
|
+
let (a_notifier, mut a_connected) = on_connected();
|
|
84
|
+
a_agent.on_connection_state_change(a_notifier);
|
|
85
|
+
|
|
86
|
+
let cfg1 = AgentConfig {
|
|
87
|
+
network_types: supported_network_types(),
|
|
88
|
+
urls: vec![Url {
|
|
89
|
+
scheme: SchemeType::Turn,
|
|
90
|
+
host: "127.0.0.1".to_owned(),
|
|
91
|
+
username: "username".to_owned(),
|
|
92
|
+
password: "password".to_owned(),
|
|
93
|
+
port: server_port,
|
|
94
|
+
proto: ProtoType::Udp,
|
|
95
|
+
}],
|
|
96
|
+
candidate_types: vec![CandidateType::Relay],
|
|
97
|
+
..Default::default()
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
let b_agent = Arc::new(Agent::new(cfg1).await?);
|
|
101
|
+
let (b_notifier, mut b_connected) = on_connected();
|
|
102
|
+
b_agent.on_connection_state_change(b_notifier);
|
|
103
|
+
|
|
104
|
+
connect_with_vnet(&a_agent, &b_agent).await?;
|
|
105
|
+
|
|
106
|
+
let _ = a_connected.recv().await;
|
|
107
|
+
let _ = b_connected.recv().await;
|
|
108
|
+
|
|
109
|
+
a_agent.close().await?;
|
|
110
|
+
b_agent.close().await?;
|
|
111
|
+
server.close().await?;
|
|
112
|
+
|
|
113
|
+
Ok(())
|
|
114
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use crate::network_type::determine_network_type;
|
|
3
|
+
use crate::rand::generate_cand_id;
|
|
4
|
+
use shared::error::*;
|
|
5
|
+
|
|
6
|
+
/// The config required to create a new `CandidateServerReflexive`.
|
|
7
|
+
#[derive(Default)]
|
|
8
|
+
pub struct CandidateServerReflexiveConfig {
|
|
9
|
+
/// The fields shared by every candidate type.
|
|
10
|
+
pub base_config: CandidateConfig,
|
|
11
|
+
|
|
12
|
+
/// The base address this candidate was derived from, reported as `raddr`.
|
|
13
|
+
pub rel_addr: String,
|
|
14
|
+
/// The base port, reported as `rport`.
|
|
15
|
+
pub rel_port: u16,
|
|
16
|
+
|
|
17
|
+
/// The server this candidate was gathered from.
|
|
18
|
+
pub url: Option<String>,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl CandidateServerReflexiveConfig {
|
|
22
|
+
/// Creates a new server reflective candidate.
|
|
23
|
+
pub fn new_candidate_server_reflexive(self) -> Result<Candidate> {
|
|
24
|
+
let mut candidate_id = self.base_config.candidate_id;
|
|
25
|
+
if candidate_id.is_empty() {
|
|
26
|
+
candidate_id = generate_cand_id();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let ip: IpAddr = match self.base_config.address.parse() {
|
|
30
|
+
Ok(ip) => ip,
|
|
31
|
+
Err(_) => return Err(Error::ErrAddressParseFailed),
|
|
32
|
+
};
|
|
33
|
+
let network_type = determine_network_type(&self.base_config.network, &ip)?;
|
|
34
|
+
|
|
35
|
+
Ok(Candidate {
|
|
36
|
+
id: candidate_id,
|
|
37
|
+
network_type,
|
|
38
|
+
candidate_type: CandidateType::ServerReflexive,
|
|
39
|
+
address: self.base_config.address,
|
|
40
|
+
port: self.base_config.port,
|
|
41
|
+
resolved_addr: SocketAddr::new(ip, self.base_config.port),
|
|
42
|
+
component: self.base_config.component,
|
|
43
|
+
foundation_override: self.base_config.foundation,
|
|
44
|
+
priority_override: self.base_config.priority,
|
|
45
|
+
related_address: Some(CandidateRelatedAddress {
|
|
46
|
+
address: self.rel_addr,
|
|
47
|
+
port: self.rel_port,
|
|
48
|
+
}),
|
|
49
|
+
url: self.url,
|
|
50
|
+
..Candidate::default()
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|