1 use super::*; 2 use crate::candidate::candidate_host::CandidateHostConfig; 3 use crate::candidate::candidate_peer_reflexive::CandidatePeerReflexiveConfig; 4 use crate::candidate::candidate_relay::CandidateRelayConfig; 5 use crate::candidate::candidate_server_reflexive::CandidateServerReflexiveConfig; 6 use crate::error::*; 7 use crate::util::*; 8 9 use async_trait::async_trait; 10 use crc::{Crc, CRC_32_ISCSI}; 11 use std::{ 12 fmt, 13 ops::Add, 14 sync::{ 15 atomic::{AtomicU16, AtomicU64, AtomicU8, Ordering}, 16 Arc, 17 }, 18 time::{Duration, SystemTime, UNIX_EPOCH}, 19 }; 20 use tokio::sync::{broadcast, Mutex}; 21 use util::sync::Mutex as SyncMutex; 22 23 #[derive(Default)] 24 pub struct CandidateBaseConfig { 25 pub candidate_id: String, 26 pub network: String, 27 pub address: String, 28 pub port: u16, 29 pub component: u16, 30 pub priority: u32, 31 pub foundation: String, 32 pub conn: Option<Arc<dyn util::Conn + Send + Sync>>, 33 pub initialized_ch: Option<broadcast::Receiver<()>>, 34 } 35 36 pub struct CandidateBase { 37 pub(crate) id: String, 38 pub(crate) network_type: AtomicU8, 39 pub(crate) candidate_type: CandidateType, 40 41 pub(crate) component: AtomicU16, 42 pub(crate) address: String, 43 pub(crate) port: u16, 44 pub(crate) related_address: Option<CandidateRelatedAddress>, 45 pub(crate) tcp_type: TcpType, 46 47 pub(crate) resolved_addr: SyncMutex<SocketAddr>, 48 49 pub(crate) last_sent: AtomicU64, 50 pub(crate) last_received: AtomicU64, 51 52 pub(crate) conn: Option<Arc<dyn util::Conn + Send + Sync>>, 53 pub(crate) closed_ch: Arc<Mutex<Option<broadcast::Sender<()>>>>, 54 55 pub(crate) foundation_override: String, 56 pub(crate) priority_override: u32, 57 58 //CandidateHost 59 pub(crate) network: String, 60 //CandidateRelay 61 pub(crate) relay_client: Option<Arc<turn::client::Client>>, 62 } 63 64 impl Default for CandidateBase { 65 fn default() -> Self { 66 Self { 67 id: String::new(), 68 network_type: AtomicU8::new(0), 69 candidate_type: CandidateType::default(), 70 71 component: AtomicU16::new(0), 72 address: String::new(), 73 port: 0, 74 related_address: None, 75 tcp_type: TcpType::default(), 76 77 resolved_addr: SyncMutex::new(SocketAddr::new(IpAddr::from([0, 0, 0, 0]), 0)), 78 79 last_sent: AtomicU64::new(0), 80 last_received: AtomicU64::new(0), 81 82 conn: None, 83 closed_ch: Arc::new(Mutex::new(None)), 84 85 foundation_override: String::new(), 86 priority_override: 0, 87 network: String::new(), 88 relay_client: None, 89 } 90 } 91 } 92 93 // String makes the candidateBase printable 94 impl fmt::Display for CandidateBase { 95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 96 if let Some(related_address) = self.related_address() { 97 write!( 98 f, 99 "{} {} {}:{}{}", 100 self.network_type(), 101 self.candidate_type(), 102 self.address(), 103 self.port(), 104 related_address, 105 ) 106 } else { 107 write!( 108 f, 109 "{} {} {}:{}", 110 self.network_type(), 111 self.candidate_type(), 112 self.address(), 113 self.port(), 114 ) 115 } 116 } 117 } 118 119 #[async_trait] 120 impl Candidate for CandidateBase { 121 fn foundation(&self) -> String { 122 if !self.foundation_override.is_empty() { 123 return self.foundation_override.clone(); 124 } 125 126 let mut buf = vec![]; 127 buf.extend_from_slice(self.candidate_type().to_string().as_bytes()); 128 buf.extend_from_slice(self.address.as_bytes()); 129 buf.extend_from_slice(self.network_type().to_string().as_bytes()); 130 131 let checksum = Crc::<u32>::new(&CRC_32_ISCSI).checksum(&buf); 132 133 format!("{}", checksum) 134 } 135 136 /// Returns Candidate ID. 137 fn id(&self) -> String { 138 self.id.clone() 139 } 140 141 /// Returns candidate component. 142 fn component(&self) -> u16 { 143 self.component.load(Ordering::SeqCst) 144 } 145 146 fn set_component(&self, component: u16) { 147 self.component.store(component, Ordering::SeqCst); 148 } 149 150 /// Returns a time indicating the last time this candidate was received. 151 fn last_received(&self) -> SystemTime { 152 UNIX_EPOCH.add(Duration::from_nanos( 153 self.last_received.load(Ordering::SeqCst), 154 )) 155 } 156 157 /// Returns a time indicating the last time this candidate was sent. 158 fn last_sent(&self) -> SystemTime { 159 UNIX_EPOCH.add(Duration::from_nanos(self.last_sent.load(Ordering::SeqCst))) 160 } 161 162 /// Returns candidate NetworkType. 163 fn network_type(&self) -> NetworkType { 164 NetworkType::from(self.network_type.load(Ordering::SeqCst)) 165 } 166 167 /// Returns Candidate Address. 168 fn address(&self) -> String { 169 self.address.clone() 170 } 171 172 /// Returns Candidate Port. 173 fn port(&self) -> u16 { 174 self.port 175 } 176 177 /// Computes the priority for this ICE Candidate. 178 fn priority(&self) -> u32 { 179 if self.priority_override != 0 { 180 return self.priority_override; 181 } 182 183 // The local preference MUST be an integer from 0 (lowest preference) to 184 // 65535 (highest preference) inclusive. When there is only a single IP 185 // address, this value SHOULD be set to 65535. If there are multiple 186 // candidates for a particular component for a particular data stream 187 // that have the same type, the local preference MUST be unique for each 188 // one. 189 (1 << 24) * u32::from(self.candidate_type().preference()) 190 + (1 << 8) * u32::from(self.local_preference()) 191 + (256 - u32::from(self.component())) 192 } 193 194 /// Returns `Option<CandidateRelatedAddress>`. 195 fn related_address(&self) -> Option<CandidateRelatedAddress> { 196 self.related_address.as_ref().cloned() 197 } 198 199 /// Returns candidate type. 200 fn candidate_type(&self) -> CandidateType { 201 self.candidate_type 202 } 203 204 fn tcp_type(&self) -> TcpType { 205 self.tcp_type 206 } 207 208 /// Returns the string representation of the ICECandidate. 209 fn marshal(&self) -> String { 210 let mut val = format!( 211 "{} {} {} {} {} {} typ {}", 212 self.foundation(), 213 self.component(), 214 self.network_type().network_short(), 215 self.priority(), 216 self.address(), 217 self.port(), 218 self.candidate_type() 219 ); 220 221 if self.tcp_type != TcpType::Unspecified { 222 val += format!(" tcptype {}", self.tcp_type()).as_str(); 223 } 224 225 if let Some(related_address) = self.related_address() { 226 val += format!( 227 " raddr {} rport {}", 228 related_address.address, related_address.port, 229 ) 230 .as_str(); 231 } 232 233 val 234 } 235 236 fn addr(&self) -> SocketAddr { 237 *self.resolved_addr.lock() 238 } 239 240 /// Stops the recvLoop. 241 async fn close(&self) -> Result<()> { 242 { 243 let mut closed_ch = self.closed_ch.lock().await; 244 if closed_ch.is_none() { 245 return Err(Error::ErrClosed); 246 } 247 closed_ch.take(); 248 } 249 250 if let Some(relay_client) = &self.relay_client { 251 let _ = relay_client.close().await; 252 } 253 254 if let Some(conn) = &self.conn { 255 let _ = conn.close().await; 256 } 257 258 Ok(()) 259 } 260 261 fn seen(&self, outbound: bool) { 262 let d = SystemTime::now() 263 .duration_since(UNIX_EPOCH) 264 .unwrap_or_else(|_| Duration::from_secs(0)); 265 266 if outbound { 267 self.set_last_sent(d); 268 } else { 269 self.set_last_received(d); 270 } 271 } 272 273 async fn write_to(&self, raw: &[u8], dst: &(dyn Candidate + Send + Sync)) -> Result<usize> { 274 let n = if let Some(conn) = &self.conn { 275 let addr = dst.addr(); 276 conn.send_to(raw, addr).await? 277 } else { 278 0 279 }; 280 self.seen(true); 281 Ok(n) 282 } 283 284 /// Used to compare two candidateBases. 285 fn equal(&self, other: &dyn Candidate) -> bool { 286 self.network_type() == other.network_type() 287 && self.candidate_type() == other.candidate_type() 288 && self.address() == other.address() 289 && self.port() == other.port() 290 && self.tcp_type() == other.tcp_type() 291 && self.related_address() == other.related_address() 292 } 293 294 fn set_ip(&self, ip: &IpAddr) -> Result<()> { 295 let network_type = determine_network_type(&self.network, ip)?; 296 297 self.network_type 298 .store(network_type as u8, Ordering::SeqCst); 299 300 let addr = create_addr(network_type, *ip, self.port); 301 *self.resolved_addr.lock() = addr; 302 303 Ok(()) 304 } 305 306 fn get_conn(&self) -> Option<&Arc<dyn util::Conn + Send + Sync>> { 307 self.conn.as_ref() 308 } 309 310 fn get_closed_ch(&self) -> Arc<Mutex<Option<broadcast::Sender<()>>>> { 311 self.closed_ch.clone() 312 } 313 } 314 315 impl CandidateBase { 316 pub fn set_last_received(&self, d: Duration) { 317 #[allow(clippy::cast_possible_truncation)] 318 self.last_received 319 .store(d.as_nanos() as u64, Ordering::SeqCst); 320 } 321 322 pub fn set_last_sent(&self, d: Duration) { 323 #[allow(clippy::cast_possible_truncation)] 324 self.last_sent.store(d.as_nanos() as u64, Ordering::SeqCst); 325 } 326 327 /// Returns the local preference for this candidate. 328 pub fn local_preference(&self) -> u16 { 329 if self.network_type().is_tcp() { 330 // RFC 6544, section 4.2 331 // 332 // In Section 4.1.2.1 of [RFC5245], a recommended formula for UDP ICE 333 // candidate prioritization is defined. For TCP candidates, the same 334 // formula and candidate type preferences SHOULD be used, and the 335 // RECOMMENDED type preferences for the new candidate types defined in 336 // this document (see Section 5) are 105 for NAT-assisted candidates and 337 // 75 for UDP-tunneled candidates. 338 // 339 // (...) 340 // 341 // With TCP candidates, the local preference part of the recommended 342 // priority formula is updated to also include the directionality 343 // (active, passive, or simultaneous-open) of the TCP connection. The 344 // RECOMMENDED local preference is then defined as: 345 // 346 // local preference = (2^13) * direction-pref + other-pref 347 // 348 // The direction-pref MUST be between 0 and 7 (both inclusive), with 7 349 // being the most preferred. The other-pref MUST be between 0 and 8191 350 // (both inclusive), with 8191 being the most preferred. It is 351 // RECOMMENDED that the host, UDP-tunneled, and relayed TCP candidates 352 // have the direction-pref assigned as follows: 6 for active, 4 for 353 // passive, and 2 for S-O. For the NAT-assisted and server reflexive 354 // candidates, the RECOMMENDED values are: 6 for S-O, 4 for active, and 355 // 2 for passive. 356 // 357 // (...) 358 // 359 // If any two candidates have the same type-preference and direction- 360 // pref, they MUST have a unique other-pref. With this specification, 361 // this usually only happens with multi-homed hosts, in which case 362 // other-pref is the preference for the particular IP address from which 363 // the candidate was obtained. When there is only a single IP address, 364 // this value SHOULD be set to the maximum allowed value (8191). 365 let other_pref: u16 = 8191; 366 367 let direction_pref: u16 = match self.candidate_type() { 368 CandidateType::Host | CandidateType::Relay => match self.tcp_type() { 369 TcpType::Active => 6, 370 TcpType::Passive => 4, 371 TcpType::SimultaneousOpen => 2, 372 TcpType::Unspecified => 0, 373 }, 374 CandidateType::PeerReflexive | CandidateType::ServerReflexive => { 375 match self.tcp_type() { 376 TcpType::SimultaneousOpen => 6, 377 TcpType::Active => 4, 378 TcpType::Passive => 2, 379 TcpType::Unspecified => 0, 380 } 381 } 382 CandidateType::Unspecified => 0, 383 }; 384 385 (1 << 13) * direction_pref + other_pref 386 } else { 387 DEFAULT_LOCAL_PREFERENCE 388 } 389 } 390 } 391 392 /// Creates a Candidate from its string representation. 393 pub fn unmarshal_candidate(raw: &str) -> Result<impl Candidate> { 394 let split: Vec<&str> = raw.split_whitespace().collect(); 395 if split.len() < 8 { 396 return Err(Error::Other(format!( 397 "{:?} ({})", 398 Error::ErrAttributeTooShortIceCandidate, 399 split.len() 400 ))); 401 } 402 403 // Foundation 404 let foundation = split[0].to_owned(); 405 406 // Component 407 let component: u16 = split[1].parse()?; 408 409 // Network 410 let network = split[2].to_owned(); 411 412 // Priority 413 let priority: u32 = split[3].parse()?; 414 415 // Address 416 let address = split[4].to_owned(); 417 418 // Port 419 let port: u16 = split[5].parse()?; 420 421 let typ = split[7]; 422 423 let mut rel_addr = String::new(); 424 let mut rel_port = 0; 425 let mut tcp_type = TcpType::Unspecified; 426 427 if split.len() > 8 { 428 let split2 = &split[8..]; 429 430 if split2[0] == "raddr" { 431 if split2.len() < 4 { 432 return Err(Error::Other(format!( 433 "{:?}: incorrect length", 434 Error::ErrParseRelatedAddr 435 ))); 436 } 437 438 // RelatedAddress 439 rel_addr = split2[1].to_owned(); 440 441 // RelatedPort 442 rel_port = split2[3].parse()?; 443 } else if split2[0] == "tcptype" { 444 if split2.len() < 2 { 445 return Err(Error::Other(format!( 446 "{:?}: incorrect length", 447 Error::ErrParseType 448 ))); 449 } 450 451 tcp_type = TcpType::from(split2[1]); 452 } 453 } 454 455 match typ { 456 "host" => { 457 let config = CandidateHostConfig { 458 base_config: CandidateBaseConfig { 459 network, 460 address, 461 port, 462 component, 463 priority, 464 foundation, 465 ..CandidateBaseConfig::default() 466 }, 467 tcp_type, 468 }; 469 config.new_candidate_host() 470 } 471 "srflx" => { 472 let config = CandidateServerReflexiveConfig { 473 base_config: CandidateBaseConfig { 474 network, 475 address, 476 port, 477 component, 478 priority, 479 foundation, 480 ..CandidateBaseConfig::default() 481 }, 482 rel_addr, 483 rel_port, 484 }; 485 config.new_candidate_server_reflexive() 486 } 487 "prflx" => { 488 let config = CandidatePeerReflexiveConfig { 489 base_config: CandidateBaseConfig { 490 network, 491 address, 492 port, 493 component, 494 priority, 495 foundation, 496 ..CandidateBaseConfig::default() 497 }, 498 rel_addr, 499 rel_port, 500 }; 501 502 config.new_candidate_peer_reflexive() 503 } 504 "relay" => { 505 let config = CandidateRelayConfig { 506 base_config: CandidateBaseConfig { 507 network, 508 address, 509 port, 510 component, 511 priority, 512 foundation, 513 ..CandidateBaseConfig::default() 514 }, 515 rel_addr, 516 rel_port, 517 ..CandidateRelayConfig::default() 518 }; 519 config.new_candidate_relay() 520 } 521 _ => Err(Error::Other(format!( 522 "{:?} ({})", 523 Error::ErrUnknownCandidateType, 524 typ 525 ))), 526 } 527 } 528