1#[cfg(test)]
2mod agent_test;
3
4pub mod agent_config;
5mod agent_proto;
6pub mod agent_selector;
7pub mod agent_stats;
8
9use agent_config::*;
10use bytes::BytesMut;
11use log::{debug, error, info, trace, warn};
12use mdns::{Mdns, QueryId};
13use sansio::Protocol;
14use std::collections::{HashMap, VecDeque};
15use std::net::{IpAddr, Ipv4Addr, SocketAddr};
16use std::sync::Arc;
17use std::time::{Duration, Instant};
18use stun::attributes::*;
19use stun::fingerprint::*;
20use stun::integrity::*;
21use stun::message::*;
22use stun::textattrs::*;
23use stun::xoraddr::*;
24
25use crate::candidate::candidate_peer_reflexive::CandidatePeerReflexiveConfig;
26use crate::candidate::{candidate_pair::*, *};
27use crate::mdns::{MulticastDnsMode, create_multicast_dns, generate_multicast_dns_name};
28use crate::network_type::NetworkType;
29use crate::rand::*;
30use crate::state::*;
31use crate::tcp_type::TcpType;
32use crate::url::*;
33use shared::error::*;
34use shared::{TaggedBytesMut, TransportContext, TransportProtocol};
35
36const ZERO_DURATION: Duration = Duration::from_secs(0);
37
38#[derive(Debug, Clone)]
39pub(crate) struct BindingRequest {
40 pub(crate) timestamp: Instant,
41 pub(crate) transaction_id: TransactionId,
42 pub(crate) destination: SocketAddr,
43 pub(crate) is_use_candidate: bool,
44}
45
46impl Default for BindingRequest {
47 fn default() -> Self {
48 Self {
49 timestamp: Instant::now(),
50 transaction_id: TransactionId::default(),
51 destination: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 0),
52 is_use_candidate: false,
53 }
54 }
55}
56
57#[derive(Default, Clone)]
58pub struct Credentials {
59 pub ufrag: String,
60 pub pwd: String,
61}
62
63#[derive(Default, Clone)]
64pub(crate) struct UfragPwd {
65 pub(crate) local_credentials: Credentials,
66 pub(crate) remote_credentials: Option<Credentials>,
67}
68
69fn assert_inbound_username(m: &Message, expected_username: &str) -> Result<()> {
70 let mut username = Username::new(ATTR_USERNAME, String::new());
71 username.get_from(m)?;
72
73 if username.to_string() != expected_username {
74 return Err(Error::Other(format!(
75 "{:?} expected({}) actual({})",
76 Error::ErrMismatchUsername,
77 expected_username,
78 username,
79 )));
80 }
81
82 Ok(())
83}
84
85fn assert_inbound_message_integrity(m: &mut Message, key: &[u8]) -> Result<()> {
86 let message_integrity_attr = MessageIntegrity(key.to_vec());
87 message_integrity_attr.check(m)
88}
89
90pub enum Event {
91 ConnectionStateChange(ConnectionState),
92 SelectedCandidatePairChange(Box<Candidate>, Box<Candidate>),
93 RoleChange(bool),
96}
97
98pub struct Agent {
100 pub(crate) tie_breaker: u64,
101 pub(crate) is_controlling: bool,
102 pub(crate) lite: bool,
103
104 pub(crate) start_time: Instant,
105
106 pub(crate) connection_state: ConnectionState,
107 pub(crate) last_connection_state: ConnectionState,
108
109 pub(crate) ufrag_pwd: UfragPwd,
111
112 pub(crate) local_candidates: Vec<Candidate>,
113 pub(crate) remote_candidates: Vec<Candidate>,
114 pub(crate) candidate_pairs: Vec<CandidatePair>,
115 pub(crate) nominated_pair: Option<usize>,
116 pub(crate) selected_pair: Option<usize>,
117
118 pub(crate) pending_binding_requests: Vec<BindingRequest>,
120
121 pub(crate) insecure_skip_verify: bool,
123 pub(crate) max_binding_requests: u16,
124 pub(crate) host_acceptance_min_wait: Duration,
125 pub(crate) srflx_acceptance_min_wait: Duration,
126 pub(crate) prflx_acceptance_min_wait: Duration,
127 pub(crate) relay_acceptance_min_wait: Duration,
128 pub(crate) disconnected_timeout: Duration,
131 pub(crate) failed_timeout: Duration,
134 pub(crate) keepalive_interval: Duration,
137 pub(crate) last_consent_sent: Instant,
139 pub(crate) check_interval: Duration,
141 pub(crate) checking_duration: Instant,
142 pub(crate) last_checking_time: Instant,
143 pub(crate) force_candidate_contact: bool,
149
150 pub(crate) mdns: Option<Mdns>,
151 pub(crate) mdns_queries: HashMap<QueryId, Candidate>,
152
153 pub(crate) mdns_mode: MulticastDnsMode,
154 pub(crate) mdns_local_name: String,
155 pub(crate) mdns_local_ip: Option<IpAddr>,
156
157 pub(crate) candidate_types: Vec<CandidateType>,
158 pub(crate) network_types: Vec<NetworkType>,
159 pub(crate) urls: Vec<Url>,
160
161 pub(crate) write_outs: VecDeque<TaggedBytesMut>,
162 pub(crate) event_outs: VecDeque<Event>,
163}
164
165impl Default for Agent {
166 fn default() -> Self {
167 Self {
168 tie_breaker: 0,
169 is_controlling: false,
170 lite: false,
171 start_time: Instant::now(),
172 connection_state: Default::default(),
173 last_connection_state: Default::default(),
174 ufrag_pwd: Default::default(),
175 local_candidates: vec![],
176 remote_candidates: vec![],
177 candidate_pairs: vec![],
178 nominated_pair: None,
179 selected_pair: None,
180 pending_binding_requests: vec![],
181 insecure_skip_verify: false,
182 max_binding_requests: 0,
183 host_acceptance_min_wait: Default::default(),
184 srflx_acceptance_min_wait: Default::default(),
185 prflx_acceptance_min_wait: Default::default(),
186 relay_acceptance_min_wait: Default::default(),
187 disconnected_timeout: Default::default(),
188 failed_timeout: Default::default(),
189 keepalive_interval: Default::default(),
190 last_consent_sent: Instant::now(),
191 check_interval: Default::default(),
192 checking_duration: Instant::now(),
193 last_checking_time: Instant::now(),
194 force_candidate_contact: false,
195 mdns_mode: MulticastDnsMode::Disabled,
196 mdns_local_name: "".to_owned(),
197 mdns_local_ip: None,
198 mdns_queries: HashMap::new(),
199 mdns: None,
200 candidate_types: vec![],
201 network_types: vec![],
202 urls: vec![],
203 write_outs: Default::default(),
204 event_outs: Default::default(),
205 }
206 }
207}
208
209impl Agent {
210 pub fn new(config: Arc<AgentConfig>) -> Result<Self> {
212 let mut mdns_local_name = config.multicast_dns_local_name.clone();
213 if mdns_local_name.is_empty() {
214 mdns_local_name = generate_multicast_dns_name();
215 }
216
217 if !mdns_local_name.ends_with(".local") || mdns_local_name.split('.').count() != 2 {
218 return Err(Error::ErrInvalidMulticastDnshostName);
219 }
220
221 let mdns_mode = config.multicast_dns_mode;
222 let mdns = create_multicast_dns(
223 mdns_mode,
224 &mdns_local_name,
225 &config.multicast_dns_local_ip,
226 &config.multicast_dns_query_timeout,
227 )
228 .unwrap_or_else(|err| {
229 warn!("Failed to initialize mDNS {mdns_local_name}: {err}");
232 None
233 });
234
235 let candidate_types = if config.candidate_types.is_empty() {
236 default_candidate_types()
237 } else {
238 config.candidate_types.clone()
239 };
240
241 if config.lite && (candidate_types.len() != 1 || candidate_types[0] != CandidateType::Host)
242 {
243 return Err(Error::ErrLiteUsingNonHostCandidates);
244 }
245
246 if !config.urls.is_empty()
247 && !contains_candidate_type(CandidateType::ServerReflexive, &candidate_types)
248 && !contains_candidate_type(CandidateType::Relay, &candidate_types)
249 {
250 return Err(Error::ErrUselessUrlsProvided);
251 }
252
253 let mut agent = Self {
254 tie_breaker: rand::random::<u64>(),
255 is_controlling: config.is_controlling,
256 lite: config.lite,
257
258 start_time: Instant::now(),
259
260 nominated_pair: None,
261 selected_pair: None,
262 candidate_pairs: vec![],
263
264 connection_state: ConnectionState::New,
265
266 insecure_skip_verify: config.insecure_skip_verify,
267
268 max_binding_requests: if let Some(max_binding_requests) = config.max_binding_requests {
272 max_binding_requests
273 } else {
274 DEFAULT_MAX_BINDING_REQUESTS
275 },
276 host_acceptance_min_wait: if let Some(host_acceptance_min_wait) =
277 config.host_acceptance_min_wait
278 {
279 host_acceptance_min_wait
280 } else {
281 DEFAULT_HOST_ACCEPTANCE_MIN_WAIT
282 },
283 srflx_acceptance_min_wait: if let Some(srflx_acceptance_min_wait) =
284 config.srflx_acceptance_min_wait
285 {
286 srflx_acceptance_min_wait
287 } else {
288 DEFAULT_SRFLX_ACCEPTANCE_MIN_WAIT
289 },
290 prflx_acceptance_min_wait: if let Some(prflx_acceptance_min_wait) =
291 config.prflx_acceptance_min_wait
292 {
293 prflx_acceptance_min_wait
294 } else {
295 DEFAULT_PRFLX_ACCEPTANCE_MIN_WAIT
296 },
297 relay_acceptance_min_wait: if let Some(relay_acceptance_min_wait) =
298 config.relay_acceptance_min_wait
299 {
300 relay_acceptance_min_wait
301 } else {
302 DEFAULT_RELAY_ACCEPTANCE_MIN_WAIT
303 },
304
305 disconnected_timeout: if let Some(disconnected_timeout) = config.disconnected_timeout {
308 disconnected_timeout
309 } else {
310 DEFAULT_DISCONNECTED_TIMEOUT
311 },
312
313 failed_timeout: if let Some(failed_timeout) = config.failed_timeout {
316 failed_timeout
317 } else {
318 DEFAULT_FAILED_TIMEOUT
319 },
320
321 keepalive_interval: if let Some(keepalive_interval) = config.keepalive_interval {
324 keepalive_interval
325 } else {
326 DEFAULT_KEEPALIVE_INTERVAL
327 },
328
329 check_interval: if config.check_interval == Duration::from_secs(0) {
331 DEFAULT_CHECK_INTERVAL
332 } else {
333 config.check_interval
334 },
335 last_consent_sent: Instant::now(),
336 checking_duration: Instant::now(),
337 last_checking_time: Instant::now(),
338 force_candidate_contact: false,
339 last_connection_state: ConnectionState::Unspecified,
340
341 mdns,
342 mdns_queries: HashMap::new(),
343
344 mdns_mode,
345 mdns_local_name,
346 mdns_local_ip: config.multicast_dns_local_ip,
347
348 ufrag_pwd: UfragPwd::default(),
349
350 local_candidates: vec![],
351 remote_candidates: vec![],
352
353 pending_binding_requests: vec![],
355
356 candidate_types,
357 network_types: config.network_types.clone(),
358 urls: config.urls.clone(),
359
360 write_outs: VecDeque::new(),
361 event_outs: VecDeque::new(),
362 };
363
364 if let Err(err) = agent.restart(config.local_ufrag.clone(), config.local_pwd.clone(), false)
366 {
367 let _ = agent.close();
368 return Err(err);
369 }
370
371 Ok(agent)
372 }
373
374 pub fn add_local_candidate(&mut self, mut c: Candidate) -> Result<bool> {
376 if !self.network_types.is_empty() {
378 let candidate_network_type = c.network_type();
379 if !self.network_types.contains(&candidate_network_type) {
380 debug!(
381 "Ignoring local candidate with network type {:?} (not in configured network types: {:?})",
382 candidate_network_type, self.network_types
383 );
384 return Ok(false);
385 }
386 }
387
388 let candidate_type = c.candidate_type();
390 if !self.candidate_types.is_empty() && !self.candidate_types.contains(&candidate_type) {
391 debug!(
392 "Ignoring local candidate with type {:?} (not in configured candidate types: {:?})",
393 candidate_type, self.candidate_types
394 );
395 return Ok(false);
396 }
397
398 if c.candidate_type() == CandidateType::Host
399 && self.mdns_mode == MulticastDnsMode::QueryAndGather
400 && c.network_type == NetworkType::Udp4
401 && self
402 .mdns_local_ip
403 .is_some_and(|local_ip| local_ip == c.addr().ip())
404 {
405 trace!(
408 "mDNS hides local ip {} with local name {}",
409 c.address, self.mdns_local_name
410 );
411 c.address = self.mdns_local_name.clone();
412 }
413
414 for cand in &self.local_candidates {
415 if cand.equal(&c) {
416 return Ok(false);
417 }
418 }
419
420 self.local_candidates.push(c);
421 let local_index = self.local_candidates.len() - 1;
422
423 for remote_index in 0..self.remote_candidates.len() {
424 if self.local_candidates[local_index]
425 .can_pair_with(&self.remote_candidates[remote_index])
426 {
427 self.add_pair(local_index, remote_index);
428 }
429 }
430
431 self.request_connectivity_check();
432
433 Ok(true)
434 }
435
436 pub fn add_remote_candidate(&mut self, c: Candidate) -> Result<bool> {
438 if !self.network_types.is_empty() {
440 let candidate_network_type = c.network_type();
441 if !self.network_types.contains(&candidate_network_type) {
442 debug!(
443 "Ignoring remote candidate with network type {:?} (not in configured network types: {:?})",
444 candidate_network_type, self.network_types
445 );
446 return Ok(false);
447 }
448 }
449
450 if c.tcp_type() == TcpType::Active {
454 debug!(
455 "Ignoring remote candidate with tcptype active: {}",
456 c.address()
457 );
458 return Ok(false);
459 }
460
461 if c.candidate_type() == CandidateType::Host && c.address().ends_with(".local") {
463 if self.mdns_mode == MulticastDnsMode::Disabled {
464 warn!(
465 "remote mDNS candidate added, but mDNS is disabled: ({})",
466 c.address()
467 );
468 return Ok(false);
469 }
470
471 if c.candidate_type() != CandidateType::Host {
472 return Err(Error::ErrAddressParseFailed);
473 }
474
475 if let Some(mdns_conn) = &mut self.mdns {
476 let query_id = mdns_conn.query(c.address());
477 self.mdns_queries.insert(query_id, c);
478 }
479
480 return Ok(false);
481 }
482
483 self.trigger_request_connectivity_check(vec![c]);
484 Ok(true)
485 }
486
487 fn trigger_request_connectivity_check(&mut self, remote_candidates: Vec<Candidate>) {
488 for c in remote_candidates {
489 if !self.remote_candidates.iter().any(|cand| cand.equal(&c)) {
490 self.remote_candidates.push(c);
491 let remote_index = self.remote_candidates.len() - 1;
492
493 for local_index in 0..self.local_candidates.len() {
494 if self.local_candidates[local_index]
495 .can_pair_with(&self.remote_candidates[remote_index])
496 {
497 self.add_pair(local_index, remote_index);
498 }
499 }
500
501 self.request_connectivity_check();
502 }
503 }
504 }
505
506 pub fn set_remote_credentials(
508 &mut self,
509 remote_ufrag: String,
510 remote_pwd: String,
511 ) -> Result<()> {
512 if remote_ufrag.is_empty() {
513 return Err(Error::ErrRemoteUfragEmpty);
514 } else if remote_pwd.is_empty() {
515 return Err(Error::ErrRemotePwdEmpty);
516 }
517
518 self.ufrag_pwd.remote_credentials = Some(Credentials {
519 ufrag: remote_ufrag,
520 pwd: remote_pwd,
521 });
522
523 Ok(())
524 }
525
526 pub fn get_remote_credentials(&self) -> Option<&Credentials> {
528 self.ufrag_pwd.remote_credentials.as_ref()
529 }
530
531 pub fn get_local_credentials(&self) -> &Credentials {
533 &self.ufrag_pwd.local_credentials
534 }
535
536 pub fn role(&self) -> bool {
537 self.is_controlling
538 }
539
540 pub fn set_role(&mut self, is_controlling: bool) {
541 self.is_controlling = is_controlling;
542 }
543
544 pub fn state(&self) -> ConnectionState {
545 self.connection_state
546 }
547
548 pub fn is_valid_non_stun_traffic(&mut self, transport: TransportContext) -> bool {
549 self.find_local_candidate(transport.local_addr, transport.transport_protocol)
550 .is_some()
551 && self.validate_non_stun_traffic(transport.peer_addr)
552 }
553
554 fn get_timeout_interval(&self) -> Duration {
555 let (check_interval, keepalive_interval, disconnected_timeout, failed_timeout) = (
556 self.check_interval,
557 self.keepalive_interval,
558 self.disconnected_timeout,
559 self.failed_timeout,
560 );
561 let mut interval = DEFAULT_CHECK_INTERVAL;
562
563 let mut update_interval = |x: Duration| {
564 if x != ZERO_DURATION && (interval == ZERO_DURATION || interval > x) {
565 interval = x;
566 }
567 };
568
569 match self.last_connection_state {
570 ConnectionState::New | ConnectionState::Checking => {
571 update_interval(check_interval);
573 }
574 ConnectionState::Connected | ConnectionState::Disconnected => {
575 update_interval(keepalive_interval);
576 }
577 _ => {}
578 };
579 update_interval(disconnected_timeout);
581 update_interval(failed_timeout);
582 interval
583 }
584
585 pub fn get_selected_candidate_pair(&self) -> Option<(&Candidate, &Candidate)> {
587 if let Some(pair_index) = self.get_selected_pair() {
588 let candidate_pair = &self.candidate_pairs[pair_index];
589 Some((
590 &self.local_candidates[candidate_pair.local_index],
591 &self.remote_candidates[candidate_pair.remote_index],
592 ))
593 } else {
594 None
595 }
596 }
597
598 pub fn get_best_available_candidate_pair(&self) -> Option<(&Candidate, &Candidate)> {
599 if let Some(pair_index) = self.get_best_available_pair() {
600 let candidate_pair = &self.candidate_pairs[pair_index];
601 Some((
602 &self.local_candidates[candidate_pair.local_index],
603 &self.remote_candidates[candidate_pair.remote_index],
604 ))
605 } else {
606 None
607 }
608 }
609
610 pub fn start_connectivity_checks(
612 &mut self,
613 is_controlling: bool,
614 remote_ufrag: String,
615 remote_pwd: String,
616 ) -> Result<()> {
617 debug!(
618 "Started agent: isControlling? {}, remoteUfrag: {}, remotePwd: {}",
619 is_controlling, remote_ufrag, remote_pwd
620 );
621 self.set_remote_credentials(remote_ufrag, remote_pwd)?;
622 self.is_controlling = is_controlling;
623 self.start();
624
625 self.update_connection_state(ConnectionState::Checking);
626 self.request_connectivity_check();
627
628 Ok(())
629 }
630
631 pub fn restart(
634 &mut self,
635 mut ufrag: String,
636 mut pwd: String,
637 keep_local_candidates: bool,
638 ) -> Result<()> {
639 if ufrag.is_empty() {
640 ufrag = generate_ufrag();
641 }
642 if pwd.is_empty() {
643 pwd = generate_pwd();
644 }
645
646 if ufrag.len() * 8 < 24 {
647 return Err(Error::ErrLocalUfragInsufficientBits);
648 }
649 if pwd.len() * 8 < 128 {
650 return Err(Error::ErrLocalPwdInsufficientBits);
651 }
652
653 self.ufrag_pwd.local_credentials.ufrag = ufrag;
655 self.ufrag_pwd.local_credentials.pwd = pwd;
656 self.ufrag_pwd.remote_credentials = None;
657
658 self.pending_binding_requests = vec![];
659
660 self.candidate_pairs = vec![];
661
662 self.set_selected_pair(None);
663 self.delete_all_candidates(keep_local_candidates);
664 self.start();
665
666 if self.connection_state != ConnectionState::New {
669 self.update_connection_state(ConnectionState::Checking);
670 }
671
672 Ok(())
673 }
674
675 pub fn get_local_candidates(&self) -> &[Candidate] {
677 &self.local_candidates
678 }
679
680 fn contact(&mut self, now: Instant) {
681 self.force_candidate_contact = false;
685
686 if self.connection_state == ConnectionState::Failed {
687 self.last_connection_state = self.connection_state;
690 return;
691 }
692 if self.connection_state == ConnectionState::Checking {
693 if self.last_connection_state != self.connection_state {
695 self.checking_duration = now;
696 }
697
698 if now
700 .checked_duration_since(self.checking_duration)
701 .unwrap_or_else(|| Duration::from_secs(0))
702 > self.disconnected_timeout + self.failed_timeout
703 {
704 self.update_connection_state(ConnectionState::Failed);
705 self.last_connection_state = self.connection_state;
706 return;
707 }
708 }
709
710 self.contact_candidates();
711
712 self.last_connection_state = self.connection_state;
713 self.last_checking_time = now;
714 }
715
716 pub(crate) fn update_connection_state(&mut self, new_state: ConnectionState) {
717 if self.connection_state != new_state {
718 if new_state == ConnectionState::Failed {
720 self.set_selected_pair(None);
721 self.delete_all_candidates(false);
722 }
723
724 info!(
725 "[{}]: Setting new connection state: {}",
726 self.get_name(),
727 new_state
728 );
729 self.connection_state = new_state;
730 self.event_outs
731 .push_back(Event::ConnectionStateChange(new_state));
732 }
733 }
734
735 pub(crate) fn set_selected_pair(&mut self, selected_pair: Option<usize>) {
736 if let Some(pair_index) = selected_pair {
737 trace!(
738 "[{}]: Set selected candidate pair: {:?}",
739 self.get_name(),
740 self.candidate_pairs[pair_index]
741 );
742
743 self.candidate_pairs[pair_index].nominated = true;
744 self.selected_pair = Some(pair_index);
745
746 self.update_connection_state(ConnectionState::Connected);
747
748 let candidate_pair = &self.candidate_pairs[pair_index];
750 self.event_outs
751 .push_back(Event::SelectedCandidatePairChange(
752 Box::new(self.local_candidates[candidate_pair.local_index].clone()),
753 Box::new(self.remote_candidates[candidate_pair.remote_index].clone()),
754 ));
755 } else {
756 self.selected_pair = None;
757 }
758 }
759
760 pub(crate) fn ping_all_candidates(&mut self) {
761 let mut pairs: Vec<(usize, usize)> = vec![];
762
763 let name = self.get_name().to_string();
764 if self.candidate_pairs.is_empty() {
765 warn!(
766 "[{}]: pingAllCandidates called with no candidate pairs. Connection is not possible yet.",
767 name,
768 );
769 }
770 for p in &mut self.candidate_pairs {
771 if p.state == CandidatePairState::Waiting {
772 p.state = CandidatePairState::InProgress;
773 } else if p.state != CandidatePairState::InProgress {
774 continue;
775 }
776
777 if p.binding_request_count > self.max_binding_requests {
778 trace!(
779 "[{}]: max requests reached for pair {} (local_addr {} <-> remote_addr {}), marking it as failed",
780 name,
781 *p,
782 self.local_candidates[p.local_index].addr(),
783 self.remote_candidates[p.remote_index].addr()
784 );
785 p.state = CandidatePairState::Failed;
786 } else {
787 p.binding_request_count += 1;
788 let local = p.local_index;
789 let remote = p.remote_index;
790 pairs.push((local, remote));
791 }
792 }
793
794 if !pairs.is_empty() {
795 trace!(
796 "[{}]: pinging all {} candidates",
797 self.get_name(),
798 pairs.len()
799 );
800 }
801
802 for (local, remote) in pairs {
803 self.ping_candidate(local, remote);
804 }
805 }
806
807 pub(crate) fn add_pair(&mut self, local_index: usize, remote_index: usize) {
808 let p = CandidatePair::new(
809 local_index,
810 remote_index,
811 self.local_candidates[local_index].priority(),
812 self.remote_candidates[remote_index].priority(),
813 self.is_controlling,
814 );
815 self.candidate_pairs.push(p);
816 }
817
818 pub(crate) fn find_pair(&self, local_index: usize, remote_index: usize) -> Option<usize> {
819 for (index, p) in self.candidate_pairs.iter().enumerate() {
820 if p.local_index == local_index && p.remote_index == remote_index {
821 return Some(index);
822 }
823 }
824 None
825 }
826
827 pub(crate) fn validate_selected_pair(&mut self) -> bool {
830 let (valid, disconnected_time) = {
831 self.selected_pair.as_ref().map_or_else(
832 || (false, Duration::from_secs(0)),
833 |&pair_index| {
834 let remote_index = self.candidate_pairs[pair_index].remote_index;
835
836 let disconnected_time = Instant::now()
837 .duration_since(self.remote_candidates[remote_index].last_received());
838 (true, disconnected_time)
839 },
840 )
841 };
842
843 if valid {
844 let mut total_time_to_failure = self.failed_timeout;
846 if total_time_to_failure != Duration::from_secs(0) {
847 total_time_to_failure += self.disconnected_timeout;
848 }
849
850 if total_time_to_failure != Duration::from_secs(0)
851 && disconnected_time > total_time_to_failure
852 {
853 self.update_connection_state(ConnectionState::Failed);
854 } else if self.disconnected_timeout != Duration::from_secs(0)
855 && disconnected_time > self.disconnected_timeout
856 {
857 self.update_connection_state(ConnectionState::Disconnected);
858 } else {
859 self.update_connection_state(ConnectionState::Connected);
860 }
861 }
862
863 valid
864 }
865
866 pub(crate) fn check_keepalive(&mut self) {
869 let (local_index, remote_index, pair_index) = {
870 self.selected_pair
871 .as_ref()
872 .map_or((None, None, None), |&pair_index| {
873 let p = &self.candidate_pairs[pair_index];
874 (Some(p.local_index), Some(p.remote_index), Some(pair_index))
875 })
876 };
877
878 if let (Some(local_index), Some(remote_index), Some(pair_index)) =
879 (local_index, remote_index, pair_index)
880 && self.keepalive_interval != Duration::from_secs(0)
881 && self.last_consent_sent.elapsed() >= self.keepalive_interval
882 {
883 self.last_consent_sent = Instant::now();
884 self.candidate_pairs[pair_index].on_consent_request_sent();
885 self.ping_candidate(local_index, remote_index);
886 }
887 }
888
889 fn request_connectivity_check(&mut self) {
890 self.force_candidate_contact = true;
896 }
897
898 pub(crate) fn delete_all_candidates(&mut self, keep_local_candidates: bool) {
903 if !keep_local_candidates {
904 self.local_candidates.clear();
905 }
906 self.remote_candidates.clear();
907
908 self.candidate_pairs.clear();
914 self.selected_pair = None;
915 self.nominated_pair = None;
916 }
917
918 pub(crate) fn find_remote_candidate(&self, addr: SocketAddr) -> Option<usize> {
919 for (index, c) in self.remote_candidates.iter().enumerate() {
920 if c.addr() == addr {
921 return Some(index);
922 }
923 }
924 None
925 }
926
927 pub(crate) fn find_local_candidate(
928 &self,
929 addr: SocketAddr,
930 transport_protocol: TransportProtocol,
931 ) -> Option<usize> {
932 for (index, c) in self.local_candidates.iter().enumerate() {
933 if c.network_type().to_protocol() != transport_protocol {
934 continue;
935 }
936
937 if c.tcp_type() == TcpType::Active && transport_protocol == TransportProtocol::TCP {
941 if c.addr().ip() == addr.ip() {
942 return Some(index);
943 }
944 } else if c.addr() == addr {
945 return Some(index);
946 } else if let Some(related_address) = c.related_address()
947 && related_address.address == addr.ip().to_string()
948 && related_address.port == addr.port()
949 {
950 return Some(index);
951 }
952 }
953 None
954 }
955
956 pub(crate) fn send_binding_request(
957 &mut self,
958 m: &Message,
959 local_index: usize,
960 remote_index: usize,
961 ) {
962 trace!(
963 "[{}]: ping STUN from {} to {}",
964 self.get_name(),
965 self.local_candidates[local_index],
966 self.remote_candidates[remote_index],
967 );
968
969 self.invalidate_pending_binding_requests(Instant::now());
970
971 self.pending_binding_requests.push(BindingRequest {
972 timestamp: Instant::now(),
973 transaction_id: m.transaction_id,
974 destination: self.remote_candidates[remote_index].addr(),
975 is_use_candidate: m.contains(ATTR_USE_CANDIDATE),
976 });
977
978 if let Some(pair_index) = self.find_pair(local_index, remote_index) {
980 self.candidate_pairs[pair_index].on_request_sent();
981 }
982
983 self.send_stun(m, local_index, remote_index);
984 }
985
986 pub(crate) fn send_binding_success(
987 &mut self,
988 m: &Message,
989 local_index: usize,
990 remote_index: usize,
991 ) {
992 let addr = self.remote_candidates[remote_index].addr();
993 let (ip, port) = (addr.ip(), addr.port());
994 let local_pwd = self.ufrag_pwd.local_credentials.pwd.clone();
995
996 let (out, result) = {
997 let mut out = Message::new();
998 let result = out.build(&[
999 Box::new(m.clone()),
1000 Box::new(BINDING_SUCCESS),
1001 Box::new(XorMappedAddress { ip, port }),
1002 Box::new(MessageIntegrity::new_short_term_integrity(local_pwd)),
1003 Box::new(FINGERPRINT),
1004 ]);
1005 (out, result)
1006 };
1007
1008 if let Err(err) = result {
1009 warn!(
1010 "[{}]: Failed to handle inbound ICE from: {} to: {} error: {}",
1011 self.get_name(),
1012 self.local_candidates[local_index],
1013 self.remote_candidates[remote_index],
1014 err
1015 );
1016 } else {
1017 if let Some(pair_index) = self.find_pair(local_index, remote_index) {
1019 self.candidate_pairs[pair_index].on_response_sent();
1020 }
1021 self.send_stun(&out, local_index, remote_index);
1022 }
1023 }
1024
1025 pub(crate) fn send_role_conflict_error(
1028 &mut self,
1029 m: &Message,
1030 local_index: usize,
1031 remote_index: usize,
1032 ) {
1033 use stun::error_code::*;
1034
1035 let local_pwd = self.ufrag_pwd.local_credentials.pwd.clone();
1036
1037 let (out, result) = {
1038 let mut out = Message::new();
1039 let result = out.build(&[
1040 Box::new(m.clone()),
1041 Box::new(stun::message::BINDING_ERROR),
1042 Box::new(CODE_ROLE_CONFLICT),
1043 Box::new(MessageIntegrity::new_short_term_integrity(local_pwd)),
1044 Box::new(FINGERPRINT),
1045 ]);
1046 (out, result)
1047 };
1048
1049 if let Err(err) = result {
1050 warn!(
1051 "[{}]: Failed to send role conflict error from: {} to: {} error: {}",
1052 self.get_name(),
1053 self.local_candidates[local_index],
1054 self.remote_candidates[remote_index],
1055 err
1056 );
1057 } else {
1058 debug!(
1059 "[{}]: Sent 487 Role Conflict error from {} to {}",
1060 self.get_name(),
1061 self.local_candidates[local_index],
1062 self.remote_candidates[remote_index]
1063 );
1064 self.send_stun(&out, local_index, remote_index);
1065 }
1066 }
1067
1068 pub(crate) fn switch_role(&mut self) {
1071 self.is_controlling = !self.is_controlling;
1072
1073 for pair in &mut self.candidate_pairs {
1076 pair.ice_role_controlling = self.is_controlling;
1077 }
1078
1079 self.nominated_pair = None;
1081
1082 info!(
1083 "[{}]: Role switched, recomputed {} candidate pair priorities",
1084 self.get_name(),
1085 self.candidate_pairs.len()
1086 );
1087
1088 self.event_outs
1089 .push_back(Event::RoleChange(self.is_controlling));
1090 }
1091
1092 pub(crate) fn invalidate_pending_binding_requests(&mut self, filter_time: Instant) {
1097 let pending_binding_requests = &mut self.pending_binding_requests;
1098 let initial_size = pending_binding_requests.len();
1099
1100 let mut temp = vec![];
1101 for binding_request in pending_binding_requests.drain(..) {
1102 if filter_time
1103 .checked_duration_since(binding_request.timestamp)
1104 .map(|duration| duration < MAX_BINDING_REQUEST_TIMEOUT)
1105 .unwrap_or(true)
1106 {
1107 temp.push(binding_request);
1108 }
1109 }
1110
1111 *pending_binding_requests = temp;
1112 let bind_requests_remaining = pending_binding_requests.len();
1113 let bind_requests_removed = initial_size - bind_requests_remaining;
1114 if bind_requests_removed > 0 {
1115 trace!(
1116 "[{}]: Discarded {} binding requests because they expired, still {} remaining",
1117 self.get_name(),
1118 bind_requests_removed,
1119 bind_requests_remaining,
1120 );
1121 }
1122 }
1123
1124 pub(crate) fn handle_inbound_binding_success(
1127 &mut self,
1128 id: TransactionId,
1129 ) -> Option<BindingRequest> {
1130 self.invalidate_pending_binding_requests(Instant::now());
1131
1132 let pending_binding_requests = &mut self.pending_binding_requests;
1133 for i in 0..pending_binding_requests.len() {
1134 if pending_binding_requests[i].transaction_id == id {
1135 let valid_binding_request = pending_binding_requests.remove(i);
1136 return Some(valid_binding_request);
1137 }
1138 }
1139 None
1140 }
1141
1142 pub(crate) fn handle_inbound(
1144 &mut self,
1145 now: Instant,
1146 m: &mut Message,
1147 local_index: usize,
1148 remote_addr: SocketAddr,
1149 ) -> Result<()> {
1150 if m.typ.method != METHOD_BINDING
1151 || !(m.typ.class == CLASS_SUCCESS_RESPONSE
1152 || m.typ.class == CLASS_REQUEST
1153 || m.typ.class == CLASS_INDICATION)
1154 {
1155 trace!(
1156 "[{}]: unhandled STUN from {} to {} class({}) method({})",
1157 self.get_name(),
1158 remote_addr,
1159 self.local_candidates[local_index],
1160 m.typ.class,
1161 m.typ.method
1162 );
1163 return Err(Error::ErrUnhandledStunpacket);
1164 }
1165
1166 if self.is_controlling {
1168 if m.contains(ATTR_ICE_CONTROLLING) {
1169 let mut remote_controlling = crate::attributes::control::AttrControlling::default();
1171 if let Err(err) = remote_controlling.get_from(m) {
1172 warn!(
1173 "[{}]: Failed to get remote ICE-CONTROLLING attribute: {}",
1174 self.get_name(),
1175 err
1176 );
1177 return Err(err);
1178 }
1179
1180 debug!(
1181 "[{}]: Role conflict detected (both controlling), local tiebreaker: {}, remote tiebreaker: {}",
1182 self.get_name(),
1183 self.tie_breaker,
1184 remote_controlling.0
1185 );
1186
1187 if m.typ.class == CLASS_REQUEST {
1189 if let Some(remote_index) = self.find_remote_candidate(remote_addr) {
1191 self.send_role_conflict_error(m, local_index, remote_index);
1192 }
1193
1194 if self.tie_breaker < remote_controlling.0 {
1196 info!(
1197 "[{}]: Switching from controlling to controlled due to role conflict (smaller tiebreaker)",
1198 self.get_name()
1199 );
1200 self.switch_role();
1201 }
1202 }
1203 } else if m.contains(ATTR_USE_CANDIDATE) {
1205 debug!(
1206 "[{}]: useCandidate && a.isControlling == true",
1207 self.get_name(),
1208 );
1209 return Err(Error::ErrUnexpectedStunrequestMessage);
1210 }
1211 } else if m.contains(ATTR_ICE_CONTROLLED) {
1212 let mut remote_controlled = crate::attributes::control::AttrControlled::default();
1214 if let Err(err) = remote_controlled.get_from(m) {
1215 warn!(
1216 "[{}]: Failed to get remote ICE-CONTROLLED attribute: {}",
1217 self.get_name(),
1218 err
1219 );
1220 return Err(err);
1221 }
1222
1223 debug!(
1224 "[{}]: Role conflict detected (both controlled), local tiebreaker: {}, remote tiebreaker: {}",
1225 self.get_name(),
1226 self.tie_breaker,
1227 remote_controlled.0
1228 );
1229
1230 if m.typ.class == CLASS_REQUEST {
1232 if let Some(remote_index) = self.find_remote_candidate(remote_addr) {
1234 self.send_role_conflict_error(m, local_index, remote_index);
1235 }
1236
1237 if self.tie_breaker > remote_controlled.0 {
1239 info!(
1240 "[{}]: Switching from controlled to controlling due to role conflict (larger tiebreaker)",
1241 self.get_name()
1242 );
1243 self.switch_role();
1244 }
1245 }
1246 }
1248
1249 let Some(remote_credentials) = &self.ufrag_pwd.remote_credentials else {
1250 debug!(
1251 "[{}]: ufrag_pwd.remote_credentials.is_none",
1252 self.get_name(),
1253 );
1254 return Err(Error::ErrPasswordEmpty);
1255 };
1256
1257 let mut remote_candidate_index = self.find_remote_candidate(remote_addr);
1258 if m.typ.class == CLASS_SUCCESS_RESPONSE {
1259 if let Err(err) = assert_inbound_message_integrity(m, remote_credentials.pwd.as_bytes())
1260 {
1261 warn!(
1262 "[{}]: discard message from ({}), {}",
1263 self.get_name(),
1264 remote_addr,
1265 err
1266 );
1267 return Err(err);
1268 }
1269
1270 if let Some(remote_index) = &remote_candidate_index {
1271 self.handle_success_response(now, m, local_index, *remote_index, remote_addr);
1272 } else {
1273 warn!(
1274 "[{}]: discard success message from ({}), no such remote",
1275 self.get_name(),
1276 remote_addr
1277 );
1278 return Err(Error::ErrUnhandledStunpacket);
1279 }
1280 } else if m.typ.class == CLASS_REQUEST {
1281 {
1282 let username = self.ufrag_pwd.local_credentials.ufrag.clone()
1283 + ":"
1284 + remote_credentials.ufrag.as_str();
1285 if let Err(err) = assert_inbound_username(m, &username) {
1286 warn!(
1287 "[{}]: discard message from ({}), {}",
1288 self.get_name(),
1289 remote_addr,
1290 err
1291 );
1292 return Err(err);
1293 } else if let Err(err) = assert_inbound_message_integrity(
1294 m,
1295 self.ufrag_pwd.local_credentials.pwd.as_bytes(),
1296 ) {
1297 warn!(
1298 "[{}]: discard message from ({}), {}",
1299 self.get_name(),
1300 remote_addr,
1301 err
1302 );
1303 return Err(err);
1304 }
1305 }
1306
1307 if remote_candidate_index.is_none() {
1308 let network_type = self.local_candidates[local_index].network_type();
1310 let (ip, port) = (remote_addr.ip(), remote_addr.port());
1311
1312 let prflx_candidate_config = CandidatePeerReflexiveConfig {
1313 base_config: CandidateConfig {
1314 network: network_type.to_string(),
1315 address: ip.to_string(),
1316 port,
1317 component: self.local_candidates[local_index].component(),
1318 ..CandidateConfig::default()
1319 },
1320 rel_addr: "".to_owned(),
1321 rel_port: 0,
1322 };
1323
1324 match prflx_candidate_config.new_candidate_peer_reflexive() {
1325 Ok(prflx_candidate) => {
1326 if let Ok(added) = self.add_remote_candidate(prflx_candidate)
1327 && added
1328 {
1329 remote_candidate_index = self.find_remote_candidate(remote_addr);
1334 }
1335 }
1336 Err(err) => {
1337 error!(
1338 "[{}]: Failed to create new remote prflx candidate ({})",
1339 self.get_name(),
1340 err
1341 );
1342 return Err(err);
1343 }
1344 };
1345
1346 debug!(
1347 "[{}]: adding a new peer-reflexive candidate: {} ",
1348 self.get_name(),
1349 remote_addr
1350 );
1351 }
1352
1353 trace!(
1354 "[{}]: inbound STUN (Request) from {} to {}",
1355 self.get_name(),
1356 remote_addr,
1357 self.local_candidates[local_index]
1358 );
1359
1360 if let Some(remote_index) = &remote_candidate_index {
1361 self.handle_binding_request(m, local_index, *remote_index);
1362 }
1363 }
1364
1365 if let Some(remote_index) = remote_candidate_index {
1366 self.remote_candidates[remote_index].seen(false);
1367 }
1368
1369 Ok(())
1370 }
1371
1372 pub(crate) fn validate_non_stun_traffic(&mut self, remote_addr: SocketAddr) -> bool {
1375 self.find_remote_candidate(remote_addr)
1376 .is_some_and(|remote_index| {
1377 self.remote_candidates[remote_index].seen(false);
1378 true
1379 })
1380 }
1381
1382 pub(crate) fn send_stun(&mut self, msg: &Message, local_index: usize, remote_index: usize) {
1383 let peer_addr = self.remote_candidates[remote_index].addr();
1384 let local_addr = self.local_candidates[local_index].addr();
1385 let transport_protocol = if self.local_candidates[local_index].network_type().is_tcp() {
1386 TransportProtocol::TCP
1387 } else {
1388 TransportProtocol::UDP
1389 };
1390
1391 self.write_outs.push_back(TaggedBytesMut {
1392 now: Instant::now(),
1393 transport: TransportContext {
1394 local_addr,
1395 peer_addr,
1396 ecn: None,
1397 transport_protocol,
1398 },
1399 message: BytesMut::from(&msg.raw[..]),
1400 });
1401
1402 self.local_candidates[local_index].seen(true);
1403 }
1404
1405 fn handle_inbound_candidate_msg(
1406 &mut self,
1407 local_index: usize,
1408 msg: TaggedBytesMut,
1409 ) -> Result<()> {
1410 if is_stun_message(&msg.message) {
1411 let mut m = Message {
1412 raw: msg.message.to_vec(),
1413 ..Message::default()
1414 };
1415
1416 if let Err(err) = m.decode() {
1417 warn!(
1418 "[{}]: Failed to handle decode ICE from {} to {}: {}",
1419 self.get_name(),
1420 msg.transport.local_addr,
1421 msg.transport.peer_addr,
1422 err
1423 );
1424 Err(err)
1425 } else {
1426 self.handle_inbound(msg.now, &mut m, local_index, msg.transport.peer_addr)
1427 }
1428 } else {
1429 if !self.validate_non_stun_traffic(msg.transport.peer_addr) {
1430 warn!(
1431 "[{}]: Discarded message, not a valid remote candidate from {}",
1432 self.get_name(),
1433 msg.transport.peer_addr,
1434 );
1435 } else {
1436 warn!(
1437 "[{}]: non-STUN traffic message from a valid remote candidate from {}",
1438 self.get_name(),
1439 msg.transport.peer_addr
1440 );
1441 }
1442 Err(Error::ErrNonStunmessage)
1443 }
1444 }
1445
1446 pub(crate) fn get_name(&self) -> &str {
1447 if self.is_controlling {
1448 "controlling"
1449 } else {
1450 "controlled"
1451 }
1452 }
1453
1454 pub(crate) fn get_selected_pair(&self) -> Option<usize> {
1455 self.selected_pair
1456 }
1457
1458 pub(crate) fn get_best_available_pair(&self) -> Option<usize> {
1459 let mut best_pair_index: Option<usize> = None;
1460
1461 for (index, p) in self.candidate_pairs.iter().enumerate() {
1462 if p.state == CandidatePairState::Failed {
1463 continue;
1464 }
1465
1466 if let Some(pair_index) = &mut best_pair_index {
1467 let b = &self.candidate_pairs[*pair_index];
1468 if b.priority() < p.priority() {
1469 *pair_index = index;
1470 }
1471 } else {
1472 best_pair_index = Some(index);
1473 }
1474 }
1475
1476 best_pair_index
1477 }
1478
1479 pub(crate) fn get_best_valid_candidate_pair(&self) -> Option<usize> {
1480 let mut best_pair_index: Option<usize> = None;
1481
1482 for (index, p) in self.candidate_pairs.iter().enumerate() {
1483 if p.state != CandidatePairState::Succeeded {
1484 continue;
1485 }
1486
1487 if let Some(pair_index) = &mut best_pair_index {
1488 let b = &self.candidate_pairs[*pair_index];
1489 if b.priority() < p.priority() {
1490 *pair_index = index;
1491 }
1492 } else {
1493 best_pair_index = Some(index);
1494 }
1495 }
1496
1497 best_pair_index
1498 }
1499}