@desklink/host 0.5.3 → 0.5.6
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 +33 -19
- package/dist/bridge.js +3 -3
- package/dist/bridge.js.map +1 -1
- package/dist/engineProcess.d.ts +5 -0
- package/dist/engineProcess.d.ts.map +1 -1
- package/dist/engineProcess.js +6 -3
- package/dist/engineProcess.js.map +1 -1
- package/dist/protocol.d.ts +39 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/docs/BOUNDARY.md +4 -2
- package/docs/PROTOCOL.md +70 -7
- package/engine/Cargo.lock +6 -8
- package/engine/Cargo.toml +13 -1
- package/engine/src/audio.rs +398 -0
- 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 +1 -28
- package/engine/src/main.rs +22 -0
- package/engine/src/peer.rs +297 -0
- package/engine/src/portal.rs +0 -18
- package/engine/src/protocol.rs +22 -162
- package/engine/src/session.rs +176 -3
- package/engine/src/win.rs +1 -0
- package/engine/src/x11.rs +0 -13
- package/engine/vendor/rtc-ice/Cargo.toml +137 -0
- package/engine/vendor/rtc-ice/DESKLINK-PATCH.md +111 -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 +647 -0
- package/engine/vendor/rtc-ice/src/agent/agent_stats.rs +292 -0
- package/engine/vendor/rtc-ice/src/agent/agent_test.rs +3594 -0
- package/engine/vendor/rtc-ice/src/agent/mod.rs +1753 -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/dl_trace.rs +49 -0
- package/engine/vendor/rtc-ice/src/lib.rs +88 -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,91 @@
|
|
|
1
|
+
use crypto::RTCRandom;
|
|
2
|
+
use shared::error::{Error, Result};
|
|
3
|
+
use shared::util::generate_crypto_random_string;
|
|
4
|
+
|
|
5
|
+
#[cfg(test)]
|
|
6
|
+
mod rand_test;
|
|
7
|
+
|
|
8
|
+
const RUNES_ALPHA: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
9
|
+
const RUNES_CANDIDATE_ID_FOUNDATION: &[u8] =
|
|
10
|
+
b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/+";
|
|
11
|
+
|
|
12
|
+
const LEN_UFRAG: usize = 16;
|
|
13
|
+
const LEN_PWD: usize = 32;
|
|
14
|
+
|
|
15
|
+
/// <https://tools.ietf.org/html/rfc5245#section-15.1>
|
|
16
|
+
/// candidate-id = "candidate" ":" foundation
|
|
17
|
+
/// foundation = 1*32ice-char
|
|
18
|
+
/// ice-char = ALPHA / DIGIT / "+" / "/"
|
|
19
|
+
///
|
|
20
|
+
/// Candidate IDs provide local uniqueness and diagnostics; they are not credentials or
|
|
21
|
+
/// cryptographic identities. This standalone helper therefore uses `rand`'s thread-local CSPRNG
|
|
22
|
+
/// rather than requiring a crypto provider.
|
|
23
|
+
pub fn generate_cand_id() -> String {
|
|
24
|
+
format!(
|
|
25
|
+
"candidate:{}",
|
|
26
|
+
generate_crypto_random_string(32, RUNES_CANDIDATE_ID_FOUNDATION)
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fn generate_string_with_random(
|
|
31
|
+
length: usize,
|
|
32
|
+
alphabet: &[u8],
|
|
33
|
+
random: &dyn RTCRandom,
|
|
34
|
+
) -> Result<String> {
|
|
35
|
+
debug_assert!(!alphabet.is_empty() && alphabet.len() <= u8::MAX as usize + 1);
|
|
36
|
+
|
|
37
|
+
let acceptance_limit = 256 - (256 % alphabet.len());
|
|
38
|
+
let mut output = String::with_capacity(length);
|
|
39
|
+
let mut random_bytes = [0_u8; 64];
|
|
40
|
+
while output.len() < length {
|
|
41
|
+
random
|
|
42
|
+
.fill(&mut random_bytes)
|
|
43
|
+
.map_err(|error| Error::Crypto(error.to_string()))?;
|
|
44
|
+
for byte in random_bytes {
|
|
45
|
+
if byte as usize >= acceptance_limit {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
output.push(alphabet[byte as usize % alphabet.len()] as char);
|
|
49
|
+
if output.len() == length {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
Ok(output)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Generates an ICE password with `rand`'s thread-local CSPRNG.
|
|
58
|
+
///
|
|
59
|
+
/// ICE agents use the provider-backed internal variant. This function remains as a standalone
|
|
60
|
+
/// compatibility helper for callers that do not own an [`crypto::RTCCryptoProvider`].
|
|
61
|
+
pub fn generate_pwd() -> String {
|
|
62
|
+
generate_crypto_random_string(LEN_PWD, RUNES_ALPHA)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Generates an ICE password using an explicitly supplied cryptographically secure random source.
|
|
66
|
+
pub(crate) fn generate_pwd_with_random(random: &dyn RTCRandom) -> Result<String> {
|
|
67
|
+
generate_string_with_random(LEN_PWD, RUNES_ALPHA, random)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// Generates the 64-bit ICE role-conflict tie breaker from the agent's random provider.
|
|
71
|
+
pub(crate) fn generate_tie_breaker(random: &dyn RTCRandom) -> Result<u64> {
|
|
72
|
+
let mut bytes = [0_u8; std::mem::size_of::<u64>()];
|
|
73
|
+
random
|
|
74
|
+
.fill(&mut bytes)
|
|
75
|
+
.map_err(|error| Error::Crypto(error.to_string()))?;
|
|
76
|
+
Ok(u64::from_be_bytes(bytes))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Generates an ICE username fragment with `rand`'s thread-local CSPRNG.
|
|
80
|
+
///
|
|
81
|
+
/// ICE agents use the provider-backed internal variant. This function remains as a standalone
|
|
82
|
+
/// compatibility helper for callers that do not own an [`crypto::RTCCryptoProvider`].
|
|
83
|
+
pub fn generate_ufrag() -> String {
|
|
84
|
+
generate_crypto_random_string(LEN_UFRAG, RUNES_ALPHA)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Generates an ICE username fragment using an explicitly supplied cryptographically secure random
|
|
88
|
+
/// source.
|
|
89
|
+
pub(crate) fn generate_ufrag_with_random(random: &dyn RTCRandom) -> Result<String> {
|
|
90
|
+
generate_string_with_random(LEN_UFRAG, RUNES_ALPHA, random)
|
|
91
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use crypto::{CryptoError, RTCRandom};
|
|
3
|
+
use shared::error::Result;
|
|
4
|
+
|
|
5
|
+
struct FixedRandom(u8);
|
|
6
|
+
|
|
7
|
+
impl RTCRandom for FixedRandom {
|
|
8
|
+
fn fill(&self, output: &mut [u8]) -> std::result::Result<(), CryptoError> {
|
|
9
|
+
output.fill(self.0);
|
|
10
|
+
Ok(())
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
struct FailingRandom;
|
|
15
|
+
|
|
16
|
+
impl RTCRandom for FailingRandom {
|
|
17
|
+
fn fill(&self, _output: &mut [u8]) -> std::result::Result<(), CryptoError> {
|
|
18
|
+
Err(CryptoError::RandomnessFailed)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#[test]
|
|
23
|
+
fn provider_backed_credentials_have_required_lengths_and_alphabet() -> Result<()> {
|
|
24
|
+
let random = FixedRandom(0);
|
|
25
|
+
let ufrag = generate_ufrag_with_random(&random)?;
|
|
26
|
+
let password = generate_pwd_with_random(&random)?;
|
|
27
|
+
|
|
28
|
+
assert_eq!(ufrag.len(), LEN_UFRAG);
|
|
29
|
+
assert_eq!(password.len(), LEN_PWD);
|
|
30
|
+
assert!(ufrag.bytes().all(|byte| RUNES_ALPHA.contains(&byte)));
|
|
31
|
+
assert!(password.bytes().all(|byte| RUNES_ALPHA.contains(&byte)));
|
|
32
|
+
Ok(())
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[test]
|
|
36
|
+
fn provider_backed_credentials_propagate_randomness_failure() {
|
|
37
|
+
assert!(matches!(
|
|
38
|
+
generate_pwd_with_random(&FailingRandom),
|
|
39
|
+
Err(Error::Crypto(_))
|
|
40
|
+
));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#[test]
|
|
44
|
+
fn provider_backed_tie_breaker_uses_all_random_bytes() -> Result<()> {
|
|
45
|
+
assert_eq!(
|
|
46
|
+
generate_tie_breaker(&FixedRandom(0x2a))?,
|
|
47
|
+
u64::from_be_bytes([0x2a; 8])
|
|
48
|
+
);
|
|
49
|
+
Ok(())
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#[test]
|
|
53
|
+
fn provider_backed_tie_breaker_propagates_randomness_failure() {
|
|
54
|
+
assert!(matches!(
|
|
55
|
+
generate_tie_breaker(&FailingRandom),
|
|
56
|
+
Err(Error::Crypto(_))
|
|
57
|
+
));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#[test]
|
|
61
|
+
fn test_random_generator_collision() -> Result<()> {
|
|
62
|
+
let test_cases = vec![
|
|
63
|
+
(
|
|
64
|
+
"CandidateID",
|
|
65
|
+
0, /*||-> String {
|
|
66
|
+
generate_cand_id()
|
|
67
|
+
},*/
|
|
68
|
+
),
|
|
69
|
+
(
|
|
70
|
+
"PWD", 1, /*||-> String {
|
|
71
|
+
generate_pwd()
|
|
72
|
+
},*/
|
|
73
|
+
),
|
|
74
|
+
(
|
|
75
|
+
"Ufrag", 2, /*|| ->String {
|
|
76
|
+
generate_ufrag()
|
|
77
|
+
},*/
|
|
78
|
+
),
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
const N: usize = 10;
|
|
82
|
+
const ITERATION: usize = 10;
|
|
83
|
+
|
|
84
|
+
for (name, test_case) in test_cases {
|
|
85
|
+
for _ in 0..ITERATION {
|
|
86
|
+
let mut rs = vec![];
|
|
87
|
+
|
|
88
|
+
for _ in 0..N {
|
|
89
|
+
let s = if test_case == 0 {
|
|
90
|
+
generate_cand_id()
|
|
91
|
+
} else if test_case == 1 {
|
|
92
|
+
generate_pwd()
|
|
93
|
+
} else {
|
|
94
|
+
generate_ufrag()
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
rs.push(s);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
assert_eq!(rs.len(), N, "{name} Failed to generate randoms");
|
|
101
|
+
|
|
102
|
+
for i in 0..N {
|
|
103
|
+
for j in i + 1..N {
|
|
104
|
+
assert_ne!(
|
|
105
|
+
rs[i], rs[j],
|
|
106
|
+
"{}: generateRandString caused collision: {} == {}",
|
|
107
|
+
name, rs[i], rs[j],
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
Ok(())
|
|
115
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#[cfg(test)]
|
|
2
|
+
mod state_test;
|
|
3
|
+
|
|
4
|
+
use std::fmt;
|
|
5
|
+
|
|
6
|
+
/// An enum showing the state of a ICE Connection List of supported States.
|
|
7
|
+
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
|
|
8
|
+
#[non_exhaustive]
|
|
9
|
+
pub enum ConnectionState {
|
|
10
|
+
/// No state was set.
|
|
11
|
+
#[default]
|
|
12
|
+
Unspecified,
|
|
13
|
+
|
|
14
|
+
/// ICE agent is gathering addresses.
|
|
15
|
+
New,
|
|
16
|
+
|
|
17
|
+
/// ICE agent has been given local and remote candidates, and is attempting to find a match.
|
|
18
|
+
Checking,
|
|
19
|
+
|
|
20
|
+
/// ICE agent has a pairing, but is still checking other pairs.
|
|
21
|
+
Connected,
|
|
22
|
+
|
|
23
|
+
/// ICE agent has finished.
|
|
24
|
+
Completed,
|
|
25
|
+
|
|
26
|
+
/// ICE agent never could successfully connect.
|
|
27
|
+
Failed,
|
|
28
|
+
|
|
29
|
+
/// ICE agent connected successfully, but has entered a failed state.
|
|
30
|
+
Disconnected,
|
|
31
|
+
|
|
32
|
+
/// ICE agent has finished and is no longer handling requests.
|
|
33
|
+
Closed,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
impl fmt::Display for ConnectionState {
|
|
37
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
38
|
+
let s = match *self {
|
|
39
|
+
Self::Unspecified => "Unspecified",
|
|
40
|
+
Self::New => "New",
|
|
41
|
+
Self::Checking => "Checking",
|
|
42
|
+
Self::Connected => "Connected",
|
|
43
|
+
Self::Completed => "Completed",
|
|
44
|
+
Self::Failed => "Failed",
|
|
45
|
+
Self::Disconnected => "Disconnected",
|
|
46
|
+
Self::Closed => "Closed",
|
|
47
|
+
};
|
|
48
|
+
write!(f, "{s}")
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
impl From<u8> for ConnectionState {
|
|
53
|
+
fn from(v: u8) -> Self {
|
|
54
|
+
match v {
|
|
55
|
+
1 => Self::New,
|
|
56
|
+
2 => Self::Checking,
|
|
57
|
+
3 => Self::Connected,
|
|
58
|
+
4 => Self::Completed,
|
|
59
|
+
5 => Self::Failed,
|
|
60
|
+
6 => Self::Disconnected,
|
|
61
|
+
7 => Self::Closed,
|
|
62
|
+
_ => Self::Unspecified,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// Describes the state of the candidate gathering process.
|
|
68
|
+
#[derive(Default, PartialEq, Eq, Copy, Clone)]
|
|
69
|
+
#[non_exhaustive]
|
|
70
|
+
pub enum GatheringState {
|
|
71
|
+
/// No state was set.
|
|
72
|
+
#[default]
|
|
73
|
+
Unspecified,
|
|
74
|
+
|
|
75
|
+
/// Indicates candidate gathering is not yet started.
|
|
76
|
+
New,
|
|
77
|
+
|
|
78
|
+
/// Indicates candidate gathering is ongoing.
|
|
79
|
+
Gathering,
|
|
80
|
+
|
|
81
|
+
/// Indicates candidate gathering has been completed.
|
|
82
|
+
Complete,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
impl From<u8> for GatheringState {
|
|
86
|
+
fn from(v: u8) -> Self {
|
|
87
|
+
match v {
|
|
88
|
+
1 => Self::New,
|
|
89
|
+
2 => Self::Gathering,
|
|
90
|
+
3 => Self::Complete,
|
|
91
|
+
_ => Self::Unspecified,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
impl fmt::Display for GatheringState {
|
|
97
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
98
|
+
let s = match *self {
|
|
99
|
+
Self::New => "new",
|
|
100
|
+
Self::Gathering => "gathering",
|
|
101
|
+
Self::Complete => "complete",
|
|
102
|
+
Self::Unspecified => "unspecified",
|
|
103
|
+
};
|
|
104
|
+
write!(f, "{s}")
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use shared::error::Result;
|
|
3
|
+
|
|
4
|
+
#[test]
|
|
5
|
+
fn test_connected_state_string() -> Result<()> {
|
|
6
|
+
let tests = vec![
|
|
7
|
+
(ConnectionState::Unspecified, "Unspecified"),
|
|
8
|
+
(ConnectionState::New, "New"),
|
|
9
|
+
(ConnectionState::Checking, "Checking"),
|
|
10
|
+
(ConnectionState::Connected, "Connected"),
|
|
11
|
+
(ConnectionState::Completed, "Completed"),
|
|
12
|
+
(ConnectionState::Failed, "Failed"),
|
|
13
|
+
(ConnectionState::Disconnected, "Disconnected"),
|
|
14
|
+
(ConnectionState::Closed, "Closed"),
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
for (connection_state, expected_string) in tests {
|
|
18
|
+
assert_eq!(
|
|
19
|
+
connection_state.to_string(),
|
|
20
|
+
expected_string,
|
|
21
|
+
"testCase: {expected_string} vs {connection_state}",
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Ok(())
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#[test]
|
|
29
|
+
fn test_gathering_state_string() -> Result<()> {
|
|
30
|
+
let tests = vec![
|
|
31
|
+
(GatheringState::Unspecified, "unspecified"),
|
|
32
|
+
(GatheringState::New, "new"),
|
|
33
|
+
(GatheringState::Gathering, "gathering"),
|
|
34
|
+
(GatheringState::Complete, "complete"),
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
for (gathering_state, expected_string) in tests {
|
|
38
|
+
assert_eq!(
|
|
39
|
+
gathering_state.to_string(),
|
|
40
|
+
expected_string,
|
|
41
|
+
"testCase: {expected_string} vs {gathering_state}",
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
Ok(())
|
|
46
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
use std::time::Instant;
|
|
2
|
+
|
|
3
|
+
use crate::candidate::candidate_pair::CandidatePairState;
|
|
4
|
+
use crate::candidate::*;
|
|
5
|
+
|
|
6
|
+
/// CandidatePairStats contains ICE candidate pair statistics.
|
|
7
|
+
#[derive(Debug, Clone)]
|
|
8
|
+
pub struct CandidatePairStats {
|
|
9
|
+
/// The timestamp associated with this object.
|
|
10
|
+
pub timestamp: Instant,
|
|
11
|
+
|
|
12
|
+
/// The id of the local candidate.
|
|
13
|
+
pub local_candidate_id: String,
|
|
14
|
+
|
|
15
|
+
/// The id of the remote candidate.
|
|
16
|
+
pub remote_candidate_id: String,
|
|
17
|
+
|
|
18
|
+
/// The state of the checklist for the local and remote
|
|
19
|
+
/// candidates in a pair.
|
|
20
|
+
pub state: CandidatePairState,
|
|
21
|
+
|
|
22
|
+
/// True when this valid pair that should be used for media
|
|
23
|
+
/// if it is the highest-priority one amongst those whose nominated flag is set.
|
|
24
|
+
pub nominated: bool,
|
|
25
|
+
|
|
26
|
+
/// The total number of packets sent on this candidate pair.
|
|
27
|
+
pub packets_sent: u32,
|
|
28
|
+
|
|
29
|
+
/// The total number of packets received on this candidate pair.
|
|
30
|
+
pub packets_received: u32,
|
|
31
|
+
|
|
32
|
+
/// The total number of payload bytes sent on this candidate pair
|
|
33
|
+
/// not including headers or padding.
|
|
34
|
+
pub bytes_sent: u64,
|
|
35
|
+
|
|
36
|
+
/// The total number of payload bytes received on this candidate pair
|
|
37
|
+
/// not including headers or padding.
|
|
38
|
+
pub bytes_received: u64,
|
|
39
|
+
|
|
40
|
+
/// The timestamp at which the last packet was
|
|
41
|
+
/// sent on this particular candidate pair, excluding STUN packets.
|
|
42
|
+
pub last_packet_sent_timestamp: Instant,
|
|
43
|
+
|
|
44
|
+
/// The timestamp at which the last packet
|
|
45
|
+
/// was received on this particular candidate pair, excluding STUN packets.
|
|
46
|
+
pub last_packet_received_timestamp: Instant,
|
|
47
|
+
|
|
48
|
+
/// The timestamp at which the first STUN request
|
|
49
|
+
/// was sent on this particular candidate pair.
|
|
50
|
+
pub first_request_timestamp: Instant,
|
|
51
|
+
|
|
52
|
+
/// The timestamp at which the last STUN request
|
|
53
|
+
/// was sent on this particular candidate pair. The average interval between two
|
|
54
|
+
/// consecutive connectivity checks sent can be calculated with
|
|
55
|
+
/// (last_request_timestamp - first_request_timestamp) / requests_sent.
|
|
56
|
+
pub last_request_timestamp: Instant,
|
|
57
|
+
|
|
58
|
+
/// The timestamp at which the last STUN response
|
|
59
|
+
/// was received on this particular candidate pair.
|
|
60
|
+
pub last_response_timestamp: Instant,
|
|
61
|
+
|
|
62
|
+
/// The sum of all round trip time measurements
|
|
63
|
+
/// in seconds since the beginning of the session, based on STUN connectivity
|
|
64
|
+
/// check responses (responses_received), including those that reply to requests
|
|
65
|
+
/// that are sent in order to verify consent. The average round trip time can
|
|
66
|
+
/// be computed from total_round_trip_time by dividing it by responses_received.
|
|
67
|
+
pub total_round_trip_time: f64,
|
|
68
|
+
|
|
69
|
+
/// The latest round trip time measured in seconds,
|
|
70
|
+
/// computed from both STUN connectivity checks, including those that are sent
|
|
71
|
+
/// for consent verification.
|
|
72
|
+
pub current_round_trip_time: f64,
|
|
73
|
+
|
|
74
|
+
/// Calculated by the underlying congestion control
|
|
75
|
+
/// by combining the available bitrate for all the outgoing RTP streams using
|
|
76
|
+
/// this candidate pair. The bitrate measurement does not count the size of the
|
|
77
|
+
/// ip or other transport layers like TCP or UDP. It is similar to the TIAS defined
|
|
78
|
+
/// in RFC 3890, i.e., it is measured in bits per second and the bitrate is calculated
|
|
79
|
+
/// over a 1 second window.
|
|
80
|
+
pub available_outgoing_bitrate: f64,
|
|
81
|
+
|
|
82
|
+
/// Calculated by the underlying congestion control
|
|
83
|
+
/// by combining the available bitrate for all the incoming RTP streams using
|
|
84
|
+
/// this candidate pair. The bitrate measurement does not count the size of the
|
|
85
|
+
/// ip or other transport layers like TCP or UDP. It is similar to the TIAS defined
|
|
86
|
+
/// in RFC 3890, i.e., it is measured in bits per second and the bitrate is
|
|
87
|
+
/// calculated over a 1 second window.
|
|
88
|
+
pub available_incoming_bitrate: f64,
|
|
89
|
+
|
|
90
|
+
/// The number of times the circuit breaker
|
|
91
|
+
/// is triggered for this particular 5-tuple, ceasing transmission.
|
|
92
|
+
pub circuit_breaker_trigger_count: u32,
|
|
93
|
+
|
|
94
|
+
/// The total number of connectivity check requests
|
|
95
|
+
/// received (including retransmissions). It is impossible for the receiver to
|
|
96
|
+
/// tell whether the request was sent in order to check connectivity or check
|
|
97
|
+
/// consent, so all connectivity checks requests are counted here.
|
|
98
|
+
pub requests_received: u64,
|
|
99
|
+
|
|
100
|
+
/// The total number of connectivity check requests
|
|
101
|
+
/// sent (not including retransmissions).
|
|
102
|
+
pub requests_sent: u64,
|
|
103
|
+
|
|
104
|
+
/// The total number of connectivity check responses received.
|
|
105
|
+
pub responses_received: u64,
|
|
106
|
+
|
|
107
|
+
/// Responses_sent epresents the total number of connectivity check responses sent.
|
|
108
|
+
/// Since we cannot distinguish connectivity check requests and consent requests,
|
|
109
|
+
/// all responses are counted.
|
|
110
|
+
pub responses_sent: u64,
|
|
111
|
+
|
|
112
|
+
/// The total number of connectivity check
|
|
113
|
+
/// request retransmissions received.
|
|
114
|
+
pub retransmissions_received: u64,
|
|
115
|
+
|
|
116
|
+
/// The total number of connectivity check
|
|
117
|
+
/// request retransmissions sent.
|
|
118
|
+
pub retransmissions_sent: u64,
|
|
119
|
+
|
|
120
|
+
/// The total number of consent requests sent.
|
|
121
|
+
pub consent_requests_sent: u64,
|
|
122
|
+
|
|
123
|
+
/// The timestamp at which the latest valid.
|
|
124
|
+
/// STUN binding response expired.
|
|
125
|
+
pub consent_expired_timestamp: Instant,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/// CandidateStats contains ICE candidate statistics related to the ICETransport objects.
|
|
129
|
+
#[derive(Debug, Clone)]
|
|
130
|
+
pub struct CandidateStats {
|
|
131
|
+
/// The timestamp associated with this object.
|
|
132
|
+
pub timestamp: Instant,
|
|
133
|
+
|
|
134
|
+
/// The candidate id.
|
|
135
|
+
pub id: String,
|
|
136
|
+
|
|
137
|
+
/// The ip address of the candidate, allowing for IPv4 addresses and.
|
|
138
|
+
/// IPv6 addresses, but fully qualified domain names (FQDNs) are not allowed.
|
|
139
|
+
pub ip: String,
|
|
140
|
+
|
|
141
|
+
/// The port number of the candidate.
|
|
142
|
+
pub port: u16,
|
|
143
|
+
|
|
144
|
+
/// The "Type" field of the ICECandidate.
|
|
145
|
+
pub candidate_type: CandidateType,
|
|
146
|
+
|
|
147
|
+
/// The "priority" field of the ICECandidate.
|
|
148
|
+
pub priority: u32,
|
|
149
|
+
|
|
150
|
+
/// The url of the TURN or STUN server indicated in the that translated
|
|
151
|
+
/// this ip address. It is the url address surfaced in an PeerConnectionICEEvent.
|
|
152
|
+
pub url: String,
|
|
153
|
+
|
|
154
|
+
/// The protocol used by the endpoint to communicate with the.
|
|
155
|
+
/// TURN server. This is only present for local candidates. Valid values for
|
|
156
|
+
/// the TURN url protocol is one of udp, tcp, or tls.
|
|
157
|
+
pub relay_protocol: String,
|
|
158
|
+
|
|
159
|
+
// deleted is true if the candidate has been deleted/freed. For host candidates,
|
|
160
|
+
// this means that any network resources (typically a socket) associated with the
|
|
161
|
+
// candidate have been released. For TURN candidates, this means the TURN allocation
|
|
162
|
+
// is no longer active.
|
|
163
|
+
//
|
|
164
|
+
/// Only defined for local candidates. For remote candidates, this property is not applicable.
|
|
165
|
+
pub deleted: bool,
|
|
166
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#[cfg(test)]
|
|
2
|
+
mod tcp_type_test;
|
|
3
|
+
|
|
4
|
+
use std::fmt;
|
|
5
|
+
|
|
6
|
+
// TCPType is the type of ICE TCP candidate as described in
|
|
7
|
+
// https://tools.ietf.org/html/rfc6544#section-4.5
|
|
8
|
+
#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
|
|
9
|
+
/// The role of an ICE-TCP candidate, per [RFC 6544] §4.5.
|
|
10
|
+
///
|
|
11
|
+
/// [RFC 6544]: https://datatracker.ietf.org/doc/html/rfc6544#section-4.5
|
|
12
|
+
#[non_exhaustive]
|
|
13
|
+
pub enum TcpType {
|
|
14
|
+
/// The default value. For example UDP candidates do not need this field.
|
|
15
|
+
#[default]
|
|
16
|
+
Unspecified,
|
|
17
|
+
/// Active TCP candidate, which initiates TCP connections.
|
|
18
|
+
Active,
|
|
19
|
+
/// Passive TCP candidate, only accepts TCP connections.
|
|
20
|
+
Passive,
|
|
21
|
+
/// Like `Active` and `Passive` at the same time.
|
|
22
|
+
SimultaneousOpen,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// from creates a new TCPType from string.
|
|
26
|
+
impl From<&str> for TcpType {
|
|
27
|
+
fn from(raw: &str) -> Self {
|
|
28
|
+
match raw {
|
|
29
|
+
"active" => Self::Active,
|
|
30
|
+
"passive" => Self::Passive,
|
|
31
|
+
"so" => Self::SimultaneousOpen,
|
|
32
|
+
_ => Self::Unspecified,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
impl fmt::Display for TcpType {
|
|
38
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
39
|
+
let s = match *self {
|
|
40
|
+
Self::Active => "active",
|
|
41
|
+
Self::Passive => "passive",
|
|
42
|
+
Self::SimultaneousOpen => "so",
|
|
43
|
+
Self::Unspecified => "unspecified",
|
|
44
|
+
};
|
|
45
|
+
write!(f, "{s}")
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use shared::error::Result;
|
|
3
|
+
|
|
4
|
+
#[test]
|
|
5
|
+
fn test_tcp_type() -> Result<()> {
|
|
6
|
+
//assert_eq!(tcpType, TCPType::Unspecified)
|
|
7
|
+
assert_eq!(TcpType::from("active"), TcpType::Active);
|
|
8
|
+
assert_eq!(TcpType::from("passive"), TcpType::Passive);
|
|
9
|
+
assert_eq!(TcpType::from("so"), TcpType::SimultaneousOpen);
|
|
10
|
+
assert_eq!(TcpType::from("something else"), TcpType::Unspecified);
|
|
11
|
+
|
|
12
|
+
assert_eq!(TcpType::Unspecified.to_string(), "unspecified");
|
|
13
|
+
assert_eq!(TcpType::Active.to_string(), "active");
|
|
14
|
+
assert_eq!(TcpType::Passive.to_string(), "passive");
|
|
15
|
+
assert_eq!(TcpType::SimultaneousOpen.to_string(), "so");
|
|
16
|
+
|
|
17
|
+
Ok(())
|
|
18
|
+
}
|