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