1#[cfg(test)]
2mod candidate_pair_test;
3#[cfg(test)]
4mod candidate_test;
5
6pub mod candidate_host;
13pub mod candidate_pair;
14pub mod candidate_peer_reflexive;
15pub mod candidate_relay;
16pub mod candidate_server_reflexive;
17
18use crate::network_type::NetworkType;
19use crate::tcp_type::TcpType;
20use crc::{CRC_32_ISCSI, Crc};
21use serde::{Deserialize, Serialize};
22use shared::error::*;
23use std::fmt;
24use std::net::{IpAddr, SocketAddr};
25use std::time::Instant;
26
27use crate::candidate::candidate_host::CandidateHostConfig;
28use crate::candidate::candidate_peer_reflexive::CandidatePeerReflexiveConfig;
29use crate::candidate::candidate_relay::CandidateRelayConfig;
30use crate::candidate::candidate_server_reflexive::CandidateServerReflexiveConfig;
31use crate::network_type::determine_network_type;
32
33pub(crate) const RECEIVE_MTU: usize = 8192;
34pub(crate) const DEFAULT_LOCAL_PREFERENCE: u16 = 65535;
35
36pub(crate) const COMPONENT_RTP: u16 = 1;
38pub(crate) const COMPONENT_RTCP: u16 = 0;
40
41#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
43pub enum CandidateType {
44 #[default]
45 #[serde(rename = "unspecified")]
46 Unspecified,
47 #[serde(rename = "host")]
48 Host,
49 #[serde(rename = "srflx")]
50 ServerReflexive,
51 #[serde(rename = "prflx")]
52 PeerReflexive,
53 #[serde(rename = "relay")]
54 Relay,
55}
56
57impl fmt::Display for CandidateType {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 let s = match *self {
61 CandidateType::Host => "host",
62 CandidateType::ServerReflexive => "srflx",
63 CandidateType::PeerReflexive => "prflx",
64 CandidateType::Relay => "relay",
65 CandidateType::Unspecified => "Unknown candidate type",
66 };
67 write!(f, "{s}")
68 }
69}
70
71impl CandidateType {
72 #[must_use]
79 pub const fn preference(self) -> u16 {
80 match self {
81 Self::Host => 126,
82 Self::PeerReflexive => 110,
83 Self::ServerReflexive => 100,
84 Self::Relay | CandidateType::Unspecified => 0,
85 }
86 }
87}
88
89pub(crate) fn contains_candidate_type(
90 candidate_type: CandidateType,
91 candidate_type_list: &[CandidateType],
92) -> bool {
93 if candidate_type_list.is_empty() {
94 return false;
95 }
96 for ct in candidate_type_list {
97 if *ct == candidate_type {
98 return true;
99 }
100 }
101 false
102}
103
104#[derive(PartialEq, Eq, Debug, Clone)]
106pub struct CandidateRelatedAddress {
107 pub address: String,
108 pub port: u16,
109}
110
111impl fmt::Display for CandidateRelatedAddress {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 write!(f, " related {}:{}", self.address, self.port)
115 }
116}
117
118#[derive(Default)]
119pub struct CandidateConfig {
120 pub candidate_id: String,
121 pub network: String,
122 pub address: String,
123 pub port: u16,
124 pub component: u16,
125 pub priority: u32,
126 pub foundation: String,
127}
128
129#[derive(Clone)]
130pub struct Candidate {
131 pub(crate) id: String,
132 pub(crate) network_type: NetworkType,
133 pub(crate) candidate_type: CandidateType,
134
135 pub(crate) component: u16,
136 pub(crate) address: String,
137 pub(crate) port: u16,
138 pub(crate) related_address: Option<CandidateRelatedAddress>,
139 pub(crate) tcp_type: TcpType,
140
141 pub(crate) resolved_addr: SocketAddr,
142
143 pub(crate) last_sent: Instant,
144 pub(crate) last_received: Instant,
145
146 pub(crate) foundation_override: String,
147 pub(crate) priority_override: u32,
148
149 pub(crate) network: String,
150}
151
152impl Default for Candidate {
153 fn default() -> Self {
154 Self {
155 id: String::new(),
156 network_type: NetworkType::Unspecified,
157 candidate_type: CandidateType::default(),
158
159 component: 0,
160 address: String::new(),
161 port: 0,
162 related_address: None,
163 tcp_type: TcpType::default(),
164
165 resolved_addr: SocketAddr::new(IpAddr::from([0, 0, 0, 0]), 0),
166
167 last_sent: Instant::now(),
168 last_received: Instant::now(),
169
170 foundation_override: String::new(),
171 priority_override: 0,
172 network: String::new(),
173 }
174 }
175}
176
177impl fmt::Display for Candidate {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 if let Some(related_address) = self.related_address() {
181 write!(
182 f,
183 "{} {} {}:{}{}",
184 self.network_type(),
185 self.candidate_type(),
186 self.address(),
187 self.port(),
188 related_address,
189 )
190 } else {
191 write!(
192 f,
193 "{} {} {}:{}",
194 self.network_type(),
195 self.candidate_type(),
196 self.address(),
197 self.port(),
198 )
199 }
200 }
201}
202
203impl Candidate {
204 pub fn foundation(&self) -> String {
205 if !self.foundation_override.is_empty() {
206 return self.foundation_override.clone();
207 }
208
209 let mut buf = vec![];
210 buf.extend_from_slice(self.candidate_type().to_string().as_bytes());
211 buf.extend_from_slice(self.address.as_bytes());
212 buf.extend_from_slice(self.network_type().to_string().as_bytes());
213
214 let checksum = Crc::<u32>::new(&CRC_32_ISCSI).checksum(&buf);
215
216 format!("{checksum}")
217 }
218
219 pub fn id(&self) -> String {
221 self.id.clone()
222 }
223
224 pub fn component(&self) -> u16 {
226 self.component
227 }
228
229 pub fn set_component(&mut self, component: u16) {
231 self.component = component;
232 }
233
234 pub fn last_received(&self) -> Instant {
236 self.last_received
237 }
238
239 pub fn last_sent(&self) -> Instant {
241 self.last_sent
242 }
243
244 pub fn network_type(&self) -> NetworkType {
246 self.network_type
247 }
248
249 pub fn address(&self) -> &str {
251 self.address.as_str()
252 }
253
254 pub fn port(&self) -> u16 {
256 self.port
257 }
258
259 pub fn priority(&self) -> u32 {
261 if self.priority_override != 0 {
262 return self.priority_override;
263 }
264
265 (1 << 24) * u32::from(self.candidate_type().preference())
272 + (1 << 8) * u32::from(self.local_preference())
273 + (256 - u32::from(self.component()))
274 }
275
276 pub fn related_address(&self) -> Option<CandidateRelatedAddress> {
278 self.related_address.as_ref().cloned()
279 }
280
281 pub fn candidate_type(&self) -> CandidateType {
283 self.candidate_type
284 }
285
286 pub fn tcp_type(&self) -> TcpType {
287 self.tcp_type
288 }
289
290 pub fn marshal(&self) -> String {
292 let mut val = format!(
293 "{} {} {} {} {} {} typ {}",
294 self.foundation(),
295 self.component(),
296 self.network_type().network_short(),
297 self.priority(),
298 self.address(),
299 self.port(),
300 self.candidate_type()
301 );
302
303 if self.tcp_type != TcpType::Unspecified {
304 val += format!(" tcptype {}", self.tcp_type()).as_str();
305 }
306
307 if let Some(related_address) = self.related_address() {
308 val += format!(
309 " raddr {} rport {}",
310 related_address.address, related_address.port,
311 )
312 .as_str();
313 }
314
315 val
316 }
317
318 pub fn addr(&self) -> SocketAddr {
319 self.resolved_addr
320 }
321
322 pub fn seen(&mut self, outbound: bool) {
323 let now = Instant::now();
324
325 if outbound {
326 self.set_last_sent(now);
327 } else {
328 self.set_last_received(now);
329 }
330 }
331
332 pub fn equal(&self, other: &Candidate) -> bool {
334 self.network_type() == other.network_type()
335 && self.candidate_type() == other.candidate_type()
336 && self.address() == other.address()
337 && self.port() == other.port()
338 && self.tcp_type() == other.tcp_type()
339 && self.related_address() == other.related_address()
340 }
341}
342
343impl Candidate {
344 pub fn set_last_received(&mut self, now: Instant) {
345 self.last_received = now;
346 }
347
348 pub fn set_last_sent(&mut self, now: Instant) {
349 self.last_sent = now;
350 }
351
352 pub fn local_preference(&self) -> u16 {
354 if self.network_type().is_tcp() {
355 let other_pref: u16 = 8191;
391
392 let direction_pref: u16 = match self.candidate_type() {
393 CandidateType::Host | CandidateType::Relay => match self.tcp_type() {
394 TcpType::Active => 6,
395 TcpType::Passive => 4,
396 TcpType::SimultaneousOpen => 2,
397 TcpType::Unspecified => 0,
398 },
399 CandidateType::PeerReflexive | CandidateType::ServerReflexive => {
400 match self.tcp_type() {
401 TcpType::SimultaneousOpen => 6,
402 TcpType::Active => 4,
403 TcpType::Passive => 2,
404 TcpType::Unspecified => 0,
405 }
406 }
407 CandidateType::Unspecified => 0,
408 };
409
410 (1 << 13) * direction_pref + other_pref
411 } else {
412 DEFAULT_LOCAL_PREFERENCE
413 }
414 }
415}
416
417pub fn unmarshal_candidate(raw: &str) -> Result<Candidate> {
419 let split: Vec<&str> = raw.split_whitespace().collect();
420 if split.len() < 8 {
421 return Err(Error::Other(format!(
422 "{:?} ({})",
423 Error::ErrAttributeTooShortIceCandidate,
424 split.len()
425 )));
426 }
427
428 let foundation = split[0].to_owned();
430
431 let component: u16 = split[1].parse()?;
433
434 let network = split[2].to_owned();
436
437 let priority: u32 = split[3].parse()?;
439
440 let address = split[4].to_owned();
442
443 let port: u16 = split[5].parse()?;
445
446 let typ = split[7];
447
448 let mut rel_addr = String::new();
449 let mut rel_port = 0;
450 let mut tcp_type = TcpType::Unspecified;
451
452 if split.len() > 8 {
453 let split2 = &split[8..];
454
455 if split2[0] == "raddr" {
456 if split2.len() < 4 {
457 return Err(Error::Other(format!(
458 "{:?}: incorrect length",
459 Error::ErrParseRelatedAddr
460 )));
461 }
462
463 split2[1].clone_into(&mut rel_addr);
465
466 rel_port = split2[3].parse()?;
468 } else if split2[0] == "tcptype" {
469 if split2.len() < 2 {
470 return Err(Error::Other(format!(
471 "{:?}: incorrect length",
472 Error::ErrParseType
473 )));
474 }
475
476 tcp_type = TcpType::from(split2[1]);
477 }
478 }
479
480 match typ {
481 "host" => {
482 let config = CandidateHostConfig {
483 base_config: CandidateConfig {
484 network,
485 address,
486 port,
487 component,
488 priority,
489 foundation,
490 ..CandidateConfig::default()
491 },
492 tcp_type,
493 };
494 config.new_candidate_host()
495 }
496 "srflx" => {
497 let config = CandidateServerReflexiveConfig {
498 base_config: CandidateConfig {
499 network,
500 address,
501 port,
502 component,
503 priority,
504 foundation,
505 ..CandidateConfig::default()
506 },
507 rel_addr,
508 rel_port,
509 };
510 config.new_candidate_server_reflexive()
511 }
512 "prflx" => {
513 let config = CandidatePeerReflexiveConfig {
514 base_config: CandidateConfig {
515 network,
516 address,
517 port,
518 component,
519 priority,
520 foundation,
521 ..CandidateConfig::default()
522 },
523 rel_addr,
524 rel_port,
525 };
526
527 config.new_candidate_peer_reflexive()
528 }
529 "relay" => {
530 let config = CandidateRelayConfig {
531 base_config: CandidateConfig {
532 network,
533 address,
534 port,
535 component,
536 priority,
537 foundation,
538 ..CandidateConfig::default()
539 },
540 rel_addr,
541 rel_port,
542 };
543 config.new_candidate_relay()
544 }
545 _ => Err(Error::Other(format!(
546 "{:?} ({})",
547 Error::ErrUnknownCandidateType,
548 typ
549 ))),
550 }
551}