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