Skip to main content

rtc_ice/agent/
mod.rs

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    /// Emitted when the ICE role switches due to a role conflict (RFC 8445 ยง7.3.1.1).
94    /// The bool is `true` if the agent is now controlling, `false` if now controlled.
95    RoleChange(bool),
96}
97
98/// Represents the ICE agent.
99pub 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) started_ch_tx: Mutex<Option<broadcast::Sender<()>>>,
110    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    // LRU of outbound Binding request Transaction IDs
119    pub(crate) pending_binding_requests: Vec<BindingRequest>,
120
121    // the following variables won't be changed after init_with_defaults()
122    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    // How long connectivity checks can fail before the ICE Agent
129    // goes to disconnected
130    pub(crate) disconnected_timeout: Duration,
131    // How long connectivity checks can fail before the ICE Agent
132    // goes to failed
133    pub(crate) failed_timeout: Duration,
134    // How often should we send keepalive packets?
135    // 0 means never
136    pub(crate) keepalive_interval: Duration,
137    // When the last STUN consent ping was sent.
138    pub(crate) last_consent_sent: Instant,
139    // How often should we run our internal taskLoop to check for state changes when connecting
140    pub(crate) check_interval: Duration,
141    pub(crate) checking_duration: Instant,
142    pub(crate) last_checking_time: Instant,
143    // When set, a connectivity check has been requested and must be run on the next
144    // `handle_timeout`. Checks are deferred (rather than run inline) so that adding a
145    // candidate can never re-enter `contact()` and mutate agent state - e.g. transition
146    // to `Failed` and drop candidates - while a caller still holds indices into the
147    // candidate vectors. See issue #88.
148    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    /// Creates a new Agent.
211    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            // Opportunistic mDNS: If we can't open the connection, that's ok: we
230            // can continue without it.
231            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            //started_ch_tx: MuteSome(started_ch_tx)),
269
270            //won't change after init_with_defaults()
271            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            // How long connectivity checks can fail before the ICE Agent
306            // goes to disconnected
307            disconnected_timeout: if let Some(disconnected_timeout) = config.disconnected_timeout {
308                disconnected_timeout
309            } else {
310                DEFAULT_DISCONNECTED_TIMEOUT
311            },
312
313            // How long connectivity checks can fail before the ICE Agent
314            // goes to failed
315            failed_timeout: if let Some(failed_timeout) = config.failed_timeout {
316                failed_timeout
317            } else {
318                DEFAULT_FAILED_TIMEOUT
319            },
320
321            // How often should we send keepalive packets?
322            // 0 means never
323            keepalive_interval: if let Some(keepalive_interval) = config.keepalive_interval {
324                keepalive_interval
325            } else {
326                DEFAULT_KEEPALIVE_INTERVAL
327            },
328
329            // How often should we run our internal taskLoop to check for state changes when connecting
330            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            // LRU of outbound Binding request Transaction IDs
354            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        // Restart is also used to initialize the agent for the first time
365        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    /// Adds a new local candidate.
375    pub fn add_local_candidate(&mut self, mut c: Candidate) -> Result<bool> {
376        // Filter by network type if network_types is configured
377        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        // Filter by candidate type if candidate_types is configured.
389        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            // only one .local mDNS host candidate per IPv4 is supported
406            // when registered local ip matches, use mdns_local_name to hide local host ip
407            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    /// Adds a new remote candidate.
437    pub fn add_remote_candidate(&mut self, c: Candidate) -> Result<bool> {
438        // Filter by network type if network_types is configured
439        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        // TCP active candidates don't have a listening port - they initiate connections.
451        // The remote active side will probe our passive candidates, so we don't need
452        // to do anything with remote active candidates.
453        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 we have a mDNS Candidate lets fully resolve it before adding it locally
462        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    /// Sets the credentials of the remote agent.
507    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    /// Returns the remote credentials.
527    pub fn get_remote_credentials(&self) -> Option<&Credentials> {
528        self.ufrag_pwd.remote_credentials.as_ref()
529    }
530
531    /// Returns the local credentials.
532    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                // While connecting, check candidates more frequently
572                update_interval(check_interval);
573            }
574            ConnectionState::Connected | ConnectionState::Disconnected => {
575                update_interval(keepalive_interval);
576            }
577            _ => {}
578        };
579        // Ensure we run our task loop as quickly as the minimum of our various configured timeouts
580        update_interval(disconnected_timeout);
581        update_interval(failed_timeout);
582        interval
583    }
584
585    /// Returns the selected pair (local_candidate, remote_candidate) or none
586    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    /// start connectivity checks
611    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    /// Restarts the ICE Agent with the provided ufrag/pwd
632    /// If no ufrag/pwd is provided the Agent will generate one itself.
633    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        // Clear all agent needed to take back to fresh state
654        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        // Restart is used by NewAgent. Accept/Connect should be used to move to checking
667        // for new Agents
668        if self.connection_state != ConnectionState::New {
669            self.update_connection_state(ConnectionState::Checking);
670        }
671
672        Ok(())
673    }
674
675    /// Returns the local candidates.
676    pub fn get_local_candidates(&self) -> &[Candidate] {
677        &self.local_candidates
678    }
679
680    fn contact(&mut self, now: Instant) {
681        // Consume any pending deferred-check request now that we are running one.
682        // Reset before the early returns below so a failed/settled agent does not
683        // keep asking `poll_timeout` for an immediate wake-up.
684        self.force_candidate_contact = false;
685
686        if self.connection_state == ConnectionState::Failed {
687            // The connection is currently failed so don't send any checks
688            // In the future it may be restarted though
689            self.last_connection_state = self.connection_state;
690            return;
691        }
692        if self.connection_state == ConnectionState::Checking {
693            // We have just entered checking for the first time so update our checking timer
694            if self.last_connection_state != self.connection_state {
695                self.checking_duration = now;
696            }
697
698            // We have been in checking longer then Disconnect+Failed timeout, set the connection to Failed
699            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            // Connection has gone to failed, release all gathered candidates
719            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            // Notify when the selected pair changes
749            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    /// Checks if the selected pair is (still) valid.
828    /// Note: the caller should hold the agent lock.
829    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            // Only allow transitions to fail if a.failedTimeout is non-zero
845            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    /// Sends STUN Binding Requests to the selected pair at `keepalive_interval` to
867    /// maintain consent freshness (RFC 7675).
868    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        // Defer the connectivity check to `handle_timeout` instead of running it
891        // inline. Running `contact()` here is re-entrant: it can advance the state
892        // to `Failed`, which calls `delete_all_candidates()` and wipes the candidate
893        // and pair vectors while a caller still holds indices into them (for example
894        // `handle_inbound` while adding a peer-reflexive candidate). See issue #88.
895        self.force_candidate_contact = true;
896    }
897
898    /// Remove all candidates.
899    /// This closes any listening sockets and removes both the local and remote candidate lists.
900    ///
901    /// This is used for restarts, failures and on close.
902    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        // Candidate pairs reference candidates by index, so once the candidates are
909        // removed every pair - and the `selected_pair`/`nominated_pair` indices into
910        // the pair list - is dangling and must be dropped to avoid out-of-bounds
911        // access. `remote_candidates` is always cleared here, so no pair can remain
912        // valid even when the local candidates are kept. See issue #88.
913        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            // For TCP active candidates, match by IP only (ignore port).
938            // TCP active candidates use port 9 as placeholder in signaling,
939            // but the actual connection uses an ephemeral port.
940            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        // Track request sent on the candidate pair
979        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            // Track response sent on the candidate pair
1018            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    /// Sends a 487 (Role Conflict) error response.
1026    /// RFC 8445 Section 7.3.1.1
1027    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    /// Switches the ICE agent role and recomputes all candidate pair priorities.
1069    /// RFC 8445 Section 7.3.1.1
1070    pub(crate) fn switch_role(&mut self) {
1071        self.is_controlling = !self.is_controlling;
1072
1073        // Recompute priorities for all candidate pairs
1074        // The priority calculation depends on ice_role_controlling
1075        for pair in &mut self.candidate_pairs {
1076            pair.ice_role_controlling = self.is_controlling;
1077        }
1078
1079        // Clear nominated pair when switching roles
1080        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    /// Removes pending binding requests that are over `maxBindingRequestTimeout` old Let HTO be the
1093    /// transaction timeout, which SHOULD be 2*RTT if RTT is known or 500 ms otherwise.
1094    ///
1095    /// reference: (IETF ref-8445)[https://tools.ietf.org/html/rfc8445#appendix-B.1].
1096    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    /// Assert that the passed `TransactionID` is in our `pendingBindingRequests` and returns the
1125    /// destination, If the bindingRequest was valid remove it from our pending cache.
1126    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    /// Processes STUN traffic from a remote candidate.
1143    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        // RFC 8445 Section 7.3.1.1 - Detecting and Repairing Role Conflicts
1167        if self.is_controlling {
1168            if m.contains(ATTR_ICE_CONTROLLING) {
1169                // Both agents are controlling - role conflict detected
1170                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                // Only process if this is a request (not a response)
1188                if m.typ.class == CLASS_REQUEST {
1189                    // Send 487 Role Conflict error
1190                    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                    // Compare tiebreakers - if ours is smaller, we switch to controlled
1195                    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                // Continue processing the message after handling role conflict
1204            } 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            // Both agents are controlled - role conflict detected
1213            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            // Only process if this is a request (not a response)
1231            if m.typ.class == CLASS_REQUEST {
1232                // Send 487 Role Conflict error
1233                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                // Compare tiebreakers - if ours is larger, we switch to controlling
1238                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            // Continue processing the message after handling role conflict
1247        }
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                // Use the local candidate's network type for the peer-reflexive candidate
1309                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                            // Look the candidate up by address rather than assuming it
1330                            // is the last element: `add_remote_candidate` may not have
1331                            // appended it (e.g. a duplicate), and this stays correct if
1332                            // the vector is ever mutated underneath us. See issue #88.
1333                            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    // Processes non STUN traffic from a remote candidate, and returns true if it is an actual
1373    // remote candidate.
1374    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}