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
144    pub(crate) mdns: Option<Mdns>,
145    pub(crate) mdns_queries: HashMap<QueryId, Candidate>,
146
147    pub(crate) mdns_mode: MulticastDnsMode,
148    pub(crate) mdns_local_name: String,
149    pub(crate) mdns_local_ip: Option<IpAddr>,
150
151    pub(crate) candidate_types: Vec<CandidateType>,
152    pub(crate) network_types: Vec<NetworkType>,
153    pub(crate) urls: Vec<Url>,
154
155    pub(crate) write_outs: VecDeque<TaggedBytesMut>,
156    pub(crate) event_outs: VecDeque<Event>,
157}
158
159impl Default for Agent {
160    fn default() -> Self {
161        Self {
162            tie_breaker: 0,
163            is_controlling: false,
164            lite: false,
165            start_time: Instant::now(),
166            connection_state: Default::default(),
167            last_connection_state: Default::default(),
168            ufrag_pwd: Default::default(),
169            local_candidates: vec![],
170            remote_candidates: vec![],
171            candidate_pairs: vec![],
172            nominated_pair: None,
173            selected_pair: None,
174            pending_binding_requests: vec![],
175            insecure_skip_verify: false,
176            max_binding_requests: 0,
177            host_acceptance_min_wait: Default::default(),
178            srflx_acceptance_min_wait: Default::default(),
179            prflx_acceptance_min_wait: Default::default(),
180            relay_acceptance_min_wait: Default::default(),
181            disconnected_timeout: Default::default(),
182            failed_timeout: Default::default(),
183            keepalive_interval: Default::default(),
184            last_consent_sent: Instant::now(),
185            check_interval: Default::default(),
186            checking_duration: Instant::now(),
187            last_checking_time: Instant::now(),
188            mdns_mode: MulticastDnsMode::Disabled,
189            mdns_local_name: "".to_owned(),
190            mdns_local_ip: None,
191            mdns_queries: HashMap::new(),
192            mdns: None,
193            candidate_types: vec![],
194            network_types: vec![],
195            urls: vec![],
196            write_outs: Default::default(),
197            event_outs: Default::default(),
198        }
199    }
200}
201
202impl Agent {
203    /// Creates a new Agent.
204    pub fn new(config: Arc<AgentConfig>) -> Result<Self> {
205        let mut mdns_local_name = config.multicast_dns_local_name.clone();
206        if mdns_local_name.is_empty() {
207            mdns_local_name = generate_multicast_dns_name();
208        }
209
210        if !mdns_local_name.ends_with(".local") || mdns_local_name.split('.').count() != 2 {
211            return Err(Error::ErrInvalidMulticastDnshostName);
212        }
213
214        let mdns_mode = config.multicast_dns_mode;
215        let mdns = create_multicast_dns(
216            mdns_mode,
217            &mdns_local_name,
218            &config.multicast_dns_local_ip,
219            &config.multicast_dns_query_timeout,
220        )
221        .unwrap_or_else(|err| {
222            // Opportunistic mDNS: If we can't open the connection, that's ok: we
223            // can continue without it.
224            warn!("Failed to initialize mDNS {mdns_local_name}: {err}");
225            None
226        });
227
228        let candidate_types = if config.candidate_types.is_empty() {
229            default_candidate_types()
230        } else {
231            config.candidate_types.clone()
232        };
233
234        if config.lite && (candidate_types.len() != 1 || candidate_types[0] != CandidateType::Host)
235        {
236            return Err(Error::ErrLiteUsingNonHostCandidates);
237        }
238
239        if !config.urls.is_empty()
240            && !contains_candidate_type(CandidateType::ServerReflexive, &candidate_types)
241            && !contains_candidate_type(CandidateType::Relay, &candidate_types)
242        {
243            return Err(Error::ErrUselessUrlsProvided);
244        }
245
246        let mut agent = Self {
247            tie_breaker: rand::random::<u64>(),
248            is_controlling: config.is_controlling,
249            lite: config.lite,
250
251            start_time: Instant::now(),
252
253            nominated_pair: None,
254            selected_pair: None,
255            candidate_pairs: vec![],
256
257            connection_state: ConnectionState::New,
258
259            insecure_skip_verify: config.insecure_skip_verify,
260
261            //started_ch_tx: MuteSome(started_ch_tx)),
262
263            //won't change after init_with_defaults()
264            max_binding_requests: if let Some(max_binding_requests) = config.max_binding_requests {
265                max_binding_requests
266            } else {
267                DEFAULT_MAX_BINDING_REQUESTS
268            },
269            host_acceptance_min_wait: if let Some(host_acceptance_min_wait) =
270                config.host_acceptance_min_wait
271            {
272                host_acceptance_min_wait
273            } else {
274                DEFAULT_HOST_ACCEPTANCE_MIN_WAIT
275            },
276            srflx_acceptance_min_wait: if let Some(srflx_acceptance_min_wait) =
277                config.srflx_acceptance_min_wait
278            {
279                srflx_acceptance_min_wait
280            } else {
281                DEFAULT_SRFLX_ACCEPTANCE_MIN_WAIT
282            },
283            prflx_acceptance_min_wait: if let Some(prflx_acceptance_min_wait) =
284                config.prflx_acceptance_min_wait
285            {
286                prflx_acceptance_min_wait
287            } else {
288                DEFAULT_PRFLX_ACCEPTANCE_MIN_WAIT
289            },
290            relay_acceptance_min_wait: if let Some(relay_acceptance_min_wait) =
291                config.relay_acceptance_min_wait
292            {
293                relay_acceptance_min_wait
294            } else {
295                DEFAULT_RELAY_ACCEPTANCE_MIN_WAIT
296            },
297
298            // How long connectivity checks can fail before the ICE Agent
299            // goes to disconnected
300            disconnected_timeout: if let Some(disconnected_timeout) = config.disconnected_timeout {
301                disconnected_timeout
302            } else {
303                DEFAULT_DISCONNECTED_TIMEOUT
304            },
305
306            // How long connectivity checks can fail before the ICE Agent
307            // goes to failed
308            failed_timeout: if let Some(failed_timeout) = config.failed_timeout {
309                failed_timeout
310            } else {
311                DEFAULT_FAILED_TIMEOUT
312            },
313
314            // How often should we send keepalive packets?
315            // 0 means never
316            keepalive_interval: if let Some(keepalive_interval) = config.keepalive_interval {
317                keepalive_interval
318            } else {
319                DEFAULT_KEEPALIVE_INTERVAL
320            },
321
322            // How often should we run our internal taskLoop to check for state changes when connecting
323            check_interval: if config.check_interval == Duration::from_secs(0) {
324                DEFAULT_CHECK_INTERVAL
325            } else {
326                config.check_interval
327            },
328            last_consent_sent: Instant::now(),
329            checking_duration: Instant::now(),
330            last_checking_time: Instant::now(),
331            last_connection_state: ConnectionState::Unspecified,
332
333            mdns,
334            mdns_queries: HashMap::new(),
335
336            mdns_mode,
337            mdns_local_name,
338            mdns_local_ip: config.multicast_dns_local_ip,
339
340            ufrag_pwd: UfragPwd::default(),
341
342            local_candidates: vec![],
343            remote_candidates: vec![],
344
345            // LRU of outbound Binding request Transaction IDs
346            pending_binding_requests: vec![],
347
348            candidate_types,
349            network_types: config.network_types.clone(),
350            urls: config.urls.clone(),
351
352            write_outs: VecDeque::new(),
353            event_outs: VecDeque::new(),
354        };
355
356        // Restart is also used to initialize the agent for the first time
357        if let Err(err) = agent.restart(config.local_ufrag.clone(), config.local_pwd.clone(), false)
358        {
359            let _ = agent.close();
360            return Err(err);
361        }
362
363        Ok(agent)
364    }
365
366    /// Adds a new local candidate.
367    pub fn add_local_candidate(&mut self, mut c: Candidate) -> Result<bool> {
368        // Filter by network type if network_types is configured
369        if !self.network_types.is_empty() {
370            let candidate_network_type = c.network_type();
371            if !self.network_types.contains(&candidate_network_type) {
372                debug!(
373                    "Ignoring local candidate with network type {:?} (not in configured network types: {:?})",
374                    candidate_network_type, self.network_types
375                );
376                return Ok(false);
377            }
378        }
379
380        // Filter by candidate type if candidate_types is configured.
381        let candidate_type = c.candidate_type();
382        if !self.candidate_types.is_empty() && !self.candidate_types.contains(&candidate_type) {
383            debug!(
384                "Ignoring local candidate with type {:?} (not in configured candidate types: {:?})",
385                candidate_type, self.candidate_types
386            );
387            return Ok(false);
388        }
389
390        if c.candidate_type() == CandidateType::Host
391            && self.mdns_mode == MulticastDnsMode::QueryAndGather
392            && c.network_type == NetworkType::Udp4
393            && self
394                .mdns_local_ip
395                .is_some_and(|local_ip| local_ip == c.addr().ip())
396        {
397            // only one .local mDNS host candidate per IPv4 is supported
398            // when registered local ip matches, use mdns_local_name to hide local host ip
399            trace!(
400                "mDNS hides local ip {} with local name {}",
401                c.address, self.mdns_local_name
402            );
403            c.address = self.mdns_local_name.clone();
404        }
405
406        for cand in &self.local_candidates {
407            if cand.equal(&c) {
408                return Ok(false);
409            }
410        }
411
412        self.local_candidates.push(c);
413        let local_index = self.local_candidates.len() - 1;
414        let local_tcp_type = self.local_candidates[local_index].tcp_type();
415
416        for remote_index in 0..self.remote_candidates.len() {
417            let remote_tcp_type = self.remote_candidates[remote_index].tcp_type();
418
419            // TCP type pairing rules (RFC 6544):
420            // - Active can only pair with Passive
421            // - Passive can only pair with Active
422            // - SimultaneousOpen can pair with SimultaneousOpen
423            // - Unspecified (UDP) can pair with Unspecified
424            let should_pair = match (local_tcp_type, remote_tcp_type) {
425                (TcpType::Active, TcpType::Passive) => true,
426                (TcpType::Passive, TcpType::Active) => true,
427                (TcpType::SimultaneousOpen, TcpType::SimultaneousOpen) => true,
428                (TcpType::Unspecified, TcpType::Unspecified) => true, // UDP candidates
429                _ => false,
430            };
431
432            if should_pair {
433                self.add_pair(local_index, remote_index);
434            }
435        }
436
437        self.request_connectivity_check();
438
439        Ok(true)
440    }
441
442    /// Adds a new remote candidate.
443    pub fn add_remote_candidate(&mut self, c: Candidate) -> Result<bool> {
444        // Filter by network type if network_types is configured
445        if !self.network_types.is_empty() {
446            let candidate_network_type = c.network_type();
447            if !self.network_types.contains(&candidate_network_type) {
448                debug!(
449                    "Ignoring remote candidate with network type {:?} (not in configured network types: {:?})",
450                    candidate_network_type, self.network_types
451                );
452                return Ok(false);
453            }
454        }
455
456        // TCP active candidates don't have a listening port - they initiate connections.
457        // The remote active side will probe our passive candidates, so we don't need
458        // to do anything with remote active candidates.
459        if c.tcp_type() == TcpType::Active {
460            debug!(
461                "Ignoring remote candidate with tcptype active: {}",
462                c.address()
463            );
464            return Ok(false);
465        }
466
467        // If we have a mDNS Candidate lets fully resolve it before adding it locally
468        if c.candidate_type() == CandidateType::Host && c.address().ends_with(".local") {
469            if self.mdns_mode == MulticastDnsMode::Disabled {
470                warn!(
471                    "remote mDNS candidate added, but mDNS is disabled: ({})",
472                    c.address()
473                );
474                return Ok(false);
475            }
476
477            if c.candidate_type() != CandidateType::Host {
478                return Err(Error::ErrAddressParseFailed);
479            }
480
481            if let Some(mdns_conn) = &mut self.mdns {
482                let query_id = mdns_conn.query(c.address());
483                self.mdns_queries.insert(query_id, c);
484            }
485
486            return Ok(false);
487        }
488
489        self.trigger_request_connectivity_check(vec![c]);
490        Ok(true)
491    }
492
493    fn trigger_request_connectivity_check(&mut self, remote_candidates: Vec<Candidate>) {
494        for c in remote_candidates {
495            if !self.remote_candidates.iter().any(|cand| cand.equal(&c)) {
496                let remote_tcp_type = c.tcp_type();
497                self.remote_candidates.push(c);
498                let remote_index = self.remote_candidates.len() - 1;
499
500                // Apply TCP type pairing rules (RFC 6544)
501                for local_index in 0..self.local_candidates.len() {
502                    let local_tcp_type = self.local_candidates[local_index].tcp_type();
503
504                    // TCP type pairing rules:
505                    // - Active can only pair with Passive
506                    // - Passive can only pair with Active
507                    // - SimultaneousOpen can pair with SimultaneousOpen
508                    // - Unspecified (UDP) can pair with Unspecified
509                    let should_pair = match (local_tcp_type, remote_tcp_type) {
510                        (TcpType::Active, TcpType::Passive) => true,
511                        (TcpType::Passive, TcpType::Active) => true,
512                        (TcpType::SimultaneousOpen, TcpType::SimultaneousOpen) => true,
513                        (TcpType::Unspecified, TcpType::Unspecified) => true, // UDP candidates
514                        _ => false,
515                    };
516
517                    if should_pair {
518                        self.add_pair(local_index, remote_index);
519                    }
520                }
521
522                self.request_connectivity_check();
523            }
524        }
525    }
526
527    /// Sets the credentials of the remote agent.
528    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    /// Returns the remote credentials.
548    pub fn get_remote_credentials(&self) -> Option<&Credentials> {
549        self.ufrag_pwd.remote_credentials.as_ref()
550    }
551
552    /// Returns the local credentials.
553    pub fn get_local_credentials(&self) -> &Credentials {
554        &self.ufrag_pwd.local_credentials
555    }
556
557    pub fn role(&self) -> bool {
558        self.is_controlling
559    }
560
561    pub fn set_role(&mut self, is_controlling: bool) {
562        self.is_controlling = is_controlling;
563    }
564
565    pub fn state(&self) -> ConnectionState {
566        self.connection_state
567    }
568
569    pub fn is_valid_non_stun_traffic(&mut self, transport: TransportContext) -> bool {
570        self.find_local_candidate(transport.local_addr, transport.transport_protocol)
571            .is_some()
572            && self.validate_non_stun_traffic(transport.peer_addr)
573    }
574
575    fn get_timeout_interval(&self) -> Duration {
576        let (check_interval, keepalive_interval, disconnected_timeout, failed_timeout) = (
577            self.check_interval,
578            self.keepalive_interval,
579            self.disconnected_timeout,
580            self.failed_timeout,
581        );
582        let mut interval = DEFAULT_CHECK_INTERVAL;
583
584        let mut update_interval = |x: Duration| {
585            if x != ZERO_DURATION && (interval == ZERO_DURATION || interval > x) {
586                interval = x;
587            }
588        };
589
590        match self.last_connection_state {
591            ConnectionState::New | ConnectionState::Checking => {
592                // While connecting, check candidates more frequently
593                update_interval(check_interval);
594            }
595            ConnectionState::Connected | ConnectionState::Disconnected => {
596                update_interval(keepalive_interval);
597            }
598            _ => {}
599        };
600        // Ensure we run our task loop as quickly as the minimum of our various configured timeouts
601        update_interval(disconnected_timeout);
602        update_interval(failed_timeout);
603        interval
604    }
605
606    /// Returns the selected pair (local_candidate, remote_candidate) or none
607    pub fn get_selected_candidate_pair(&self) -> Option<(&Candidate, &Candidate)> {
608        if let Some(pair_index) = self.get_selected_pair() {
609            let candidate_pair = &self.candidate_pairs[pair_index];
610            Some((
611                &self.local_candidates[candidate_pair.local_index],
612                &self.remote_candidates[candidate_pair.remote_index],
613            ))
614        } else {
615            None
616        }
617    }
618
619    pub fn get_best_available_candidate_pair(&self) -> Option<(&Candidate, &Candidate)> {
620        if let Some(pair_index) = self.get_best_available_pair() {
621            let candidate_pair = &self.candidate_pairs[pair_index];
622            Some((
623                &self.local_candidates[candidate_pair.local_index],
624                &self.remote_candidates[candidate_pair.remote_index],
625            ))
626        } else {
627            None
628        }
629    }
630
631    /// start connectivity checks
632    pub fn start_connectivity_checks(
633        &mut self,
634        is_controlling: bool,
635        remote_ufrag: String,
636        remote_pwd: String,
637    ) -> Result<()> {
638        debug!(
639            "Started agent: isControlling? {}, remoteUfrag: {}, remotePwd: {}",
640            is_controlling, remote_ufrag, remote_pwd
641        );
642        self.set_remote_credentials(remote_ufrag, remote_pwd)?;
643        self.is_controlling = is_controlling;
644        self.start();
645
646        self.update_connection_state(ConnectionState::Checking);
647        self.request_connectivity_check();
648
649        Ok(())
650    }
651
652    /// Restarts the ICE Agent with the provided ufrag/pwd
653    /// If no ufrag/pwd is provided the Agent will generate one itself.
654    pub fn restart(
655        &mut self,
656        mut ufrag: String,
657        mut pwd: String,
658        keep_local_candidates: bool,
659    ) -> Result<()> {
660        if ufrag.is_empty() {
661            ufrag = generate_ufrag();
662        }
663        if pwd.is_empty() {
664            pwd = generate_pwd();
665        }
666
667        if ufrag.len() * 8 < 24 {
668            return Err(Error::ErrLocalUfragInsufficientBits);
669        }
670        if pwd.len() * 8 < 128 {
671            return Err(Error::ErrLocalPwdInsufficientBits);
672        }
673
674        // Clear all agent needed to take back to fresh state
675        self.ufrag_pwd.local_credentials.ufrag = ufrag;
676        self.ufrag_pwd.local_credentials.pwd = pwd;
677        self.ufrag_pwd.remote_credentials = None;
678
679        self.pending_binding_requests = vec![];
680
681        self.candidate_pairs = vec![];
682
683        self.set_selected_pair(None);
684        self.delete_all_candidates(keep_local_candidates);
685        self.start();
686
687        // Restart is used by NewAgent. Accept/Connect should be used to move to checking
688        // for new Agents
689        if self.connection_state != ConnectionState::New {
690            self.update_connection_state(ConnectionState::Checking);
691        }
692
693        Ok(())
694    }
695
696    /// Returns the local candidates.
697    pub fn get_local_candidates(&self) -> &[Candidate] {
698        &self.local_candidates
699    }
700
701    fn contact(&mut self, now: Instant) {
702        if self.connection_state == ConnectionState::Failed {
703            // The connection is currently failed so don't send any checks
704            // In the future it may be restarted though
705            self.last_connection_state = self.connection_state;
706            return;
707        }
708        if self.connection_state == ConnectionState::Checking {
709            // We have just entered checking for the first time so update our checking timer
710            if self.last_connection_state != self.connection_state {
711                self.checking_duration = now;
712            }
713
714            // We have been in checking longer then Disconnect+Failed timeout, set the connection to Failed
715            if now
716                .checked_duration_since(self.checking_duration)
717                .unwrap_or_else(|| Duration::from_secs(0))
718                > self.disconnected_timeout + self.failed_timeout
719            {
720                self.update_connection_state(ConnectionState::Failed);
721                self.last_connection_state = self.connection_state;
722                return;
723            }
724        }
725
726        self.contact_candidates();
727
728        self.last_connection_state = self.connection_state;
729        self.last_checking_time = now;
730    }
731
732    pub(crate) fn update_connection_state(&mut self, new_state: ConnectionState) {
733        if self.connection_state != new_state {
734            // Connection has gone to failed, release all gathered candidates
735            if new_state == ConnectionState::Failed {
736                self.set_selected_pair(None);
737                self.delete_all_candidates(false);
738            }
739
740            info!(
741                "[{}]: Setting new connection state: {}",
742                self.get_name(),
743                new_state
744            );
745            self.connection_state = new_state;
746            self.event_outs
747                .push_back(Event::ConnectionStateChange(new_state));
748        }
749    }
750
751    pub(crate) fn set_selected_pair(&mut self, selected_pair: Option<usize>) {
752        if let Some(pair_index) = selected_pair {
753            trace!(
754                "[{}]: Set selected candidate pair: {:?}",
755                self.get_name(),
756                self.candidate_pairs[pair_index]
757            );
758
759            self.candidate_pairs[pair_index].nominated = true;
760            self.selected_pair = Some(pair_index);
761
762            self.update_connection_state(ConnectionState::Connected);
763
764            // Notify when the selected pair changes
765            let candidate_pair = &self.candidate_pairs[pair_index];
766            self.event_outs
767                .push_back(Event::SelectedCandidatePairChange(
768                    Box::new(self.local_candidates[candidate_pair.local_index].clone()),
769                    Box::new(self.remote_candidates[candidate_pair.remote_index].clone()),
770                ));
771        } else {
772            self.selected_pair = None;
773        }
774    }
775
776    pub(crate) fn ping_all_candidates(&mut self) {
777        let mut pairs: Vec<(usize, usize)> = vec![];
778
779        let name = self.get_name().to_string();
780        if self.candidate_pairs.is_empty() {
781            warn!(
782                "[{}]: pingAllCandidates called with no candidate pairs. Connection is not possible yet.",
783                name,
784            );
785        }
786        for p in &mut self.candidate_pairs {
787            if p.state == CandidatePairState::Waiting {
788                p.state = CandidatePairState::InProgress;
789            } else if p.state != CandidatePairState::InProgress {
790                continue;
791            }
792
793            if p.binding_request_count > self.max_binding_requests {
794                trace!(
795                    "[{}]: max requests reached for pair {} (local_addr {} <-> remote_addr {}), marking it as failed",
796                    name,
797                    *p,
798                    self.local_candidates[p.local_index].addr(),
799                    self.remote_candidates[p.remote_index].addr()
800                );
801                p.state = CandidatePairState::Failed;
802            } else {
803                p.binding_request_count += 1;
804                let local = p.local_index;
805                let remote = p.remote_index;
806                pairs.push((local, remote));
807            }
808        }
809
810        if !pairs.is_empty() {
811            trace!(
812                "[{}]: pinging all {} candidates",
813                self.get_name(),
814                pairs.len()
815            );
816        }
817
818        for (local, remote) in pairs {
819            self.ping_candidate(local, remote);
820        }
821    }
822
823    pub(crate) fn add_pair(&mut self, local_index: usize, remote_index: usize) {
824        let p = CandidatePair::new(
825            local_index,
826            remote_index,
827            self.local_candidates[local_index].priority(),
828            self.remote_candidates[remote_index].priority(),
829            self.is_controlling,
830        );
831        self.candidate_pairs.push(p);
832    }
833
834    pub(crate) fn find_pair(&self, local_index: usize, remote_index: usize) -> Option<usize> {
835        for (index, p) in self.candidate_pairs.iter().enumerate() {
836            if p.local_index == local_index && p.remote_index == remote_index {
837                return Some(index);
838            }
839        }
840        None
841    }
842
843    /// Checks if the selected pair is (still) valid.
844    /// Note: the caller should hold the agent lock.
845    pub(crate) fn validate_selected_pair(&mut self) -> bool {
846        let (valid, disconnected_time) = {
847            self.selected_pair.as_ref().map_or_else(
848                || (false, Duration::from_secs(0)),
849                |&pair_index| {
850                    let remote_index = self.candidate_pairs[pair_index].remote_index;
851
852                    let disconnected_time = Instant::now()
853                        .duration_since(self.remote_candidates[remote_index].last_received());
854                    (true, disconnected_time)
855                },
856            )
857        };
858
859        if valid {
860            // Only allow transitions to fail if a.failedTimeout is non-zero
861            let mut total_time_to_failure = self.failed_timeout;
862            if total_time_to_failure != Duration::from_secs(0) {
863                total_time_to_failure += self.disconnected_timeout;
864            }
865
866            if total_time_to_failure != Duration::from_secs(0)
867                && disconnected_time > total_time_to_failure
868            {
869                self.update_connection_state(ConnectionState::Failed);
870            } else if self.disconnected_timeout != Duration::from_secs(0)
871                && disconnected_time > self.disconnected_timeout
872            {
873                self.update_connection_state(ConnectionState::Disconnected);
874            } else {
875                self.update_connection_state(ConnectionState::Connected);
876            }
877        }
878
879        valid
880    }
881
882    /// Sends STUN Binding Requests to the selected pair at `keepalive_interval` to
883    /// maintain consent freshness (RFC 7675).
884    pub(crate) fn check_keepalive(&mut self) {
885        let (local_index, remote_index, pair_index) = {
886            self.selected_pair
887                .as_ref()
888                .map_or((None, None, None), |&pair_index| {
889                    let p = &self.candidate_pairs[pair_index];
890                    (Some(p.local_index), Some(p.remote_index), Some(pair_index))
891                })
892        };
893
894        if let (Some(local_index), Some(remote_index), Some(pair_index)) =
895            (local_index, remote_index, pair_index)
896            && self.keepalive_interval != Duration::from_secs(0)
897            && self.last_consent_sent.elapsed() >= self.keepalive_interval
898        {
899            self.last_consent_sent = Instant::now();
900            self.candidate_pairs[pair_index].on_consent_request_sent();
901            self.ping_candidate(local_index, remote_index);
902        }
903    }
904
905    fn request_connectivity_check(&mut self) {
906        if self.ufrag_pwd.remote_credentials.is_some() {
907            self.contact(Instant::now());
908        }
909    }
910
911    /// Remove all candidates.
912    /// This closes any listening sockets and removes both the local and remote candidate lists.
913    ///
914    /// This is used for restarts, failures and on close.
915    pub(crate) fn delete_all_candidates(&mut self, keep_local_candidates: bool) {
916        if !keep_local_candidates {
917            self.local_candidates.clear();
918        }
919        self.remote_candidates.clear();
920    }
921
922    pub(crate) fn find_remote_candidate(&self, addr: SocketAddr) -> Option<usize> {
923        for (index, c) in self.remote_candidates.iter().enumerate() {
924            if c.addr() == addr {
925                return Some(index);
926            }
927        }
928        None
929    }
930
931    pub(crate) fn find_local_candidate(
932        &self,
933        addr: SocketAddr,
934        transport_protocol: TransportProtocol,
935    ) -> Option<usize> {
936        for (index, c) in self.local_candidates.iter().enumerate() {
937            if c.network_type().to_protocol() != transport_protocol {
938                continue;
939            }
940
941            // For TCP active candidates, match by IP only (ignore port).
942            // TCP active candidates use port 9 as placeholder in signaling,
943            // but the actual connection uses an ephemeral port.
944            if c.tcp_type() == TcpType::Active && transport_protocol == TransportProtocol::TCP {
945                if c.addr().ip() == addr.ip() {
946                    return Some(index);
947                }
948            } else if c.addr() == addr {
949                return Some(index);
950            } else if let Some(related_address) = c.related_address()
951                && related_address.address == addr.ip().to_string()
952                && related_address.port == addr.port()
953            {
954                return Some(index);
955            }
956        }
957        None
958    }
959
960    pub(crate) fn send_binding_request(
961        &mut self,
962        m: &Message,
963        local_index: usize,
964        remote_index: usize,
965    ) {
966        trace!(
967            "[{}]: ping STUN from {} to {}",
968            self.get_name(),
969            self.local_candidates[local_index],
970            self.remote_candidates[remote_index],
971        );
972
973        self.invalidate_pending_binding_requests(Instant::now());
974
975        self.pending_binding_requests.push(BindingRequest {
976            timestamp: Instant::now(),
977            transaction_id: m.transaction_id,
978            destination: self.remote_candidates[remote_index].addr(),
979            is_use_candidate: m.contains(ATTR_USE_CANDIDATE),
980        });
981
982        // Track request sent on the candidate pair
983        if let Some(pair_index) = self.find_pair(local_index, remote_index) {
984            self.candidate_pairs[pair_index].on_request_sent();
985        }
986
987        self.send_stun(m, local_index, remote_index);
988    }
989
990    pub(crate) fn send_binding_success(
991        &mut self,
992        m: &Message,
993        local_index: usize,
994        remote_index: usize,
995    ) {
996        let addr = self.remote_candidates[remote_index].addr();
997        let (ip, port) = (addr.ip(), addr.port());
998        let local_pwd = self.ufrag_pwd.local_credentials.pwd.clone();
999
1000        let (out, result) = {
1001            let mut out = Message::new();
1002            let result = out.build(&[
1003                Box::new(m.clone()),
1004                Box::new(BINDING_SUCCESS),
1005                Box::new(XorMappedAddress { ip, port }),
1006                Box::new(MessageIntegrity::new_short_term_integrity(local_pwd)),
1007                Box::new(FINGERPRINT),
1008            ]);
1009            (out, result)
1010        };
1011
1012        if let Err(err) = result {
1013            warn!(
1014                "[{}]: Failed to handle inbound ICE from: {} to: {} error: {}",
1015                self.get_name(),
1016                self.local_candidates[local_index],
1017                self.remote_candidates[remote_index],
1018                err
1019            );
1020        } else {
1021            // Track response sent on the candidate pair
1022            if let Some(pair_index) = self.find_pair(local_index, remote_index) {
1023                self.candidate_pairs[pair_index].on_response_sent();
1024            }
1025            self.send_stun(&out, local_index, remote_index);
1026        }
1027    }
1028
1029    /// Sends a 487 (Role Conflict) error response.
1030    /// RFC 8445 Section 7.3.1.1
1031    pub(crate) fn send_role_conflict_error(
1032        &mut self,
1033        m: &Message,
1034        local_index: usize,
1035        remote_index: usize,
1036    ) {
1037        use stun::error_code::*;
1038
1039        let local_pwd = self.ufrag_pwd.local_credentials.pwd.clone();
1040
1041        let (out, result) = {
1042            let mut out = Message::new();
1043            let result = out.build(&[
1044                Box::new(m.clone()),
1045                Box::new(stun::message::BINDING_ERROR),
1046                Box::new(CODE_ROLE_CONFLICT),
1047                Box::new(MessageIntegrity::new_short_term_integrity(local_pwd)),
1048                Box::new(FINGERPRINT),
1049            ]);
1050            (out, result)
1051        };
1052
1053        if let Err(err) = result {
1054            warn!(
1055                "[{}]: Failed to send role conflict error from: {} to: {} error: {}",
1056                self.get_name(),
1057                self.local_candidates[local_index],
1058                self.remote_candidates[remote_index],
1059                err
1060            );
1061        } else {
1062            debug!(
1063                "[{}]: Sent 487 Role Conflict error from {} to {}",
1064                self.get_name(),
1065                self.local_candidates[local_index],
1066                self.remote_candidates[remote_index]
1067            );
1068            self.send_stun(&out, local_index, remote_index);
1069        }
1070    }
1071
1072    /// Switches the ICE agent role and recomputes all candidate pair priorities.
1073    /// RFC 8445 Section 7.3.1.1
1074    pub(crate) fn switch_role(&mut self) {
1075        self.is_controlling = !self.is_controlling;
1076
1077        // Recompute priorities for all candidate pairs
1078        // The priority calculation depends on ice_role_controlling
1079        for pair in &mut self.candidate_pairs {
1080            pair.ice_role_controlling = self.is_controlling;
1081        }
1082
1083        // Clear nominated pair when switching roles
1084        self.nominated_pair = None;
1085
1086        info!(
1087            "[{}]: Role switched, recomputed {} candidate pair priorities",
1088            self.get_name(),
1089            self.candidate_pairs.len()
1090        );
1091
1092        self.event_outs
1093            .push_back(Event::RoleChange(self.is_controlling));
1094    }
1095
1096    /// Removes pending binding requests that are over `maxBindingRequestTimeout` old Let HTO be the
1097    /// transaction timeout, which SHOULD be 2*RTT if RTT is known or 500 ms otherwise.
1098    ///
1099    /// reference: (IETF ref-8445)[https://tools.ietf.org/html/rfc8445#appendix-B.1].
1100    pub(crate) fn invalidate_pending_binding_requests(&mut self, filter_time: Instant) {
1101        let pending_binding_requests = &mut self.pending_binding_requests;
1102        let initial_size = pending_binding_requests.len();
1103
1104        let mut temp = vec![];
1105        for binding_request in pending_binding_requests.drain(..) {
1106            if filter_time
1107                .checked_duration_since(binding_request.timestamp)
1108                .map(|duration| duration < MAX_BINDING_REQUEST_TIMEOUT)
1109                .unwrap_or(true)
1110            {
1111                temp.push(binding_request);
1112            }
1113        }
1114
1115        *pending_binding_requests = temp;
1116        let bind_requests_remaining = pending_binding_requests.len();
1117        let bind_requests_removed = initial_size - bind_requests_remaining;
1118        if bind_requests_removed > 0 {
1119            trace!(
1120                "[{}]: Discarded {} binding requests because they expired, still {} remaining",
1121                self.get_name(),
1122                bind_requests_removed,
1123                bind_requests_remaining,
1124            );
1125        }
1126    }
1127
1128    /// Assert that the passed `TransactionID` is in our `pendingBindingRequests` and returns the
1129    /// destination, If the bindingRequest was valid remove it from our pending cache.
1130    pub(crate) fn handle_inbound_binding_success(
1131        &mut self,
1132        id: TransactionId,
1133    ) -> Option<BindingRequest> {
1134        self.invalidate_pending_binding_requests(Instant::now());
1135
1136        let pending_binding_requests = &mut self.pending_binding_requests;
1137        for i in 0..pending_binding_requests.len() {
1138            if pending_binding_requests[i].transaction_id == id {
1139                let valid_binding_request = pending_binding_requests.remove(i);
1140                return Some(valid_binding_request);
1141            }
1142        }
1143        None
1144    }
1145
1146    /// Processes STUN traffic from a remote candidate.
1147    pub(crate) fn handle_inbound(
1148        &mut self,
1149        now: Instant,
1150        m: &mut Message,
1151        local_index: usize,
1152        remote_addr: SocketAddr,
1153    ) -> Result<()> {
1154        if m.typ.method != METHOD_BINDING
1155            || !(m.typ.class == CLASS_SUCCESS_RESPONSE
1156                || m.typ.class == CLASS_REQUEST
1157                || m.typ.class == CLASS_INDICATION)
1158        {
1159            trace!(
1160                "[{}]: unhandled STUN from {} to {} class({}) method({})",
1161                self.get_name(),
1162                remote_addr,
1163                self.local_candidates[local_index],
1164                m.typ.class,
1165                m.typ.method
1166            );
1167            return Err(Error::ErrUnhandledStunpacket);
1168        }
1169
1170        // RFC 8445 Section 7.3.1.1 - Detecting and Repairing Role Conflicts
1171        if self.is_controlling {
1172            if m.contains(ATTR_ICE_CONTROLLING) {
1173                // Both agents are controlling - role conflict detected
1174                let mut remote_controlling = crate::attributes::control::AttrControlling::default();
1175                if let Err(err) = remote_controlling.get_from(m) {
1176                    warn!(
1177                        "[{}]: Failed to get remote ICE-CONTROLLING attribute: {}",
1178                        self.get_name(),
1179                        err
1180                    );
1181                    return Err(err);
1182                }
1183
1184                debug!(
1185                    "[{}]: Role conflict detected (both controlling), local tiebreaker: {}, remote tiebreaker: {}",
1186                    self.get_name(),
1187                    self.tie_breaker,
1188                    remote_controlling.0
1189                );
1190
1191                // Only process if this is a request (not a response)
1192                if m.typ.class == CLASS_REQUEST {
1193                    // Send 487 Role Conflict error
1194                    if let Some(remote_index) = self.find_remote_candidate(remote_addr) {
1195                        self.send_role_conflict_error(m, local_index, remote_index);
1196                    }
1197
1198                    // Compare tiebreakers - if ours is smaller, we switch to controlled
1199                    if self.tie_breaker < remote_controlling.0 {
1200                        info!(
1201                            "[{}]: Switching from controlling to controlled due to role conflict (smaller tiebreaker)",
1202                            self.get_name()
1203                        );
1204                        self.switch_role();
1205                    }
1206                }
1207                // Continue processing the message after handling role conflict
1208            } else if m.contains(ATTR_USE_CANDIDATE) {
1209                debug!(
1210                    "[{}]: useCandidate && a.isControlling == true",
1211                    self.get_name(),
1212                );
1213                return Err(Error::ErrUnexpectedStunrequestMessage);
1214            }
1215        } else if m.contains(ATTR_ICE_CONTROLLED) {
1216            // Both agents are controlled - role conflict detected
1217            let mut remote_controlled = crate::attributes::control::AttrControlled::default();
1218            if let Err(err) = remote_controlled.get_from(m) {
1219                warn!(
1220                    "[{}]: Failed to get remote ICE-CONTROLLED attribute: {}",
1221                    self.get_name(),
1222                    err
1223                );
1224                return Err(err);
1225            }
1226
1227            debug!(
1228                "[{}]: Role conflict detected (both controlled), local tiebreaker: {}, remote tiebreaker: {}",
1229                self.get_name(),
1230                self.tie_breaker,
1231                remote_controlled.0
1232            );
1233
1234            // Only process if this is a request (not a response)
1235            if m.typ.class == CLASS_REQUEST {
1236                // Send 487 Role Conflict error
1237                if let Some(remote_index) = self.find_remote_candidate(remote_addr) {
1238                    self.send_role_conflict_error(m, local_index, remote_index);
1239                }
1240
1241                // Compare tiebreakers - if ours is larger, we switch to controlling
1242                if self.tie_breaker > remote_controlled.0 {
1243                    info!(
1244                        "[{}]: Switching from controlled to controlling due to role conflict (larger tiebreaker)",
1245                        self.get_name()
1246                    );
1247                    self.switch_role();
1248                }
1249            }
1250            // Continue processing the message after handling role conflict
1251        }
1252
1253        let Some(remote_credentials) = &self.ufrag_pwd.remote_credentials else {
1254            debug!(
1255                "[{}]: ufrag_pwd.remote_credentials.is_none",
1256                self.get_name(),
1257            );
1258            return Err(Error::ErrPasswordEmpty);
1259        };
1260
1261        let mut remote_candidate_index = self.find_remote_candidate(remote_addr);
1262        if m.typ.class == CLASS_SUCCESS_RESPONSE {
1263            if let Err(err) = assert_inbound_message_integrity(m, remote_credentials.pwd.as_bytes())
1264            {
1265                warn!(
1266                    "[{}]: discard message from ({}), {}",
1267                    self.get_name(),
1268                    remote_addr,
1269                    err
1270                );
1271                return Err(err);
1272            }
1273
1274            if let Some(remote_index) = &remote_candidate_index {
1275                self.handle_success_response(now, m, local_index, *remote_index, remote_addr);
1276            } else {
1277                warn!(
1278                    "[{}]: discard success message from ({}), no such remote",
1279                    self.get_name(),
1280                    remote_addr
1281                );
1282                return Err(Error::ErrUnhandledStunpacket);
1283            }
1284        } else if m.typ.class == CLASS_REQUEST {
1285            {
1286                let username = self.ufrag_pwd.local_credentials.ufrag.clone()
1287                    + ":"
1288                    + remote_credentials.ufrag.as_str();
1289                if let Err(err) = assert_inbound_username(m, &username) {
1290                    warn!(
1291                        "[{}]: discard message from ({}), {}",
1292                        self.get_name(),
1293                        remote_addr,
1294                        err
1295                    );
1296                    return Err(err);
1297                } else if let Err(err) = assert_inbound_message_integrity(
1298                    m,
1299                    self.ufrag_pwd.local_credentials.pwd.as_bytes(),
1300                ) {
1301                    warn!(
1302                        "[{}]: discard message from ({}), {}",
1303                        self.get_name(),
1304                        remote_addr,
1305                        err
1306                    );
1307                    return Err(err);
1308                }
1309            }
1310
1311            if remote_candidate_index.is_none() {
1312                // Use the local candidate's network type for the peer-reflexive candidate
1313                let network_type = self.local_candidates[local_index].network_type();
1314                let (ip, port) = (remote_addr.ip(), remote_addr.port());
1315
1316                let prflx_candidate_config = CandidatePeerReflexiveConfig {
1317                    base_config: CandidateConfig {
1318                        network: network_type.to_string(),
1319                        address: ip.to_string(),
1320                        port,
1321                        component: self.local_candidates[local_index].component(),
1322                        ..CandidateConfig::default()
1323                    },
1324                    rel_addr: "".to_owned(),
1325                    rel_port: 0,
1326                };
1327
1328                match prflx_candidate_config.new_candidate_peer_reflexive() {
1329                    Ok(prflx_candidate) => {
1330                        if let Ok(added) = self.add_remote_candidate(prflx_candidate)
1331                            && added
1332                        {
1333                            remote_candidate_index = Some(self.remote_candidates.len() - 1);
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}