@desklink/host 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +25 -17
  2. package/dist/engineProcess.d.ts +5 -0
  3. package/dist/engineProcess.d.ts.map +1 -1
  4. package/dist/engineProcess.js +5 -3
  5. package/dist/engineProcess.js.map +1 -1
  6. package/engine/Cargo.lock +6 -8
  7. package/engine/Cargo.toml +13 -1
  8. package/engine/src/clipboard.rs +0 -34
  9. package/engine/src/convert.rs +0 -170
  10. package/engine/src/cursor.rs +0 -23
  11. package/engine/src/input.rs +0 -65
  12. package/engine/src/input_mac.rs +0 -11
  13. package/engine/src/keeper.rs +0 -137
  14. package/engine/src/keymap.rs +0 -107
  15. package/engine/src/keymap_mac.rs +0 -25
  16. package/engine/src/mac.rs +0 -28
  17. package/engine/src/peer.rs +224 -0
  18. package/engine/src/portal.rs +0 -18
  19. package/engine/src/protocol.rs +0 -162
  20. package/engine/src/x11.rs +0 -13
  21. package/engine/vendor/rtc-ice/Cargo.toml +137 -0
  22. package/engine/vendor/rtc-ice/DESKLINK-PATCH.md +59 -0
  23. package/engine/vendor/rtc-ice/LICENSE-APACHE +201 -0
  24. package/engine/vendor/rtc-ice/LICENSE-MIT +21 -0
  25. package/engine/vendor/rtc-ice/README.md +30 -0
  26. package/engine/vendor/rtc-ice/examples/ping_pong.rs +376 -0
  27. package/engine/vendor/rtc-ice/src/agent/agent_config.rs +126 -0
  28. package/engine/vendor/rtc-ice/src/agent/agent_proto.rs +172 -0
  29. package/engine/vendor/rtc-ice/src/agent/agent_selector.rs +566 -0
  30. package/engine/vendor/rtc-ice/src/agent/agent_stats.rs +292 -0
  31. package/engine/vendor/rtc-ice/src/agent/agent_test.rs +3388 -0
  32. package/engine/vendor/rtc-ice/src/agent/mod.rs +1662 -0
  33. package/engine/vendor/rtc-ice/src/attributes/control/control_test.rs +168 -0
  34. package/engine/vendor/rtc-ice/src/attributes/control/mod.rs +142 -0
  35. package/engine/vendor/rtc-ice/src/attributes/mod.rs +6 -0
  36. package/engine/vendor/rtc-ice/src/attributes/priority/mod.rs +37 -0
  37. package/engine/vendor/rtc-ice/src/attributes/priority/priority_test.rs +39 -0
  38. package/engine/vendor/rtc-ice/src/attributes/use_candidate/mod.rs +33 -0
  39. package/engine/vendor/rtc-ice/src/attributes/use_candidate/use_candidate_test.rs +19 -0
  40. package/engine/vendor/rtc-ice/src/candidate/candidate_host.rs +53 -0
  41. package/engine/vendor/rtc-ice/src/candidate/candidate_pair.rs +215 -0
  42. package/engine/vendor/rtc-ice/src/candidate/candidate_pair_test.rs +201 -0
  43. package/engine/vendor/rtc-ice/src/candidate/candidate_peer_reflexive.rs +49 -0
  44. package/engine/vendor/rtc-ice/src/candidate/candidate_relay.rs +53 -0
  45. package/engine/vendor/rtc-ice/src/candidate/candidate_relay_test.rs +114 -0
  46. package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive.rs +53 -0
  47. package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive_test.rs +91 -0
  48. package/engine/vendor/rtc-ice/src/candidate/candidate_test.rs +540 -0
  49. package/engine/vendor/rtc-ice/src/candidate/mod.rs +679 -0
  50. package/engine/vendor/rtc-ice/src/lib.rs +85 -0
  51. package/engine/vendor/rtc-ice/src/mdns/mdns_test.rs +150 -0
  52. package/engine/vendor/rtc-ice/src/mdns/mod.rs +69 -0
  53. package/engine/vendor/rtc-ice/src/network_type/mod.rs +162 -0
  54. package/engine/vendor/rtc-ice/src/network_type/network_type_test.rs +95 -0
  55. package/engine/vendor/rtc-ice/src/rand/mod.rs +91 -0
  56. package/engine/vendor/rtc-ice/src/rand/rand_test.rs +115 -0
  57. package/engine/vendor/rtc-ice/src/state/mod.rs +106 -0
  58. package/engine/vendor/rtc-ice/src/state/state_test.rs +46 -0
  59. package/engine/vendor/rtc-ice/src/stats/mod.rs +166 -0
  60. package/engine/vendor/rtc-ice/src/tcp_type/mod.rs +47 -0
  61. package/engine/vendor/rtc-ice/src/tcp_type/tcp_type_test.rs +18 -0
  62. package/engine/vendor/rtc-ice/src/url/mod.rs +266 -0
  63. package/engine/vendor/rtc-ice/src/url/url_test.rs +142 -0
  64. package/package.json +8 -3
@@ -0,0 +1,85 @@
1
+ #![warn(rust_2018_idioms)]
2
+ #![warn(missing_docs)]
3
+ #![allow(dead_code)]
4
+
5
+ //! ICE for the Sans-I/O WebRTC stack.
6
+ //!
7
+ //! Interactive Connectivity Establishment ([RFC 8445], superseding [RFC 5245]) with the
8
+ //! extensions WebRTC uses: ICE-TCP candidates ([RFC 6544]), consent freshness
9
+ //! ([RFC 7675]), and Trickle ICE. ICE is what finds a path between two peers behind NATs:
10
+ //! it gathers candidate addresses, pairs local with remote, and probes each pair with STUN
11
+ //! connectivity checks until one succeeds.
12
+ //!
13
+ //! # Structure
14
+ //!
15
+ //! * [`agent`] — the Sans-I/O [`Agent`]: give it candidates and inbound
16
+ //! datagrams, poll it for checks to send, state transitions, and the selected pair. It
17
+ //! owns no sockets and no clock.
18
+ //! * [`candidate`] — the candidate types (host, server-reflexive, peer-reflexive, relay),
19
+ //! their priorities, and SDP `a=candidate` parsing.
20
+ //! * [`state`] — connection and gathering states, and the checklist state machine.
21
+ //! * [`url`] — parsing `stun:`/`turn:` server URLs into something the agent can gather from.
22
+ //! * [`network_type`], [`tcp_type`] — UDP/TCP and active/passive/simultaneous-open.
23
+ //! * [`stats`] — per-candidate and per-pair counters, surfaced through `getStats`.
24
+ //! * [`mdns`] — mDNS candidate handling, for hiding private addresses.
25
+ //!
26
+ //! # Example
27
+ //!
28
+ //! ```
29
+ //! use rtc_ice::url::{ProtoType, SchemeType, Url};
30
+ //!
31
+ //! # fn example() -> Result<(), Box<dyn std::error::Error>> {
32
+ //! let stun = Url::parse_url("stun:stun.l.google.com:19302")?;
33
+ //! assert_eq!(stun.scheme, SchemeType::Stun);
34
+ //! assert_eq!(stun.port, 19302);
35
+ //!
36
+ //! // TURN URLs may pin the transport used to reach the server.
37
+ //! let turn = Url::parse_url("turn:turn.example.com:3478?transport=tcp")?;
38
+ //! assert_eq!(turn.scheme, SchemeType::Turn);
39
+ //! assert_eq!(turn.proto, ProtoType::Tcp);
40
+ //! # Ok(())
41
+ //! # }
42
+ //! ```
43
+ //!
44
+ //! Most applications do not depend on this crate directly — the
45
+ //! [`rtc`](https://docs.rs/rtc) crate drives the agent as one layer of the peer-connection
46
+ //! pipeline.
47
+ //!
48
+ //! [RFC 8445]: https://datatracker.ietf.org/doc/html/rfc8445
49
+ //! [RFC 5245]: https://datatracker.ietf.org/doc/html/rfc5245
50
+ //! [RFC 6544]: https://datatracker.ietf.org/doc/html/rfc6544
51
+ //! [RFC 7675]: https://datatracker.ietf.org/doc/html/rfc7675
52
+
53
+ /// The Sans-I/O ICE agent: candidate pairing, connectivity checks, and nomination.
54
+ /// The crypto provider API.
55
+ ///
56
+ /// Re-exported because this crate's public constructors take an
57
+ /// [`Arc<dyn RTCCryptoProvider>`](crypto::RTCCryptoProvider), which a caller must be able to name
58
+ /// without adding — and version-matching — a direct `rtc-crypto` dependency.
59
+ pub use crypto;
60
+
61
+ pub mod agent;
62
+ /// The ICE-specific STUN attributes carried in connectivity checks.
63
+ pub mod attributes;
64
+ /// Candidate types, priorities, and SDP `a=candidate` parsing.
65
+ pub mod candidate;
66
+ /// mDNS candidate handling, which hides private addresses behind `.local` names.
67
+ pub mod mdns;
68
+ /// UDP/TCP over IPv4/IPv6, as a candidate's transport.
69
+ pub mod network_type;
70
+ /// Random ICE credentials and identifiers.
71
+ pub mod rand;
72
+ /// Connection and gathering states.
73
+ pub mod state;
74
+ /// Per-candidate and per-pair counters, surfaced through `getStats`.
75
+ pub mod stats;
76
+ /// Active, passive and simultaneous-open, for ICE-TCP candidates.
77
+ pub mod tcp_type;
78
+ /// Parsing `stun:`/`turn:` server URLs.
79
+ pub mod url;
80
+
81
+ pub use agent::{
82
+ Agent, Credentials, Event,
83
+ agent_config::AgentConfig,
84
+ agent_stats::{CandidatePairStats, CandidateStats},
85
+ };
@@ -0,0 +1,150 @@
1
+ use regex::Regex;
2
+ use tokio::sync::{Mutex, mpsc};
3
+
4
+ use super::*;
5
+ use crate::agent::agent_config::*;
6
+ use crate::agent::*;
7
+ use crate::candidate::*;
8
+ use crate::network_type::*;
9
+ use shared::error::Error;
10
+
11
+ #[tokio::test]
12
+ // This test is disabled on Windows for now because it gets stuck and never finishes.
13
+ // This does not seem to have happened due to a code change. It started happening with
14
+ // `ce55c3a066ab461c3e74f0d5ac6f1209205e79bc` but was verified as happening on
15
+ // `92cc698a3dc6da459f3bf3789fd046c2dffdf107` too.
16
+ #[cfg(not(windows))]
17
+ async fn test_multicast_dns_only_connection() -> Result<()> {
18
+ let cfg0 = AgentConfig {
19
+ network_types: vec![NetworkType::Udp4],
20
+ candidate_types: vec![CandidateType::Host],
21
+ multicast_dns_mode: MulticastDnsMode::QueryAndGather,
22
+ ..Default::default()
23
+ };
24
+
25
+ let a_agent = Arc::new(Agent::new(cfg0).await?);
26
+ let (a_notifier, mut a_connected) = on_connected();
27
+ a_agent.on_connection_state_change(a_notifier);
28
+
29
+ let cfg1 = AgentConfig {
30
+ network_types: vec![NetworkType::Udp4],
31
+ candidate_types: vec![CandidateType::Host],
32
+ multicast_dns_mode: MulticastDnsMode::QueryAndGather,
33
+ ..Default::default()
34
+ };
35
+
36
+ let b_agent = Arc::new(Agent::new(cfg1).await?);
37
+ let (b_notifier, mut b_connected) = on_connected();
38
+ b_agent.on_connection_state_change(b_notifier);
39
+
40
+ connect_with_vnet(&a_agent, &b_agent).await?;
41
+ let _ = a_connected.recv().await;
42
+ let _ = b_connected.recv().await;
43
+
44
+ a_agent.close().await?;
45
+ b_agent.close().await?;
46
+
47
+ Ok(())
48
+ }
49
+
50
+ #[tokio::test]
51
+ async fn test_multicast_dns_mixed_connection() -> Result<()> {
52
+ let cfg0 = AgentConfig {
53
+ network_types: vec![NetworkType::Udp4],
54
+ candidate_types: vec![CandidateType::Host],
55
+ multicast_dns_mode: MulticastDnsMode::QueryAndGather,
56
+ ..Default::default()
57
+ };
58
+
59
+ let a_agent = Arc::new(Agent::new(cfg0).await?);
60
+ let (a_notifier, mut a_connected) = on_connected();
61
+ a_agent.on_connection_state_change(a_notifier);
62
+
63
+ let cfg1 = AgentConfig {
64
+ network_types: vec![NetworkType::Udp4],
65
+ candidate_types: vec![CandidateType::Host],
66
+ multicast_dns_mode: MulticastDnsMode::QueryOnly,
67
+ ..Default::default()
68
+ };
69
+
70
+ let b_agent = Arc::new(Agent::new(cfg1).await?);
71
+ let (b_notifier, mut b_connected) = on_connected();
72
+ b_agent.on_connection_state_change(b_notifier);
73
+
74
+ connect_with_vnet(&a_agent, &b_agent).await?;
75
+ let _ = a_connected.recv().await;
76
+ let _ = b_connected.recv().await;
77
+
78
+ a_agent.close().await?;
79
+ b_agent.close().await?;
80
+
81
+ Ok(())
82
+ }
83
+
84
+ #[tokio::test]
85
+ async fn test_multicast_dns_static_host_name() -> Result<()> {
86
+ let cfg0 = AgentConfig {
87
+ network_types: vec![NetworkType::Udp4],
88
+ candidate_types: vec![CandidateType::Host],
89
+ multicast_dns_mode: MulticastDnsMode::QueryAndGather,
90
+ multicast_dns_host_name: "invalidHostName".to_owned(),
91
+ ..Default::default()
92
+ };
93
+ if let Err(err) = Agent::new(cfg0).await {
94
+ assert_eq!(err, Error::ErrInvalidMulticastDnshostName);
95
+ } else {
96
+ panic!("expected error, but got ok");
97
+ }
98
+
99
+ let cfg1 = AgentConfig {
100
+ network_types: vec![NetworkType::Udp4],
101
+ candidate_types: vec![CandidateType::Host],
102
+ multicast_dns_mode: MulticastDnsMode::QueryAndGather,
103
+ multicast_dns_host_name: "validName.local".to_owned(),
104
+ ..Default::default()
105
+ };
106
+
107
+ let a = Agent::new(cfg1).await?;
108
+
109
+ let (done_tx, mut done_rx) = mpsc::channel::<()>(1);
110
+ let done_tx = Arc::new(Mutex::new(Some(done_tx)));
111
+ a.on_candidate(Box::new(
112
+ move |c: Option<Arc<dyn Candidate + Send + Sync>>| {
113
+ let done_tx_clone = Arc::clone(&done_tx);
114
+ Box::pin(async move {
115
+ if c.is_none() {
116
+ let mut tx = done_tx_clone.lock().await;
117
+ tx.take();
118
+ }
119
+ })
120
+ },
121
+ ));
122
+
123
+ a.gather_candidates()?;
124
+
125
+ log::debug!("wait for gathering is done...");
126
+ let _ = done_rx.recv().await;
127
+ log::debug!("gathering is done");
128
+
129
+ Ok(())
130
+ }
131
+
132
+ #[test]
133
+ fn test_generate_multicast_dnsname() -> Result<()> {
134
+ let name = generate_multicast_dns_name();
135
+
136
+ let re = Regex::new(
137
+ r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}.local+$",
138
+ );
139
+
140
+ if let Ok(re) = re {
141
+ assert!(
142
+ re.is_match(&name),
143
+ "mDNS name must be UUID v4 + \".local\" suffix, got {name}"
144
+ );
145
+ } else {
146
+ panic!("expected ok, but got err");
147
+ }
148
+
149
+ Ok(())
150
+ }
@@ -0,0 +1,69 @@
1
+ //#[cfg(test)]
2
+ //mod mdns_test;
3
+
4
+ use mdns::Mdns;
5
+ use mdns::MdnsConfig;
6
+ use std::net::{IpAddr, Ipv4Addr};
7
+ use std::time::{Duration, Instant};
8
+ use uuid::Uuid;
9
+
10
+ use shared::error::Result;
11
+
12
+ /// Represents the different Multicast modes that ICE can run.
13
+ #[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
14
+ #[non_exhaustive]
15
+ pub enum MulticastDnsMode {
16
+ /// Means remote mDNS candidates will be discarded, and local host candidates will use IPs.
17
+ Disabled,
18
+
19
+ /// Means remote mDNS candidates will be accepted, and local host candidates will use IPs.
20
+ #[default]
21
+ QueryOnly,
22
+
23
+ /// Means remote mDNS candidates will be accepted, and local host candidates will use mDNS.
24
+ QueryAndGather,
25
+ }
26
+
27
+ pub(crate) fn generate_multicast_dns_name() -> String {
28
+ // https://tools.ietf.org/id/draft-ietf-rtcweb-mdns-ice-candidates-02.html#gathering
29
+ // The unique name MUST consist of a version 4 UUID as defined in [RFC4122], followed by “.local”.
30
+ // This is a short-lived privacy alias, not a credential. `Uuid::new_v4` obtains randomness
31
+ // from the UUID crate's secure random source without forcing provider ownership into mDNS.
32
+ let u = Uuid::new_v4();
33
+ format!("{u}.local")
34
+ }
35
+
36
+ pub(crate) fn create_multicast_dns(
37
+ now: Instant,
38
+ mdns_mode: MulticastDnsMode,
39
+ mdns_local_name: &str,
40
+ mdns_local_ip: &Option<IpAddr>,
41
+ mdns_query_timeout: &Option<Duration>,
42
+ ) -> Result<Option<Mdns>> {
43
+ if mdns_mode == MulticastDnsMode::Disabled {
44
+ return Ok(None);
45
+ }
46
+
47
+ let mut config = if mdns_mode == MulticastDnsMode::QueryAndGather {
48
+ let local_ip = if let Some(local_ip) = mdns_local_ip {
49
+ *local_ip
50
+ } else {
51
+ IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))
52
+ };
53
+ log::info!("mDNS is using {local_ip} as local ip");
54
+
55
+ MdnsConfig::new()
56
+ .with_local_names(vec![mdns_local_name.to_owned()])
57
+ .with_local_ip(local_ip)
58
+ } else {
59
+ MdnsConfig::new()
60
+ };
61
+
62
+ if let Some(query_timeout) = mdns_query_timeout {
63
+ config = config.with_query_timeout(*query_timeout);
64
+ }
65
+
66
+ let mdns_server = Mdns::new(now, config);
67
+
68
+ Ok(Some(mdns_server))
69
+ }
@@ -0,0 +1,162 @@
1
+ //! Candidate transports: UDP or TCP, over IPv4 or IPv6.
2
+ //!
3
+ //! A [`NetworkType`](crate::network_type::NetworkType) pairs the transport protocol with the address family, because ICE treats
4
+ //! them together: a candidate's type constrains which remote candidates it can be paired with,
5
+ //! and pairs across families are never formed.
6
+ #[cfg(test)]
7
+ mod network_type_test;
8
+
9
+ use std::fmt;
10
+ use std::net::IpAddr;
11
+
12
+ use serde::{Deserialize, Serialize};
13
+
14
+ use shared::TransportProtocol;
15
+ use shared::error::*;
16
+
17
+ pub(crate) const UDP: &str = "udp";
18
+ pub(crate) const TCP: &str = "tcp";
19
+
20
+ #[must_use]
21
+ /// Every network type this crate can gather candidates for.
22
+ pub fn supported_network_types() -> Vec<NetworkType> {
23
+ vec![
24
+ NetworkType::Udp4,
25
+ NetworkType::Udp6,
26
+ NetworkType::Tcp4,
27
+ NetworkType::Tcp6,
28
+ ]
29
+ }
30
+
31
+ /// Represents the type of network.
32
+ #[derive(Default, PartialEq, Debug, Copy, Clone, Eq, Hash, Serialize, Deserialize)]
33
+ #[non_exhaustive]
34
+ pub enum NetworkType {
35
+ #[serde(rename = "unspecified")]
36
+ #[default]
37
+ /// No network type was set.
38
+ Unspecified,
39
+
40
+ /// Indicates UDP over IPv4.
41
+ #[serde(rename = "udp4")]
42
+ Udp4,
43
+
44
+ /// Indicates UDP over IPv6.
45
+ #[serde(rename = "udp6")]
46
+ Udp6,
47
+
48
+ /// Indicates TCP over IPv4.
49
+ #[serde(rename = "tcp4")]
50
+ Tcp4,
51
+
52
+ /// Indicates TCP over IPv6.
53
+ #[serde(rename = "tcp6")]
54
+ Tcp6,
55
+ }
56
+
57
+ impl From<u8> for NetworkType {
58
+ fn from(v: u8) -> Self {
59
+ match v {
60
+ 1 => Self::Udp4,
61
+ 2 => Self::Udp6,
62
+ 3 => Self::Tcp4,
63
+ 4 => Self::Tcp6,
64
+ _ => Self::Unspecified,
65
+ }
66
+ }
67
+ }
68
+
69
+ impl fmt::Display for NetworkType {
70
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71
+ let s = match *self {
72
+ Self::Udp4 => "udp4",
73
+ Self::Udp6 => "udp6",
74
+ Self::Tcp4 => "tcp4",
75
+ Self::Tcp6 => "tcp6",
76
+ Self::Unspecified => "unspecified",
77
+ };
78
+ write!(f, "{s}")
79
+ }
80
+ }
81
+
82
+ impl NetworkType {
83
+ /// Returns true when network is UDP4 or UDP6.
84
+ #[must_use]
85
+ pub fn is_udp(self) -> bool {
86
+ self == Self::Udp4 || self == Self::Udp6
87
+ }
88
+
89
+ /// Returns true when network is TCP4 or TCP6.
90
+ #[must_use]
91
+ pub fn is_tcp(self) -> bool {
92
+ self == Self::Tcp4 || self == Self::Tcp6
93
+ }
94
+
95
+ #[must_use]
96
+ /// The transport protocol, discarding the address family.
97
+ pub fn to_protocol(self) -> TransportProtocol {
98
+ if self.is_tcp() {
99
+ TransportProtocol::TCP
100
+ } else {
101
+ TransportProtocol::UDP
102
+ }
103
+ }
104
+
105
+ /// Returns the short network description.
106
+ #[must_use]
107
+ pub fn network_short(self) -> String {
108
+ match self {
109
+ Self::Udp4 | Self::Udp6 => UDP.to_owned(),
110
+ Self::Tcp4 | Self::Tcp6 => TCP.to_owned(),
111
+ Self::Unspecified => "Unspecified".to_owned(),
112
+ }
113
+ }
114
+
115
+ /// Returns true if the network is reliable.
116
+ #[must_use]
117
+ pub const fn is_reliable(self) -> bool {
118
+ match self {
119
+ Self::Tcp4 | Self::Tcp6 => true,
120
+ Self::Udp4 | Self::Udp6 | Self::Unspecified => false,
121
+ }
122
+ }
123
+
124
+ /// Returns whether the network type is IPv4 or not.
125
+ #[must_use]
126
+ pub const fn is_ipv4(self) -> bool {
127
+ match self {
128
+ Self::Udp4 | Self::Tcp4 => true,
129
+ Self::Udp6 | Self::Tcp6 | Self::Unspecified => false,
130
+ }
131
+ }
132
+
133
+ /// Returns whether the network type is IPv6 or not.
134
+ #[must_use]
135
+ pub const fn is_ipv6(self) -> bool {
136
+ match self {
137
+ Self::Udp6 | Self::Tcp6 => true,
138
+ Self::Udp4 | Self::Tcp4 | Self::Unspecified => false,
139
+ }
140
+ }
141
+ }
142
+
143
+ /// Determines the type of network based on the short network string and an IP address.
144
+ pub(crate) fn determine_network_type(network: &str, ip: &IpAddr) -> Result<NetworkType> {
145
+ let ipv4 = ip.is_ipv4();
146
+ let net = network.to_lowercase();
147
+ if net.starts_with(UDP) {
148
+ if ipv4 {
149
+ Ok(NetworkType::Udp4)
150
+ } else {
151
+ Ok(NetworkType::Udp6)
152
+ }
153
+ } else if net.starts_with(TCP) {
154
+ if ipv4 {
155
+ Ok(NetworkType::Tcp4)
156
+ } else {
157
+ Ok(NetworkType::Tcp6)
158
+ }
159
+ } else {
160
+ Err(Error::ErrDetermineNetworkType)
161
+ }
162
+ }
@@ -0,0 +1,95 @@
1
+ use super::*;
2
+ use shared::error::Result;
3
+
4
+ #[test]
5
+ fn test_network_type_parsing_success() -> Result<()> {
6
+ let ipv4: IpAddr = "192.168.0.1".parse().unwrap();
7
+ let ipv6: IpAddr = "fe80::a3:6ff:fec4:5454".parse().unwrap();
8
+
9
+ let tests = vec![
10
+ ("lowercase UDP4", "udp", ipv4, NetworkType::Udp4),
11
+ ("uppercase UDP4", "UDP", ipv4, NetworkType::Udp4),
12
+ ("lowercase UDP6", "udp", ipv6, NetworkType::Udp6),
13
+ ("uppercase UDP6", "UDP", ipv6, NetworkType::Udp6),
14
+ ];
15
+
16
+ for (name, in_network, in_ip, expected) in tests {
17
+ let actual = determine_network_type(in_network, &in_ip)?;
18
+
19
+ assert_eq!(
20
+ actual, expected,
21
+ "NetworkTypeParsing: '{name}' -- input:{in_network} expected:{expected} actual:{actual}"
22
+ );
23
+ }
24
+
25
+ Ok(())
26
+ }
27
+
28
+ #[test]
29
+ fn test_network_type_parsing_failure() -> Result<()> {
30
+ let ipv6: IpAddr = "fe80::a3:6ff:fec4:5454".parse().unwrap();
31
+
32
+ let tests = vec![("invalid network", "junkNetwork", ipv6)];
33
+ for (name, in_network, in_ip) in tests {
34
+ let result = determine_network_type(in_network, &in_ip);
35
+ assert!(
36
+ result.is_err(),
37
+ "NetworkTypeParsing should fail: '{name}' -- input:{in_network}",
38
+ );
39
+ }
40
+
41
+ Ok(())
42
+ }
43
+
44
+ #[test]
45
+ fn test_network_type_is_udp() -> Result<()> {
46
+ assert!(NetworkType::Udp4.is_udp());
47
+ assert!(NetworkType::Udp6.is_udp());
48
+ assert!(!NetworkType::Udp4.is_tcp());
49
+ assert!(!NetworkType::Udp6.is_tcp());
50
+
51
+ Ok(())
52
+ }
53
+
54
+ #[test]
55
+ fn test_network_type_is_tcp() -> Result<()> {
56
+ assert!(NetworkType::Tcp4.is_tcp());
57
+ assert!(NetworkType::Tcp6.is_tcp());
58
+ assert!(!NetworkType::Tcp4.is_udp());
59
+ assert!(!NetworkType::Tcp6.is_udp());
60
+
61
+ Ok(())
62
+ }
63
+
64
+ #[test]
65
+ fn test_network_type_serialization() {
66
+ let tests = vec![
67
+ (NetworkType::Tcp4, "\"tcp4\""),
68
+ (NetworkType::Tcp6, "\"tcp6\""),
69
+ (NetworkType::Udp4, "\"udp4\""),
70
+ (NetworkType::Udp6, "\"udp6\""),
71
+ (NetworkType::Unspecified, "\"unspecified\""),
72
+ ];
73
+
74
+ for (network_type, expected_string) in tests {
75
+ assert_eq!(
76
+ expected_string.to_string(),
77
+ serde_json::to_string(&network_type).unwrap()
78
+ );
79
+ }
80
+ }
81
+
82
+ #[test]
83
+ fn test_network_type_to_string() {
84
+ let tests = vec![
85
+ (NetworkType::Tcp4, "tcp4"),
86
+ (NetworkType::Tcp6, "tcp6"),
87
+ (NetworkType::Udp4, "udp4"),
88
+ (NetworkType::Udp6, "udp6"),
89
+ (NetworkType::Unspecified, "unspecified"),
90
+ ];
91
+
92
+ for (network_type, expected_string) in tests {
93
+ assert_eq!(network_type.to_string(), expected_string);
94
+ }
95
+ }
@@ -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
+ }