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 pub(crate) url: Option<String>,
152}
153
154impl Default for Candidate {
155 fn default() -> Self {
156 Self {
157 id: String::new(),
158 network_type: NetworkType::Unspecified,
159 candidate_type: CandidateType::default(),
160
161 component: 0,
162 address: String::new(),
163 port: 0,
164 related_address: None,
165 tcp_type: TcpType::default(),
166
167 resolved_addr: SocketAddr::new(IpAddr::from([0, 0, 0, 0]), 0),
168
169 last_sent: Instant::now(),
170 last_received: Instant::now(),
171
172 foundation_override: String::new(),
173 priority_override: 0,
174 network: String::new(),
175
176 url: None,
177 }
178 }
179}
180
181impl fmt::Display for Candidate {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 if let Some(related_address) = self.related_address() {
185 write!(
186 f,
187 "{} {} {}:{}{}",
188 self.network_type(),
189 self.candidate_type(),
190 self.address(),
191 self.port(),
192 related_address,
193 )
194 } else {
195 write!(
196 f,
197 "{} {} {}:{}",
198 self.network_type(),
199 self.candidate_type(),
200 self.address(),
201 self.port(),
202 )
203 }
204 }
205}
206
207impl Candidate {
208 pub fn foundation(&self) -> String {
209 if !self.foundation_override.is_empty() {
210 return self.foundation_override.clone();
211 }
212
213 let mut buf = vec![];
214 buf.extend_from_slice(self.candidate_type().to_string().as_bytes());
215 buf.extend_from_slice(self.address.as_bytes());
216 buf.extend_from_slice(self.network_type().to_string().as_bytes());
217
218 let checksum = Crc::<u32>::new(&CRC_32_ISCSI).checksum(&buf);
219
220 format!("{checksum}")
221 }
222
223 pub fn id(&self) -> &str {
225 self.id.as_str()
226 }
227
228 pub fn component(&self) -> u16 {
230 self.component
231 }
232
233 pub fn set_component(&mut self, component: u16) {
235 self.component = component;
236 }
237
238 pub fn last_received(&self) -> Instant {
240 self.last_received
241 }
242
243 pub fn last_sent(&self) -> Instant {
245 self.last_sent
246 }
247
248 pub fn network_type(&self) -> NetworkType {
250 self.network_type
251 }
252
253 pub fn address(&self) -> &str {
255 self.address.as_str()
256 }
257
258 pub fn port(&self) -> u16 {
260 self.port
261 }
262
263 pub fn priority(&self) -> u32 {
265 if self.priority_override != 0 {
266 return self.priority_override;
267 }
268
269 (1 << 24) * u32::from(self.candidate_type().preference())
276 + (1 << 8) * u32::from(self.local_preference())
277 + (256 - u32::from(self.component()))
278 }
279
280 pub fn related_address(&self) -> Option<CandidateRelatedAddress> {
282 self.related_address.as_ref().cloned()
283 }
284
285 pub fn candidate_type(&self) -> CandidateType {
287 self.candidate_type
288 }
289
290 pub fn tcp_type(&self) -> TcpType {
291 self.tcp_type
292 }
293
294 pub fn url(&self) -> Option<&str> {
295 self.url.as_deref()
296 }
297
298 pub fn marshal(&self) -> String {
300 let mut val = format!(
301 "{} {} {} {} {} {} typ {}",
302 self.foundation(),
303 self.component(),
304 self.network_type().network_short(),
305 self.priority(),
306 self.address(),
307 self.port(),
308 self.candidate_type()
309 );
310
311 if self.tcp_type != TcpType::Unspecified {
312 val += format!(" tcptype {}", self.tcp_type()).as_str();
313 }
314
315 if let Some(related_address) = self.related_address() {
316 val += format!(
317 " raddr {} rport {}",
318 related_address.address, related_address.port,
319 )
320 .as_str();
321 }
322
323 val
324 }
325
326 pub fn addr(&self) -> SocketAddr {
327 self.resolved_addr
328 }
329
330 pub fn seen(&mut self, outbound: bool) {
331 let now = Instant::now();
332
333 if outbound {
334 self.set_last_sent(now);
335 } else {
336 self.set_last_received(now);
337 }
338 }
339
340 pub fn equal(&self, other: &Candidate) -> bool {
342 self.network_type() == other.network_type()
343 && self.candidate_type() == other.candidate_type()
344 && self.address() == other.address()
345 && self.port() == other.port()
346 && self.tcp_type() == other.tcp_type()
347 && self.related_address() == other.related_address()
348 }
349
350 pub fn set_ip(&mut self, ip: &IpAddr) -> Result<()> {
351 self.network_type = determine_network_type(&self.network, ip)?;
352 self.resolved_addr = SocketAddr::new(*ip, self.port); Ok(())
354 }
355}
356
357impl Candidate {
358 pub fn set_last_received(&mut self, now: Instant) {
359 self.last_received = now;
360 }
361
362 pub fn set_last_sent(&mut self, now: Instant) {
363 self.last_sent = now;
364 }
365
366 pub fn local_preference(&self) -> u16 {
368 if self.network_type().is_tcp() {
369 let other_pref: u16 = 8191;
405
406 let direction_pref: u16 = match self.candidate_type() {
407 CandidateType::Host | CandidateType::Relay => match self.tcp_type() {
408 TcpType::Active => 6,
409 TcpType::Passive => 4,
410 TcpType::SimultaneousOpen => 2,
411 TcpType::Unspecified => 0,
412 },
413 CandidateType::PeerReflexive | CandidateType::ServerReflexive => {
414 match self.tcp_type() {
415 TcpType::SimultaneousOpen => 6,
416 TcpType::Active => 4,
417 TcpType::Passive => 2,
418 TcpType::Unspecified => 0,
419 }
420 }
421 CandidateType::Unspecified => 0,
422 };
423
424 (1 << 13) * direction_pref + other_pref
425 } else {
426 DEFAULT_LOCAL_PREFERENCE
427 }
428 }
429}
430
431pub fn unmarshal_candidate(raw: &str) -> Result<Candidate> {
433 let split: Vec<&str> = raw.split_whitespace().collect();
434 if split.len() < 8 {
435 return Err(Error::Other(format!(
436 "{:?} ({})",
437 Error::ErrAttributeTooShortIceCandidate,
438 split.len()
439 )));
440 }
441
442 let foundation = split[0].to_owned();
444
445 let component: u16 = split[1].parse()?;
447
448 let network = split[2].to_owned();
450
451 let priority: u32 = split[3].parse()?;
453
454 let address = split[4].to_owned();
456
457 let port: u16 = split[5].parse()?;
459
460 let typ = split[7];
461
462 let mut rel_addr = String::new();
463 let mut rel_port = 0;
464 let mut tcp_type = TcpType::Unspecified;
465
466 if split.len() > 8 {
467 let split2 = &split[8..];
468
469 if split2[0] == "raddr" {
470 if split2.len() < 4 {
471 return Err(Error::Other(format!(
472 "{:?}: incorrect length",
473 Error::ErrParseRelatedAddr
474 )));
475 }
476
477 split2[1].clone_into(&mut rel_addr);
479
480 rel_port = split2[3].parse()?;
482 } else if split2[0] == "tcptype" {
483 if split2.len() < 2 {
484 return Err(Error::Other(format!(
485 "{:?}: incorrect length",
486 Error::ErrParseType
487 )));
488 }
489
490 tcp_type = TcpType::from(split2[1]);
491 }
492 }
493
494 match typ {
495 "host" => {
496 let config = CandidateHostConfig {
497 base_config: CandidateConfig {
498 network,
499 address,
500 port,
501 component,
502 priority,
503 foundation,
504 ..CandidateConfig::default()
505 },
506 tcp_type,
507 };
508 config.new_candidate_host()
509 }
510 "srflx" => {
511 let config = CandidateServerReflexiveConfig {
512 base_config: CandidateConfig {
513 network,
514 address,
515 port,
516 component,
517 priority,
518 foundation,
519 ..CandidateConfig::default()
520 },
521 rel_addr,
522 rel_port,
523 url: None,
524 };
525 config.new_candidate_server_reflexive()
526 }
527 "prflx" => {
528 let config = CandidatePeerReflexiveConfig {
529 base_config: CandidateConfig {
530 network,
531 address,
532 port,
533 component,
534 priority,
535 foundation,
536 ..CandidateConfig::default()
537 },
538 rel_addr,
539 rel_port,
540 };
541
542 config.new_candidate_peer_reflexive()
543 }
544 "relay" => {
545 let config = CandidateRelayConfig {
546 base_config: CandidateConfig {
547 network,
548 address,
549 port,
550 component,
551 priority,
552 foundation,
553 ..CandidateConfig::default()
554 },
555 rel_addr,
556 rel_port,
557 url: None,
558 };
559 config.new_candidate_relay()
560 }
561 _ => Err(Error::Other(format!(
562 "{:?} ({})",
563 Error::ErrUnknownCandidateType,
564 typ
565 ))),
566 }
567}