1use alloc::boxed::Box;
15use alloc::string::String;
16use alloc::vec::Vec;
17
18use alloc::collections::{BTreeMap, BTreeSet, VecDeque};
19use core::net::{IpAddr, SocketAddr};
20use core::ops::Range;
21use core::sync::atomic::{AtomicUsize, Ordering};
22use core::time::Duration;
23use stun_proto::auth::ShortTermAuth;
24
25use crate::ALPHABET;
26use crate::candidate::{Candidate, CandidatePair, CandidateType, TcpType, TransportType};
27use crate::component::ComponentConnectionState;
28use crate::gathering::GatheredCandidate;
29use crate::rand::generate_random_ice_string;
30use crate::tcp::TcpBuffer;
31use crate::turn::TurnClient;
32use byteorder::{BigEndian, ByteOrder};
33use rice_stun_types::attribute::{IceControlled, IceControlling, Priority, UseCandidate};
34use stun_proto::Instant;
35use stun_proto::agent::{StunAgent, StunAgentPollRet, StunError, Transmit};
36use stun_proto::types::attribute::*;
37use stun_proto::types::data::Data;
38use stun_proto::types::message::*;
39use turn_client_proto::api::{Socket5Tuple, TransmitBuild, TurnEvent, TurnPollRet, TurnRecvRet};
40use turn_client_proto::prelude::*;
41
42use tracing::{debug, error, info, trace, warn};
43
44static STUN_AGENT_COUNT: AtomicUsize = AtomicUsize::new(0);
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub(crate) struct StunAgentId(usize);
48
49impl core::ops::Deref for StunAgentId {
50 type Target = usize;
51 fn deref(&self) -> &Self::Target {
52 &self.0
53 }
54}
55
56impl StunAgentId {
57 fn generate() -> Self {
58 let stun_agent_id = STUN_AGENT_COUNT.fetch_add(1, Ordering::SeqCst);
59 Self(stun_agent_id)
60 }
61}
62
63impl core::fmt::Display for StunAgentId {
64 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
65 self.0.fmt(f)
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct Credentials {
72 pub ufrag: String,
74 pub passwd: String,
76}
77
78impl From<Credentials> for ShortTermCredentials {
79 fn from(cred: Credentials) -> Self {
80 ShortTermCredentials::new(cred.passwd)
81 }
82}
83
84impl Credentials {
85 pub fn new(username: String, password: String) -> Self {
87 Self {
89 ufrag: username,
90 passwd: password,
91 }
92 }
93}
94
95#[derive(Debug, Clone)]
96pub struct SelectedTurn {
97 transport: TransportType,
98 local_addr: SocketAddr,
99 remote_addr: SocketAddr,
100}
101
102impl SelectedTurn {
103 pub fn transport(&self) -> TransportType {
104 self.transport
105 }
106 pub fn local_addr(&self) -> SocketAddr {
107 self.local_addr
108 }
109 pub fn remote_addr(&self) -> SocketAddr {
110 self.remote_addr
111 }
112}
113
114#[derive(Debug, Clone)]
116pub struct SelectedPair {
117 candidate_pair: CandidatePair,
118 local_stun_agent: StunAgentId,
119 turn: Option<SelectedTurn>,
120}
121
122impl SelectedPair {
123 pub(crate) fn new(
125 candidate_pair: CandidatePair,
126 local_stun_agent: StunAgentId,
127 turn: Option<SelectedTurn>,
128 ) -> Self {
129 Self {
130 candidate_pair,
131 local_stun_agent,
132 turn,
133 }
134 }
135
136 pub fn candidate_pair(&self) -> &CandidatePair {
138 &self.candidate_pair
139 }
140
141 pub fn local_turn(&self) -> Option<&SelectedTurn> {
143 self.turn.as_ref()
144 }
145
146 pub(crate) fn stun_agent_id(&self) -> StunAgentId {
148 self.local_stun_agent
149 }
150}
151
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct RequestRto {
154 pub(crate) initial: Duration,
155 pub(crate) max: Duration,
156 pub(crate) retransmits: u32,
157 pub(crate) final_retransmit_timeout: Duration,
158}
159
160impl RequestRto {
161 pub fn from_parts(
162 initial: Duration,
163 max: Duration,
164 retransmits: u32,
165 final_retransmit_timeout: Duration,
166 ) -> Self {
167 Self {
168 initial,
169 max,
170 retransmits,
171 final_retransmit_timeout,
172 }
173 }
174}
175
176#[derive(Debug)]
178pub struct HandleRecvReply<T: AsRef<[u8]> + core::fmt::Debug> {
179 pub handled: bool,
180 pub have_more_data: bool,
181 pub data: Option<DataAndRange<T>>,
182}
183
184impl<T: AsRef<[u8]> + core::fmt::Debug> core::fmt::Display for HandleRecvReply<T> {
185 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
186 write!(f, "HandleRecvReply {{")?;
187 let mut need_comma = false;
188 if self.handled {
189 write!(f, "handled, ")?;
190 need_comma = true;
191 }
192 if let Some(data) = self.data.as_ref() {
193 if need_comma {
194 write!(f, ", ")?;
195 }
196 write!(f, "{} bytes", data.as_ref().len())?;
197 }
198 write!(f, "}}")
199 }
200}
201
202impl<T: AsRef<[u8]> + core::fmt::Debug> Default for HandleRecvReply<T> {
203 fn default() -> Self {
204 Self {
205 handled: false,
206 have_more_data: false,
207 data: None,
208 }
209 }
210}
211
212#[derive(Debug)]
213pub struct DataAndRange<T: AsRef<[u8]> + core::fmt::Debug> {
214 data: T,
215 range: Range<usize>,
216}
217
218impl<T: AsRef<[u8]> + core::fmt::Debug> AsRef<[u8]> for DataAndRange<T> {
219 fn as_ref(&self) -> &[u8] {
220 &self.data.as_ref()[self.range.start..self.range.end]
221 }
222}
223
224#[derive(Debug)]
226pub enum ConnCheckEvent {
227 ComponentState(usize, ComponentConnectionState),
229 SelectedPair(usize, Box<SelectedPair>),
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq)]
234pub(crate) enum CandidatePairState {
235 Waiting,
236 InProgress,
237 Succeeded,
238 Failed,
239 Frozen,
240}
241
242impl CandidatePairState {
243 fn cmp_progression(&self, other: &Self) -> core::cmp::Ordering {
244 if self == other {
245 return core::cmp::Ordering::Equal;
246 }
247 match (self, other) {
248 (Self::Failed, _) => core::cmp::Ordering::Less,
249 (Self::Frozen, other) => {
250 if *other == Self::Failed {
251 core::cmp::Ordering::Greater
252 } else {
253 core::cmp::Ordering::Less
254 }
255 }
256 (Self::Waiting, other) => {
257 if [Self::Failed, Self::Frozen].contains(other) {
258 core::cmp::Ordering::Greater
259 } else {
260 core::cmp::Ordering::Less
261 }
262 }
263 (Self::InProgress, other) => {
264 if [Self::Failed, Self::Frozen, Self::Waiting].contains(other) {
265 core::cmp::Ordering::Greater
266 } else {
267 core::cmp::Ordering::Less
268 }
269 }
270 (Self::Succeeded, other) => {
271 if [Self::Failed, Self::Frozen, Self::InProgress, Self::Waiting].contains(other) {
272 core::cmp::Ordering::Greater
273 } else {
274 core::cmp::Ordering::Less
275 }
276 }
277 }
278 }
279}
280
281impl core::fmt::Display for CandidatePairState {
282 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
283 f.pad(&alloc::format!("{self:?}"))
284 }
285}
286
287static CONN_CHECK_COUNT: AtomicUsize = AtomicUsize::new(0);
288
289#[derive(Debug, Clone)]
290struct TcpConnCheck {
291 agent: Option<StunAgentId>,
292}
293
294#[derive(Debug, Clone)]
295enum ConnCheckVariant {
296 Agent(StunAgentId),
297 Tcp(TcpConnCheck),
298}
299
300#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
301struct ConnCheckId(usize);
302
303impl core::ops::Deref for ConnCheckId {
304 type Target = usize;
305 fn deref(&self) -> &Self::Target {
306 &self.0
307 }
308}
309
310impl ConnCheckId {
311 fn generate() -> Self {
312 let conncheck_id = CONN_CHECK_COUNT.fetch_add(1, Ordering::SeqCst);
313 Self(conncheck_id)
314 }
315}
316
317impl core::fmt::Display for ConnCheckId {
318 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
319 self.0.fmt(f)
320 }
321}
322
323#[derive(Debug)]
324struct ConnCheck {
325 conncheck_id: ConnCheckId,
326 checklist_id: usize,
327 nominate: bool,
328 pair: CandidatePair,
329 variant: ConnCheckVariant,
330 controlling: bool,
331 state: CandidatePairState,
332 stun_request: Option<TransactionId>,
333 remote_credentials: Credentials,
334}
335
336impl ConnCheck {
337 fn new(
338 checklist_id: usize,
339 pair: CandidatePair,
340 agent: StunAgentId,
341 nominate: bool,
342 controlling: bool,
343 remote_credentials: Credentials,
344 ) -> Self {
345 Self {
346 conncheck_id: ConnCheckId::generate(),
347 checklist_id,
348 pair,
349 state: CandidatePairState::Frozen,
350 stun_request: None,
351 variant: ConnCheckVariant::Agent(agent),
352 nominate,
353 controlling,
354 remote_credentials,
355 }
356 }
357
358 fn new_tcp(
359 checklist_id: usize,
360 pair: CandidatePair,
361 nominate: bool,
362 controlling: bool,
363 remote_credentials: Credentials,
364 ) -> Self {
365 Self {
366 conncheck_id: ConnCheckId::generate(),
367 checklist_id,
368 pair,
369 state: CandidatePairState::Frozen,
370 stun_request: None,
371 variant: ConnCheckVariant::Tcp(TcpConnCheck { agent: None }),
372 nominate,
373 controlling,
374 remote_credentials,
375 }
376 }
377
378 fn agent_id(&self) -> Option<StunAgentId> {
379 match &self.variant {
380 ConnCheckVariant::Agent(agent) => Some(*agent),
381 ConnCheckVariant::Tcp(tcp) => tcp.agent,
382 }
383 }
384
385 fn state(&self) -> CandidatePairState {
386 self.state
387 }
388
389 #[tracing::instrument(
390 name = "set_check_state",
391 level = "debug",
392 skip(self, state),
393 fields(
394 ?self.conncheck_id,
395 )
396 )]
397 fn set_state(&mut self, state: CandidatePairState) {
398 if self.state != state {
400 debug!(old_state = ?self.state, new_state = ?state, "updating state");
401 self.state = state;
402 }
403 }
404
405 fn nominate(&self) -> bool {
406 self.nominate
407 }
408
409 fn generate_stun_request(
410 pair: &CandidatePair,
411 nominate: bool,
412 controlling: bool,
413 tie_breaker: u64,
414 local_credentials: Credentials,
415 remote_credentials: Credentials,
416 ) -> Result<MessageWriteVec, StunError> {
417 let username = remote_credentials.ufrag.clone() + ":" + &local_credentials.ufrag;
418
419 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
421 let priority = Priority::new(pair.local.priority);
422 msg.add_attribute(&priority)?;
423 let control = IceControlling::new(tie_breaker);
424 let controlled = IceControlled::new(tie_breaker);
425 if controlling {
426 msg.add_attribute(&control)?;
427 } else {
428 msg.add_attribute(&controlled)?;
429 }
430 let use_cand = UseCandidate::new();
431 if nominate {
432 msg.add_attribute(&use_cand)?;
433 }
434 let username = Username::new(&username)?;
435 msg.add_attribute(&username)?;
436 msg.add_message_integrity(
437 &MessageIntegrityCredentials::ShortTerm(remote_credentials.clone().into()),
438 IntegrityAlgorithm::Sha1,
439 )?;
440 msg.add_fingerprint()?;
441 Ok(msg)
442 }
443}
444
445#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
446pub(crate) enum CheckListState {
447 Running,
448 Completed,
449 Failed,
450}
451
452static CONN_CHECK_LIST_COUNT: AtomicUsize = AtomicUsize::new(0);
453
454#[derive(Debug)]
455struct CheckStunAgent {
456 id: StunAgentId,
457 agent: StunAgent,
458 turn_id: Option<StunAgentId>,
459}
460
461#[derive(Debug)]
463pub struct ConnCheckList {
464 checklist_id: usize,
465 state: CheckListState,
466 component_ids: Vec<(usize, ComponentConnectionState)>,
467 local_credentials: Credentials,
468 remote_credentials: Credentials,
469 local_candidates: Vec<ConnCheckLocalCandidate>,
470 remote_candidates: Vec<Candidate>,
471 triggered: VecDeque<ConnCheckId>,
473 pairs: VecDeque<ConnCheck>,
474 valid: Vec<ConnCheckId>,
475 nominated: Vec<ConnCheckId>,
476 controlling: bool,
477 trickle_ice: bool,
478 local_end_of_candidates: bool,
479 remote_end_of_candidates: bool,
480 events: VecDeque<ConnCheckEvent>,
481 agents: Vec<CheckStunAgent>,
482 stun_auth_local: ShortTermAuth,
483 stun_auth_remote: ShortTermAuth,
484 turn_clients: Vec<CheckTurnClient>,
485 pending_delete_turn_clients: Vec<CheckTurnClient>,
486 tcp_buffers: BTreeMap<(SocketAddr, SocketAddr), TcpBuffer>,
487 pending_turn_permissions: VecDeque<(StunAgentId, TransportType, IpAddr)>,
488 pending_recv: VecDeque<PendingRecv>,
489 pending_turn_tcp_connect: Vec<PendingTurnTcp>,
490}
491
492#[derive(Debug)]
493struct CheckTurnClient {
494 id: StunAgentId,
495 client: TurnClient,
496 local_tcp_sockets: Vec<SocketAddr>,
497}
498
499#[derive(Debug)]
500struct PendingTurnTcp {
501 turn_id: StunAgentId,
502 conncheck_id: ConnCheckId,
503 relayed_addr: SocketAddr,
504 turn_addr: SocketAddr,
505 peer_addr: SocketAddr,
506 turn_connect_id: Option<u32>,
507 allocated: bool,
508}
509
510fn candidate_is_same_connection(a: &Candidate, b: &Candidate) -> bool {
511 if a.component_id != b.component_id {
512 return false;
513 }
514 if a.transport_type != b.transport_type {
515 return false;
516 }
517 if a.base_address != b.base_address {
518 return false;
519 }
520 if a.address != b.address {
521 return false;
522 }
523 if a.tcp_type != b.tcp_type {
525 return false;
526 }
527 true
529}
530
531fn candidate_pair_is_same_connection(a: &CandidatePair, b: &CandidatePair) -> bool {
532 if !candidate_is_same_connection(&a.local, &b.local) {
533 return false;
534 }
535 if !candidate_is_same_connection(&a.remote, &b.remote) {
536 return false;
537 }
538 true
539}
540
541#[derive(Debug)]
542enum LocalCandidateVariant {
543 Agent(StunAgentId),
544 TcpListener,
545 TcpActive,
546}
547
548#[derive(Debug)]
549struct ConnCheckLocalCandidate {
550 candidate: Candidate,
551 variant: LocalCandidateVariant,
552}
553
554fn response_add_credentials<O, B: MessageWrite<Output = O>>(
555 response: B,
556 auth: &mut ShortTermAuth,
557) -> Result<B, StunError> {
558 let mut response = auth.sign_outgoing_message(response).unwrap();
559 response.add_fingerprint()?;
560 Ok(response)
561}
562fn binding_success_response(
563 msg: &Message<'_>,
564 from: SocketAddr,
565 auth: &mut ShortTermAuth,
566) -> MessageWriteVec {
567 let mut response = Message::builder_success(msg, MessageWriteVec::new());
568 let xor_addr = XorMappedAddress::new(from, msg.transaction_id());
569 response.add_attribute(&xor_addr).unwrap();
570 response_add_credentials(response, auth).unwrap()
571}
572
573#[derive(Clone, Copy, Debug)]
574enum Nominate {
575 True,
576 False,
577 DontCare,
578}
579
580impl PartialEq<Nominate> for Nominate {
581 fn eq(&self, other: &Nominate) -> bool {
582 matches!(self, &Nominate::DontCare)
583 || matches!(other, &Nominate::DontCare)
584 || (matches!(self, Nominate::True) && matches!(other, Nominate::True))
585 || (matches!(self, Nominate::False) && matches!(other, Nominate::False))
586 }
587}
588impl PartialEq<bool> for Nominate {
589 fn eq(&self, other: &bool) -> bool {
590 matches!(self, Nominate::DontCare)
591 || (*other && self.eq(&Nominate::True))
592 || (!*other && self.eq(&Nominate::False))
593 }
594}
595
596fn generate_random_credentials() -> Credentials {
597 let user = generate_random_ice_string(ALPHABET.as_bytes(), 4);
598 let pass = generate_random_ice_string(ALPHABET.as_bytes(), 22);
599 Credentials::new(user, pass)
600}
601
602impl ConnCheckList {
603 fn new(checklist_id: usize, controlling: bool, trickle_ice: bool) -> Self {
604 let local_credentials = generate_random_credentials();
605 let remote_credentials = generate_random_credentials();
606 let mut stun_auth_local = ShortTermAuth::new();
607 stun_auth_local.set_credentials(local_credentials.clone().into(), IntegrityAlgorithm::Sha1);
608 let mut stun_auth_remote = ShortTermAuth::new();
609 stun_auth_remote
610 .set_credentials(remote_credentials.clone().into(), IntegrityAlgorithm::Sha1);
611 Self {
612 checklist_id,
613 state: CheckListState::Running,
614 component_ids: Vec::new(),
615 local_credentials,
616 remote_credentials,
617 local_candidates: Vec::new(),
618 remote_candidates: Vec::new(),
619 triggered: VecDeque::new(),
620 pairs: VecDeque::new(),
621 valid: Vec::new(),
622 nominated: Vec::new(),
623 controlling,
624 trickle_ice,
625 local_end_of_candidates: false,
626 remote_end_of_candidates: false,
627 events: VecDeque::new(),
628 agents: Vec::new(),
629 stun_auth_local,
630 stun_auth_remote,
631 turn_clients: Vec::new(),
632 pending_delete_turn_clients: Vec::new(),
633 tcp_buffers: BTreeMap::default(),
634 pending_turn_permissions: VecDeque::new(),
635 pending_recv: VecDeque::new(),
636 pending_turn_tcp_connect: Vec::new(),
637 }
638 }
639
640 fn state(&self) -> CheckListState {
641 self.state
642 }
643
644 pub fn set_local_credentials(&mut self, credentials: Credentials) {
646 trace!(
647 "changing local credentials from {:?} to {credentials:?}",
648 self.remote_credentials
649 );
650 self.stun_auth_local
651 .set_credentials(credentials.clone().into(), IntegrityAlgorithm::Sha1);
652 self.local_credentials = credentials;
653 }
654
655 pub fn set_remote_credentials(&mut self, credentials: Credentials) {
657 trace!(
658 "changing remote credentials from {:?} to {credentials:?}",
659 self.remote_credentials
660 );
661 self.stun_auth_remote
662 .set_credentials(credentials.clone().into(), IntegrityAlgorithm::Sha1);
663
664 let mut request_cancels = Vec::new();
667 let new_pairs = self
668 .pairs
669 .drain(..)
670 .map(|mut check| {
671 if check.remote_credentials != credentials {
672 if let Some((agent_id, request_id)) =
673 check.agent_id().zip(check.stun_request.take())
674 {
675 request_cancels.push((agent_id, request_id));
676 let mut check = ConnCheck::new(
677 check.checklist_id,
678 check.pair.clone(),
679 agent_id,
680 check.nominate(),
681 check.controlling,
682 credentials.clone(),
683 );
684 if check.state != CandidatePairState::Frozen {
685 check.set_state(CandidatePairState::Waiting);
686 }
687 if let ConnCheckVariant::Tcp(ref mut tcp) = check.variant {
688 tcp.agent.take();
689 }
690 check
691 } else {
692 check
693 }
694 } else {
695 check
696 }
697 })
698 .collect::<VecDeque<_>>();
699 self.pairs = new_pairs;
700 self.sort_pairs();
701
702 for (agent_id, request_id) in request_cancels {
703 let Some(agent) = self.mut_agent_by_id(agent_id) else {
704 continue;
705 };
706 let Some(mut request) = agent.mut_request_transaction(request_id) else {
707 continue;
708 };
709 request.cancel();
710 }
711
712 self.remote_credentials = credentials;
713 }
714
715 pub fn add_component(&mut self, component_id: usize) {
717 if self
718 .component_ids
719 .iter()
720 .any(|(cid, _state)| component_id == *cid)
721 {
722 panic!("Component with ID {component_id} already exists in checklist!");
723 };
724 self.component_ids
725 .push((component_id, ComponentConnectionState::New));
726 }
727
728 fn poll_event(&mut self) -> Option<ConnCheckEvent> {
729 self.events.pop_back()
730 }
731
732 pub(crate) fn poll_recv(&mut self) -> Option<PendingRecv> {
733 self.pending_recv.pop_front()
734 }
735
736 pub(crate) fn add_agent_for_5tuple(
737 &mut self,
738 transport: TransportType,
739 local: SocketAddr,
740 remote: SocketAddr,
741 turn_id: Option<StunAgentId>,
742 ) -> (StunAgentId, usize) {
743 let agent = new_agent(transport, local, remote);
744 self.add_agent(agent, turn_id)
745 }
746
747 fn add_agent(
748 &mut self,
749 agent: StunAgent,
750 turn_id: Option<StunAgentId>,
751 ) -> (StunAgentId, usize) {
752 let agent_id = StunAgentId::generate();
753 trace!(
754 "Adding STUN Agent with id {agent_id} for transport {}, remote:{:?}, local:{}, turn:{turn_id:?}",
755 agent.transport(),
756 agent.remote_addr(),
757 agent.local_addr()
758 );
759 self.agents.push(CheckStunAgent {
760 id: agent_id,
761 agent,
762 turn_id,
763 });
764 (agent_id, self.agents.len() - 1)
765 }
766
767 pub(crate) fn mut_agent_for_5tuple(
768 &mut self,
769 transport: TransportType,
770 local: SocketAddr,
771 remote: SocketAddr,
772 ) -> Option<(StunAgentId, &mut StunAgent)> {
773 self.agents.iter_mut().find_map(|a| {
774 let matched = match transport {
775 TransportType::Udp => {
776 a.agent.local_addr() == local && a.agent.transport() == TransportType::Udp
777 }
778 TransportType::Tcp => {
779 a.agent.local_addr() == local
780 && a.agent.transport() == TransportType::Tcp
781 && a.agent.remote_addr().unwrap() == remote
782 }
783 };
784 if matched {
785 Some((a.id, &mut a.agent))
786 } else {
787 None
788 }
789 })
790 }
791
792 pub(crate) fn find_agent_for_5tuple(
793 &self,
794 transport: TransportType,
795 local: SocketAddr,
796 remote: SocketAddr,
797 ) -> Option<(StunAgentId, &StunAgent)> {
798 self.agents.iter().find_map(|a| {
799 let matched = match transport {
800 TransportType::Udp => {
801 a.agent.local_addr() == local && a.agent.transport() == TransportType::Udp
802 }
803 TransportType::Tcp => {
804 a.agent.local_addr() == local
805 && a.agent.transport() == TransportType::Tcp
806 && a.agent.remote_addr().unwrap() == remote
807 }
808 };
809 if matched {
810 Some((a.id, &a.agent))
811 } else {
812 None
813 }
814 })
815 }
816
817 pub(crate) fn agent_by_id(&self, id: StunAgentId) -> Option<&StunAgent> {
818 self.agents.iter().find_map(|agent| {
819 if id == agent.id {
820 Some(&agent.agent)
821 } else {
822 None
823 }
824 })
825 }
826
827 pub(crate) fn mut_agent_by_id(&mut self, id: StunAgentId) -> Option<&mut StunAgent> {
828 self.agents.iter_mut().find_map(|agent| {
829 if id == agent.id {
830 Some(&mut agent.agent)
831 } else {
832 None
833 }
834 })
835 }
836
837 pub(crate) fn find_or_create_udp_agent(
838 &mut self,
839 candidate: &Candidate,
840 turn_id: Option<StunAgentId>,
841 ) -> (StunAgentId, &StunAgent) {
842 if let Some(agent_id) = self
843 .agents
844 .iter()
845 .find(|a| {
846 let a = &a.agent;
847 match candidate.transport_type {
848 TransportType::Udp => {
849 a.local_addr() == candidate.base_address
850 && a.transport() == TransportType::Udp
851 }
852 _ => false,
853 }
854 })
855 .map(|a| a.id)
856 {
857 return (agent_id, self.agent_by_id(agent_id).unwrap());
858 }
859 let agent = StunAgent::builder(candidate.transport_type, candidate.base_address).build();
860 let (agent_id, agent_idx) = self.add_agent(agent, turn_id);
861 (agent_id, &self.agents[agent_idx].agent)
862 }
863
864 fn mut_turn_client_by_id(&mut self, id: StunAgentId) -> Option<&mut TurnClient> {
865 self.turn_clients
866 .iter_mut()
867 .chain(self.pending_delete_turn_clients.iter_mut())
868 .find_map(|client| {
869 if id == client.id {
870 Some(&mut client.client)
871 } else {
872 None
873 }
874 })
875 }
876
877 fn remove_turn_client_by_id(&mut self, id: StunAgentId) -> Option<TurnClient> {
878 if let Some(position) = self.turn_clients.iter().position(|client| id == client.id) {
879 Some(self.turn_clients.remove(position).client)
880 } else {
881 None
882 }
883 }
884
885 fn turn_client_by_allocated_address(
886 &self,
887 allocated_transport: TransportType,
888 allocated_addr: SocketAddr,
889 ) -> Option<(StunAgentId, &TurnClient)> {
890 self.turn_clients.iter().find_map(|client| {
891 if client
892 .client
893 .relayed_addresses()
894 .any(|(client_relayed_transport, relayed)| {
895 allocated_transport == client_relayed_transport && relayed == allocated_addr
898 })
899 {
900 Some((client.id, &client.client))
901 } else {
902 None
903 }
904 })
905 }
906
907 pub(crate) fn mut_turn_client_by_allocated_address(
908 &mut self,
909 allocated_transport: TransportType,
910 allocated_addr: SocketAddr,
911 ) -> Option<(StunAgentId, &mut TurnClient)> {
912 self.turn_clients
913 .iter_mut()
914 .chain(self.pending_delete_turn_clients.iter_mut())
915 .find_map(|client| {
916 if client
917 .client
918 .relayed_addresses()
919 .any(|(client_relayed_transport, relayed)| {
920 allocated_transport == client_relayed_transport && relayed == allocated_addr
923 })
924 {
925 Some((client.id, &mut client.client))
926 } else {
927 None
928 }
929 })
930 }
931
932 pub(crate) fn find_turn_client_for_5tuple(
933 &self,
934 transport: TransportType,
935 local: SocketAddr,
936 remote: SocketAddr,
937 ) -> Option<(StunAgentId, &TurnClient)> {
938 self.turn_clients
939 .iter()
940 .chain(self.pending_delete_turn_clients.iter())
941 .find_map(|client| {
942 if client.client.transport() == transport
943 && client.client.remote_addr() == remote
944 && (client.client.local_addr() == local
945 || client.local_tcp_sockets.contains(&local))
946 {
947 Some((client.id, &client.client))
948 } else {
949 None
950 }
951 })
952 }
953
954 #[tracing::instrument(
963 level = "info"
964 skip(self, gathered),
965 fields(
966 checklist_id = self.checklist_id,
967 candidate = ?gathered.candidate,
968 )
969 )]
970 pub fn add_local_gathered_candidate(&mut self, gathered: GatheredCandidate) -> bool {
971 let candidate_type = gathered.candidate.candidate_type;
972 let turn_id = if candidate_type == CandidateType::Relayed {
973 Some(StunAgentId::generate())
974 } else {
975 None
976 };
977 if !self.add_local_candidate_internal(gathered.candidate, turn_id) {
978 return false;
979 }
980 if candidate_type == CandidateType::Relayed {
981 let client = gathered.turn_agent.unwrap();
982 self.turn_clients.push(CheckTurnClient {
983 id: turn_id.unwrap(),
984 client: *client,
985 local_tcp_sockets: Default::default(),
986 });
987 }
988 self.generate_checks();
989 true
990 }
991
992 #[tracing::instrument(
1001 level = "info"
1002 skip(self),
1003 fields(
1004 checklist_id = self.checklist_id,
1005 )
1006 )]
1007 pub fn add_local_candidate(&mut self, local: Candidate) -> bool {
1008 if self.add_local_candidate_internal(local, None) {
1009 self.generate_checks();
1010 true
1011 } else {
1012 false
1013 }
1014 }
1015
1016 fn add_local_candidate_internal(
1017 &mut self,
1018 local: Candidate,
1019 turn_id: Option<StunAgentId>,
1020 ) -> bool {
1021 if self.local_end_of_candidates {
1022 panic!("Attempt made to add a local candidate after end-of-candidate received");
1023 }
1024 let existing = self
1025 .component_ids
1026 .iter()
1027 .find(|(id, _state)| id == &local.component_id);
1028 if existing.is_none() {
1029 panic!("Attempt made to add a local candidate without a corresponding add_component()");
1030 }
1031
1032 if let Some(idx) = self
1033 .local_candidates
1034 .iter()
1035 .position(|c| local.redundant_with(&c.candidate))
1036 {
1037 let other = &self.local_candidates[idx].candidate;
1038 if self.trickle_ice || other.priority >= local.priority {
1039 debug!("not adding redundant candidate");
1040 return false;
1041 } else if !self.trickle_ice {
1042 let removed = self.local_candidates.swap_remove(idx);
1043 debug!(
1044 "removing already existing redundant candidate {:?}",
1045 removed.candidate
1046 );
1047 self.pairs
1049 .retain(|pair| pair.pair.local != removed.candidate);
1050 }
1052 }
1053
1054 info!("adding");
1055
1056 match local.transport_type {
1057 TransportType::Udp => {
1058 let (agent_id, _) = self.find_or_create_udp_agent(&local, turn_id);
1059 self.local_candidates.push(ConnCheckLocalCandidate {
1060 candidate: local,
1061 variant: LocalCandidateVariant::Agent(agent_id),
1062 });
1063 }
1064 TransportType::Tcp => {
1065 let tcp_type = local.tcp_type.unwrap();
1066 if matches!(tcp_type, TcpType::Passive) {
1067 self.local_candidates.push(ConnCheckLocalCandidate {
1068 candidate: local,
1069 variant: LocalCandidateVariant::TcpListener,
1070 });
1071 } else {
1072 self.local_candidates.push(ConnCheckLocalCandidate {
1073 candidate: local,
1074 variant: LocalCandidateVariant::TcpActive,
1075 });
1076 }
1077 }
1078 }
1079 true
1080 }
1081
1082 #[tracing::instrument(
1084 level = "debug",
1085 skip(self),
1086 fields(
1087 checklist_id = self.checklist_id,
1088 )
1089 )]
1090 pub fn end_of_local_candidates(&mut self) {
1091 info!("end of local candidates");
1092 self.local_end_of_candidates = true;
1093 if self.remote_end_of_candidates {
1094 self.check_for_failure();
1095 }
1096 self.dump_check_state();
1097 }
1098
1099 #[tracing::instrument(
1101 level = "debug",
1102 skip(self),
1103 fields(
1104 checklist_id = self.checklist_id,
1105 )
1106 )]
1107 pub fn end_of_remote_candidates(&mut self) {
1108 info!("end of remote candidates");
1109 self.remote_end_of_candidates = true;
1110 if self.local_end_of_candidates {
1111 self.check_for_failure();
1112 }
1113 self.dump_check_state();
1114 }
1115
1116 pub fn add_remote_candidate(&mut self, remote: Candidate) {
1118 if remote.candidate_type != CandidateType::PeerReflexive && self.remote_end_of_candidates {
1119 error!("Attempt made to add a remote candidate after an end-of-candidates received");
1120 return;
1121 }
1122 if !self
1123 .component_ids
1124 .iter()
1125 .any(|(cid, _state)| cid == &remote.component_id)
1126 {
1127 self.component_ids
1128 .push((remote.component_id, ComponentConnectionState::New));
1129 }
1130 self.remote_candidates.push(remote);
1131 self.generate_checks();
1132 self.dump_check_state();
1133 }
1134
1135 fn next_triggered(&mut self) -> Option<&mut ConnCheck> {
1136 while let Some(check_id) = self.triggered.pop_back() {
1139 if let Some(check) = self.mut_check_by_id(check_id) {
1140 if check.stun_request.is_some() {
1144 continue;
1145 }
1146 check.set_state(CandidatePairState::InProgress);
1147 return self.mut_check_by_id(check_id);
1148 }
1149 }
1150 None
1151 }
1152
1153 #[cfg(test)]
1154 fn is_triggered(&self, needle: &CandidatePair) -> bool {
1155 trace!("triggered {:?}", self.triggered);
1156 self.triggered.iter().any(|&check_id| {
1157 self.check_by_id(check_id)
1158 .is_some_and(|check| needle == &check.pair)
1159 })
1160 }
1161
1162 #[tracing::instrument(
1163 level = "debug",
1164 skip(self),
1165 fields(
1166 checklist_id = self.checklist_id
1167 )
1168 )]
1169 fn next_waiting(&mut self) -> Option<&mut ConnCheck> {
1170 self.pairs
1171 .iter_mut()
1172 .filter_map(|check| {
1176 if check.state == CandidatePairState::Waiting {
1177 check.set_state(CandidatePairState::InProgress);
1178 Some(check)
1179 } else {
1180 None
1181 }
1182 })
1183 .next()
1184 }
1185
1186 fn foundations(&self) -> BTreeSet<String> {
1187 let mut foundations = BTreeSet::new();
1188 let _: Vec<_> = self
1189 .pairs
1190 .iter()
1191 .inspect(|check| {
1192 foundations.insert(check.pair.foundation());
1193 })
1194 .collect();
1195 foundations
1196 }
1197
1198 fn check_has_turn_permission(&self, check: &ConnCheck) -> bool {
1199 if check.pair.local.candidate_type == CandidateType::Relayed {
1200 let Some((_id, client)) = self.turn_client_by_allocated_address(
1201 check.pair.local.transport_type,
1202 check.pair.local.base_address,
1203 ) else {
1204 return false;
1205 };
1206 if client
1207 .permissions(
1208 check.pair.local.transport_type,
1209 check.pair.local.base_address,
1210 )
1211 .all(|permission| permission != check.pair.remote.address.ip())
1212 {
1213 return false;
1214 }
1215 }
1216 true
1217 }
1218
1219 fn foundation_not_waiting_in_progress(&self, foundation: &str) -> bool {
1220 for check in self
1221 .pairs
1222 .iter()
1223 .filter(|check| check.pair.foundation() == foundation)
1224 {
1225 if !self.check_has_turn_permission(check) {
1226 return false;
1227 }
1228 let state = check.state();
1229 if [CandidatePairState::InProgress, CandidatePairState::Waiting].contains(&state) {
1230 return false;
1231 }
1232 }
1233 true
1234 }
1235
1236 pub fn local_candidates(&self) -> impl Iterator<Item = &'_ Candidate> + '_ {
1238 self.local_candidates.iter().map(|local| &local.candidate)
1239 }
1240
1241 pub fn remote_candidates(&self) -> &[Candidate] {
1243 &self.remote_candidates
1244 }
1245
1246 #[tracing::instrument(
1247 name = "set_checklist_state",
1248 level = "debug",
1249 skip(self),
1250 fields(
1251 self.checklist_id,
1252 )
1253 )]
1254 fn set_state(&mut self, state: CheckListState) {
1255 if self.state != state {
1256 trace!(old_state = ?self.state, new_state = ?state, "changing state");
1257 self.state = state;
1258 }
1259 }
1260
1261 #[tracing::instrument(
1262 level = "debug",
1263 skip(self),
1264 fields(
1265 self.checklist_id
1266 )
1267 )]
1268 fn find_remote_candidate(
1269 &self,
1270 component_id: usize,
1271 ttype: TransportType,
1272 addr: SocketAddr,
1273 ) -> Option<Candidate> {
1274 self.remote_candidates
1275 .iter()
1276 .find(|&remote| {
1277 remote.component_id == component_id
1278 && remote.transport_type == ttype
1279 && remote.address == addr
1280 })
1281 .cloned()
1282 }
1283
1284 fn check_by_id(&self, id: ConnCheckId) -> Option<&ConnCheck> {
1285 self.pairs.iter().find(|check| check.conncheck_id == id)
1286 }
1287
1288 fn mut_check_by_id(&mut self, id: ConnCheckId) -> Option<&mut ConnCheck> {
1289 self.pairs.iter_mut().find(|check| check.conncheck_id == id)
1290 }
1291
1292 #[tracing::instrument(
1293 level = "debug",
1294 skip(self, check),
1295 fields(
1296 self.checklist_id,
1297 check.conncheck_id
1298 )
1299 )]
1300 fn add_triggered(&mut self, check: &ConnCheck) {
1301 if let Some(idx) = self.triggered.iter().position(|&existing| {
1302 self.check_by_id(existing).is_some_and(|existing| {
1303 candidate_pair_is_same_connection(&existing.pair, &check.pair)
1304 })
1305 }) {
1306 let triggered = self.check_by_id(self.triggered[idx]).unwrap();
1307 if check.nominate() && !triggered.nominate()
1311 || triggered.state() == CandidatePairState::Failed
1312 {
1313 let existing = self.triggered.remove(idx).unwrap();
1314 debug!("removing existing triggered {}", existing);
1315 } else {
1316 debug!("not adding duplicate triggered check");
1317 return;
1318 }
1319 }
1320 debug!("adding triggered check {}", check.conncheck_id);
1321 self.triggered.push_front(check.conncheck_id)
1322 }
1323
1324 fn foundation_has_check_state(&self, foundation: &str, state: CandidatePairState) -> bool {
1325 self.pairs
1326 .iter()
1327 .any(|check| check.pair.foundation() == foundation && check.state() == state)
1328 }
1329
1330 fn thawn_foundations(&mut self) -> Vec<String> {
1331 let mut thawn_foundations = Vec::new();
1333 for check in self.pairs.iter() {
1334 if !thawn_foundations
1335 .iter()
1336 .any(|foundation| check.pair.foundation() == *foundation)
1337 {
1338 thawn_foundations.push(check.pair.foundation().clone());
1339 }
1340 }
1341 thawn_foundations
1342 }
1343
1344 #[tracing::instrument(
1345 level = "debug",
1346 skip(self),
1347 fields(
1348 checklist_id = self.checklist_id
1349 )
1350 )]
1351 fn generate_checks(&mut self) {
1352 let mut checks = Vec::new();
1353 let mut pairs: Vec<_> = self
1357 .pairs
1358 .iter()
1359 .filter_map(|check| {
1360 if matches!(
1361 check.state(),
1362 CandidatePairState::Waiting | CandidatePairState::Frozen
1363 ) {
1364 Some(check.pair.clone())
1365 } else {
1366 None
1367 }
1368 })
1369 .collect();
1370 let mut redundant_pairs = Vec::new();
1371 let mut turn_checks = Vec::new();
1372
1373 for local in self.local_candidates.iter() {
1374 let turn_client_id = {
1375 trace!("turn clients: {:?}", self.turn_clients);
1376 let turn_client_id = self
1377 .turn_client_by_allocated_address(
1378 local.candidate.transport_type,
1379 local.candidate.base_address,
1380 )
1381 .map(|(id, _client)| id);
1382 if local.candidate.candidate_type == CandidateType::Relayed
1383 && turn_client_id.is_none()
1384 {
1385 warn!("No configured TURN client for candidate: {local:?}, ignoring");
1386 continue;
1387 }
1388 turn_client_id
1389 };
1390 for remote in self.remote_candidates.iter() {
1391 if candidate_can_pair_with(&local.candidate, remote) {
1392 let pair = CandidatePair::new(local.candidate.clone(), remote.clone());
1393 let component_id = self
1394 .component_ids
1395 .iter()
1396 .find(|(id, _state)| id == &local.candidate.component_id)
1397 .unwrap_or_else(|| {
1398 panic!(
1399 "No component {} for local candidate",
1400 local.candidate.component_id
1401 )
1402 });
1403
1404 if let Some(redundant_pair) = pair.redundant_with(pairs.iter()) {
1405 if redundant_pair.remote.candidate_type == CandidateType::PeerReflexive {
1406 match local.variant {
1407 LocalCandidateVariant::Agent(ref agent_id) => {
1408 redundant_pairs.push((
1409 redundant_pair.clone(),
1410 pair,
1411 *agent_id,
1412 component_id,
1413 ));
1414 }
1415 LocalCandidateVariant::TcpActive
1416 | LocalCandidateVariant::TcpListener => {}
1417 }
1418 } else {
1419 }
1421 } else {
1422 if let Some(turn_client_id) = turn_client_id {
1423 turn_checks.push((turn_client_id, pair.clone()));
1424 }
1425 trace!("constructed pair: {pair:?}");
1426 pairs.push(pair.clone());
1427 match local.variant {
1428 LocalCandidateVariant::Agent(ref agent_id) => {
1429 checks.push(ConnCheck::new(
1430 self.checklist_id,
1431 pair.clone(),
1432 *agent_id,
1433 false,
1434 self.controlling,
1435 self.remote_credentials.clone(),
1436 ));
1437 }
1438 LocalCandidateVariant::TcpActive => {
1439 checks.push(ConnCheck::new_tcp(
1440 self.checklist_id,
1441 pair.clone(),
1442 false,
1443 self.controlling,
1444 self.remote_credentials.clone(),
1445 ));
1446 }
1447 LocalCandidateVariant::TcpListener => (), }
1449 }
1451 }
1452 }
1453 }
1454 for (turn_id, pair) in turn_checks {
1472 debug!(
1473 "Adding turn permission for {} using TURN allocation {} {}",
1474 pair.remote.address, pair.local.transport_type, pair.local.base_address
1475 );
1476 self.pending_turn_permissions.push_front((
1477 turn_id,
1478 pair.local.transport_type,
1479 pair.remote.address.ip(),
1480 ));
1481 }
1482
1483 let mut thawn_foundations = if self.trickle_ice {
1484 self.thawn_foundations()
1485 } else {
1486 Vec::new()
1487 };
1488 for mut check in checks {
1489 if self.trickle_ice {
1490 if !thawn_foundations
1494 .iter()
1495 .any(|foundation| check.pair.foundation() == *foundation)
1496 && self.check_has_turn_permission(&check)
1497 {
1498 check.set_state(CandidatePairState::Waiting);
1499 thawn_foundations.push(check.pair.foundation());
1500 } else if self.foundation_has_check_state(
1501 &check.pair.foundation(),
1502 CandidatePairState::Succeeded,
1503 ) {
1504 check.set_state(CandidatePairState::Waiting);
1505 }
1506 }
1507 self.add_check_if_not_duplicate(check);
1508 }
1509 }
1510
1511 fn check_is_equal(check: &ConnCheck, pair: &CandidatePair, nominate: Nominate) -> bool {
1512 candidate_is_same_connection(&check.pair.local, &pair.local)
1513 && candidate_is_same_connection(&check.pair.remote, &pair.remote)
1514 && nominate.eq(&check.nominate)
1515 }
1516
1517 #[tracing::instrument(
1518 level = "trace",
1519 skip(self, pair),
1520 fields(
1521 ttype = ?pair.local.transport_type,
1522 local.base_address = ?pair.local.base_address,
1523 remote.address = ?pair.remote.address,
1524 local.ctype = ?pair.local.candidate_type,
1525 remote.ctype = ?pair.remote.candidate_type,
1526 foundation = %pair.foundation(),
1527 )
1528 )]
1529 fn matching_check_idx(&self, pair: &CandidatePair, nominate: Nominate) -> Option<usize> {
1530 let mut best_index = None;
1531 for (idx, potential) in self
1532 .pairs
1533 .iter()
1534 .enumerate()
1535 .filter(|(_idx, check)| Self::check_is_equal(check, pair, nominate))
1536 {
1537 let best = best_index.get_or_insert(idx);
1538 if *best != idx {
1539 let best_check = &self.pairs[*best];
1540 trace!("comparing current best {best_check:?} with {potential:?}");
1541 if potential.nominate && !best_check.nominate {
1542 trace!("better because of nomination");
1543 *best = idx;
1544 continue;
1545 }
1546 if potential.state.cmp_progression(&best_check.state).is_gt() {
1547 trace!("better because of state");
1548 *best = idx;
1549 continue;
1550 }
1551 }
1552 }
1553 if let Some(idx) = best_index {
1554 trace!("found check {}", self.pairs[idx].conncheck_id);
1555 Some(idx)
1556 } else {
1557 trace!("could not find check");
1558 None
1559 }
1560 }
1561
1562 fn take_matching_check(
1563 &mut self,
1564 pair: &CandidatePair,
1565 nominate: Nominate,
1566 ) -> Option<ConnCheck> {
1567 self.matching_check_idx(pair, nominate)
1568 .and_then(|idx| self.pairs.remove(idx))
1569 }
1570
1571 fn matching_check(&self, pair: &CandidatePair, nominate: Nominate) -> Option<&ConnCheck> {
1572 self.matching_check_idx(pair, nominate)
1573 .map(|idx| &self.pairs[idx])
1574 }
1575
1576 fn add_check_if_not_duplicate(&mut self, check: ConnCheck) -> bool {
1577 if let Some(idx) = self
1578 .pairs
1579 .iter()
1580 .position(|existing| candidate_pair_is_same_connection(&existing.pair, &check.pair))
1581 {
1582 if check.nominate() && !self.pairs[idx].nominate()
1586 || self.pairs[idx].state() == CandidatePairState::Failed
1587 {
1588 let existing = self.pairs.remove(idx).unwrap();
1589 debug!("removing existing check {:?}", existing);
1590 } else {
1591 debug!("not adding duplicate check");
1592 return false;
1593 }
1594 }
1595
1596 self.add_check(check);
1597 true
1598 }
1599
1600 fn add_check(&mut self, check: ConnCheck) {
1601 trace!("adding check {}", check.conncheck_id);
1602
1603 let idx = self
1604 .pairs
1605 .binary_search_by(|existing| {
1606 existing
1607 .pair
1608 .priority(self.controlling)
1609 .cmp(&check.pair.priority(self.controlling))
1610 .reverse()
1611 })
1612 .unwrap_or_else(|x| x);
1613 self.pairs.insert(idx, check);
1614 self.dump_check_state();
1615 }
1616
1617 fn set_controlling(&mut self, controlling: bool) {
1618 self.controlling = controlling;
1619 self.sort_pairs();
1621 }
1622
1623 fn sort_pairs(&mut self) {
1624 self.pairs.make_contiguous().sort_by(|a, b| {
1625 a.pair
1626 .priority(self.controlling)
1627 .cmp(&b.pair.priority(self.controlling))
1628 .reverse()
1629 })
1630 }
1631
1632 #[tracing::instrument(
1633 level = "debug",
1634 skip(self, pair),
1635 fields(
1636 checklist_id = self.checklist_id,
1637 )
1638 )]
1639 fn add_valid(&mut self, conncheck_id: ConnCheckId, pair: &CandidatePair) {
1640 if pair.local.transport_type == TransportType::Tcp
1641 && pair.local.tcp_type == Some(TcpType::Passive)
1642 && pair.local.address.port() == 9
1643 {
1644 warn!("not adding local passive tcp candidate without a valid port");
1645 }
1646 trace!(
1647 ttype = ?pair.local.transport_type,
1648 local.address = ?pair.local.address,
1649 remote.address = ?pair.remote.address,
1650 local.ctype = ?pair.local.candidate_type,
1651 remote.ctype = ?pair.remote.candidate_type,
1652 foundation = %pair.foundation(),
1653 "adding valid {conncheck_id}"
1654 );
1655 self.valid.push(conncheck_id);
1656 }
1657
1658 #[tracing::instrument(
1659 level = "debug",
1660 skip(self),
1661 fields(
1662 checklist_id = self.checklist_id
1663 )
1664 )]
1665 fn remove_valid(&mut self, pair: &CandidatePair) {
1666 let valid_to_remove = self
1667 .valid
1668 .iter()
1669 .filter(|&check_id| {
1670 let Some(check) = self.check_by_id(*check_id) else {
1671 return true;
1672 };
1673 candidate_pair_is_same_connection(&check.pair, pair)
1674 })
1675 .cloned()
1676 .collect::<Vec<_>>();
1677 self.valid
1678 .retain(|check_id| !valid_to_remove.contains(check_id));
1679 }
1680
1681 #[tracing::instrument(
1682 level = "debug",
1683 skip(self),
1684 fields(checklist.id = self.checklist_id)
1685 )]
1686 fn check_for_failure(&mut self) {
1687 if self.state == CheckListState::Completed {
1688 return;
1689 }
1690 if self.local_end_of_candidates && self.remote_end_of_candidates {
1691 debug!("all candidates have arrived");
1692 let mut any_not_failed = false;
1693 for (component_id, state) in self.component_ids.iter_mut() {
1694 if self.pairs.iter().any(|check| {
1695 check.pair.local.component_id == *component_id
1696 && check.state() != CandidatePairState::Failed
1697 }) {
1698 any_not_failed = true;
1699 trace!("component {component_id} has any non-failed check");
1700 } else if *state != ComponentConnectionState::Failed {
1701 *state = ComponentConnectionState::Failed;
1702 self.events.push_front(ConnCheckEvent::ComponentState(
1703 *component_id,
1704 ComponentConnectionState::Failed,
1705 ));
1706 }
1707 }
1708 if !any_not_failed {
1709 self.set_state(CheckListState::Failed);
1710 }
1711 }
1712 }
1713
1714 #[tracing::instrument(
1715 level = "debug",
1716 skip(self, pair),
1717 fields(component.id = pair.local.component_id)
1718 )]
1719 fn nominated_pair(&mut self, pair: &CandidatePair) {
1720 self.dump_check_state();
1721 if let Some(idx) = self.valid.iter().position(|&check_id| {
1722 self.check_by_id(check_id).is_some_and(|check| {
1723 check.nominate && candidate_pair_is_same_connection(&check.pair, pair)
1724 })
1725 }) {
1726 info!(
1727 ttype = ?pair.local.transport_type,
1728 local.address = ?pair.local.address,
1729 remote.address = ?pair.remote.address,
1730 local.ctype = ?pair.local.candidate_type,
1731 remote.ctype = ?pair.remote.candidate_type,
1732 foundation = %pair.foundation(),
1733 "nominated"
1734 );
1735 self.nominated.push(self.valid.remove(idx));
1736 let component_id = self.component_ids.iter().find_map(|(id, _state)| {
1737 if *id == pair.local.component_id {
1738 Some(*id)
1739 } else {
1740 None
1741 }
1742 });
1743 let triggered_to_remove = self
1754 .triggered
1755 .iter()
1756 .filter(|&check_id| {
1757 let Some(check) = self.check_by_id(*check_id) else {
1758 return true;
1759 };
1760 check.pair.local.component_id == pair.local.component_id
1761 })
1762 .cloned()
1763 .collect::<Vec<_>>();
1764 self.triggered
1765 .retain(|check_id| !triggered_to_remove.contains(check_id));
1766 let nominated_ids = self.nominated.clone();
1767 self.pairs.retain(|check| {
1768 if nominated_ids.contains(&check.conncheck_id) {
1769 true
1770 } else {
1771 check.pair.local.component_id != pair.local.component_id
1772 }
1773 });
1774 let all_nominated = self.component_ids.iter().all(|(component_id, _state)| {
1780 self.nominated
1781 .iter()
1782 .filter_map(|&check_id| self.check_by_id(check_id))
1783 .any(|check| check.pair.local.component_id == *component_id)
1784 });
1785 if all_nominated {
1786 info!(
1792 "all {} component/s nominated, setting selected pair/s",
1793 self.component_ids.len()
1794 );
1795 self.nominated.clone().iter().fold(
1796 Vec::new(),
1797 |mut component_ids_selected, &check_id| {
1798 let Some(check) = self.check_by_id(check_id) else {
1799 return component_ids_selected;
1800 };
1801 let check_component_id = check.pair.local.component_id;
1802 if component_ids_selected.contains(&check_component_id) {
1804 return component_ids_selected;
1805 }
1806 if let Some(component_id) = component_id {
1807 let agent_id = check.agent_id().unwrap();
1808 let turn = {
1809 let ret = self
1810 .turn_client_by_allocated_address(
1811 check.pair.local.transport_type,
1812 check.pair.local.base_address,
1813 )
1814 .map(|(_turn_id, client)| SelectedTurn {
1815 transport: client.transport(),
1816 local_addr: client.local_addr(),
1817 remote_addr: client.remote_addr(),
1818 });
1819 if check.pair.local.candidate_type == CandidateType::Relayed {
1820 trace!("turn clients: {:?}", self.turn_clients);
1821 debug_assert!(ret.is_some());
1822 }
1823 ret
1824 };
1825 self.events.push_front(ConnCheckEvent::SelectedPair(
1826 component_id,
1827 Box::new(SelectedPair::new(pair.clone(), agent_id, turn)),
1828 ));
1829 debug!("trying to signal component {:?}", component_id);
1830 self.events.push_front(ConnCheckEvent::ComponentState(
1831 component_id,
1832 ComponentConnectionState::Connected,
1833 ));
1834 }
1835 component_ids_selected.push(check_component_id);
1836 component_ids_selected
1837 },
1838 );
1839 self.set_state(CheckListState::Completed);
1840 }
1841 } else {
1842 warn!("unknown nomination for pair {pair:?}");
1843 }
1844 self.dump_check_state();
1845 }
1846
1847 fn try_nominate(&mut self) {
1848 let retriggered: Vec<_> = self
1849 .component_ids
1850 .iter()
1851 .map(|(component_id, _state)| {
1852 let nominated = self.pairs.iter().find(|check| check.nominate());
1853 nominated.or({
1854 let mut valid: Vec<_> = self
1855 .valid
1856 .iter()
1857 .filter_map(|&check_id| self.check_by_id(check_id))
1858 .filter(|check| {
1859 check.pair.local.component_id == *component_id
1860 && (check.pair.local.transport_type != TransportType::Tcp
1861 || check.pair.local.address.port() != 9)
1862 })
1863 .collect();
1864 valid.sort_by(|check1, check2| {
1865 check1
1866 .pair
1867 .priority(true )
1868 .cmp(&check2.pair.priority(true))
1869 });
1870 if !valid.is_empty() {
1873 Some(valid[0])
1874 } else {
1875 None
1876 }
1877 })
1878 })
1879 .collect();
1880 trace!("retriggered {:?}", retriggered);
1881 if retriggered.iter().all(|pair| pair.is_some()) {
1883 self.dump_check_state();
1884 info!("all components have successful connchecks");
1885 let new_checks = retriggered
1886 .iter()
1887 .filter_map(|check| {
1888 let check = check.as_ref().unwrap(); if check.nominate() {
1890 trace!(
1891 "already have nominate check for component {}",
1892 check.pair.local.component_id
1893 );
1894 None
1895 } else {
1896 let agent_id = check.agent_id().unwrap();
1897 let mut check = ConnCheck::new(
1898 self.checklist_id,
1899 check.pair.clone(),
1900 agent_id,
1901 true,
1902 self.controlling,
1903 self.remote_credentials.clone(),
1904 );
1905 check.set_state(CandidatePairState::Waiting);
1906 debug!("attempting nomination with check {}", check.conncheck_id);
1907 Some(check)
1908 }
1909 })
1910 .collect::<Vec<_>>();
1911 for check in new_checks {
1912 self.add_triggered(&check);
1913 self.add_check(check);
1914 }
1915 }
1916 }
1917
1918 #[tracing::instrument(level = "trace", skip(self))]
1919 fn dump_check_state(&self) {
1920 let mut s = alloc::format!("checklist {}", self.checklist_id);
1921 for pair in self.pairs.iter() {
1922 use core::fmt::Write as _;
1923 let _ = write!(
1924 &mut s,
1925 "\nID:{id} foundation:{foundation} state:{state} nom:{nominate} con:{controlling} priority:{local_pri},{remote_pri} trans:{transport} local:{local_cand_type} {local_addr} remote:{remote_cand_type} {remote_addr}",
1926 id = format_args!("{:<3}", pair.conncheck_id),
1927 foundation = format_args!("{:10}", pair.pair.foundation()),
1928 state = format_args!("{:10}", pair.state()),
1929 nominate = format_args!("{:5}", pair.nominate()),
1930 controlling = format_args!("{:5}", pair.controlling),
1931 local_pri = format_args!("{:10}", pair.pair.local.priority),
1932 remote_pri = format_args!("{:10}", pair.pair.remote.priority),
1933 transport = format_args!("{:4}", pair.pair.local.transport_type),
1934 local_cand_type = format_args!("{:5}", pair.pair.local.candidate_type),
1935 local_addr = format_args!("{:32}", pair.pair.local.base_address),
1936 remote_cand_type = format_args!("{:5}", pair.pair.remote.candidate_type),
1937 remote_addr = format_args!("{:32}", pair.pair.remote.address)
1938 );
1939 }
1940 debug!("{}", s);
1941 }
1942
1943 fn check_response_failure(&mut self, conncheck_id: ConnCheckId) {
1944 let conncheck = self.mut_check_by_id(conncheck_id).unwrap();
1945 warn!("conncheck failure for id {conncheck_id}");
1946 conncheck.set_state(CandidatePairState::Failed);
1947 let pair = conncheck.pair.clone();
1948 if conncheck.nominate() {
1949 self.set_state(CheckListState::Failed);
1950 }
1951 self.remove_valid(&pair);
1952 if self.local_end_of_candidates && self.remote_end_of_candidates {
1953 self.check_for_failure();
1954 }
1955 }
1956
1957 fn mut_check_from_stun_response(
1958 &mut self,
1959 transaction: TransactionId,
1960 _from: SocketAddr,
1961 ) -> Option<&mut ConnCheck> {
1962 self.pairs.iter_mut().find_map(|check| {
1963 check
1964 .stun_request
1965 .filter(|&request| request == transaction)
1966 .map(|_request| check)
1967 })
1968 }
1969
1970 fn find_local_candidate(
1971 &self,
1972 transport: TransportType,
1973 addr: SocketAddr,
1974 ) -> Option<Candidate> {
1975 let f = |candidate: &Candidate| -> bool {
1976 candidate.transport_type == transport && candidate.base_address == addr
1977 };
1978 self.local_candidates
1979 .iter()
1980 .find(|cand| f(&cand.candidate))
1981 .map(|c| c.candidate.clone())
1982 .or_else(|| {
1983 if transport == TransportType::Tcp {
1984 self.pairs
1985 .iter()
1986 .find(|&check| f(&check.pair.local))
1987 .map(|c| c.pair.local.clone())
1988 } else {
1989 None
1990 }
1991 })
1992 }
1993
1994 fn check_cancel(&mut self, check_id: ConnCheckId) {
1995 let Some(check) = self.mut_check_by_id(check_id) else {
1996 return;
1997 };
1998 let Some(agent_id) = check.agent_id() else {
1999 return;
2000 };
2001 let Some(transaction_id) = check.stun_request else {
2002 return;
2003 };
2004 debug!(conncheck.id = *check_id, "cancelling conncheck");
2005 check.set_state(CandidatePairState::Failed);
2006 let Some(agent) = self.mut_agent_by_id(agent_id) else {
2007 return;
2008 };
2009 let Some(mut request) = agent.mut_request_transaction(transaction_id) else {
2010 return;
2011 };
2012 request.cancel();
2013 }
2014
2015 fn check_cancel_retransmissions(&mut self, check_id: ConnCheckId) {
2016 let Some(check) = self.mut_check_by_id(check_id) else {
2017 return;
2018 };
2019 let Some(agent_id) = check.agent_id() else {
2020 return;
2021 };
2022 let Some(transaction_id) = check.stun_request else {
2023 return;
2024 };
2025 debug!(
2026 conncheck.id = *check_id,
2027 "cancelling conncheck retransmissions"
2028 );
2029 let Some(agent) = self.mut_agent_by_id(agent_id) else {
2030 return;
2031 };
2032 let Some(mut request) = agent.mut_request_transaction(transaction_id) else {
2033 return;
2034 };
2035 request.cancel_retransmissions();
2036 }
2037
2038 fn prune_checks_with<F: FnMut(&ConnCheck) -> bool>(
2039 &mut self,
2040 mut precondition: F,
2041 ) -> Vec<ConnCheck> {
2042 let mut i = 0;
2043 let mut ret = Vec::new();
2044 while let Some(check) = self.pairs.get(i) {
2045 if precondition(check) {
2046 ret.push(self.pairs.remove(i).unwrap());
2047 } else {
2048 i += 1;
2049 }
2050 }
2051 ret
2052 }
2053
2054 fn close(&mut self) {
2055 self.state = CheckListState::Failed;
2056 self.component_ids.clear();
2057 self.local_candidates.clear();
2058 self.remote_candidates.clear();
2059 self.triggered.clear();
2060 self.pairs.clear();
2061 self.valid.clear();
2062 self.nominated.clear();
2063 self.pending_turn_permissions.clear();
2064 self.agents.clear();
2065 }
2066}
2067
2068pub struct ConnCheckListSetBuilder {
2070 tie_breaker: u64,
2071 controlling: bool,
2072 trickle_ice: bool,
2073 timing_advance: Duration,
2074 rto: Option<RequestRto>,
2075}
2076
2077impl ConnCheckListSetBuilder {
2078 fn new(tie_breaker: u64, controlling: bool) -> Self {
2079 Self {
2080 tie_breaker,
2081 controlling,
2082 trickle_ice: false,
2083 timing_advance: DEFAULT_MINIMUM_SET_TICK,
2084 rto: None,
2085 }
2086 }
2087
2088 pub fn trickle_ice(mut self, trickle_ice: bool) -> Self {
2090 self.trickle_ice = trickle_ice;
2091 self
2092 }
2093
2094 pub fn timing_advance(mut self, ta: Duration) -> Self {
2100 self.timing_advance = ta;
2101 self
2102 }
2103
2104 pub fn build(self) -> ConnCheckListSet {
2106 ConnCheckListSet {
2107 checklists: Default::default(),
2108 tie_breaker: self.tie_breaker,
2109 controlling: self.controlling,
2110 trickle_ice: self.trickle_ice,
2111 checklist_i: 0,
2112 last_send_time: None,
2113 pending_messages: Default::default(),
2114 pending_transmits: Default::default(),
2115 pending_remove_sockets: Default::default(),
2116 completed: false,
2117 closed: false,
2118 timing_advance: self.timing_advance,
2119 rto: self.rto,
2120 }
2121 }
2122}
2123
2124pub const DEFAULT_MINIMUM_SET_TICK: Duration = Duration::from_millis(50);
2126pub const MIN_TIMING_ADVANCE: Duration = Duration::from_millis(5);
2128
2129#[derive(Debug)]
2131pub struct ConnCheckListSet {
2132 checklists: Vec<ConnCheckList>,
2133 tie_breaker: u64,
2134 controlling: bool,
2135 trickle_ice: bool,
2136 checklist_i: usize,
2137 last_send_time: Option<Instant>,
2138 pending_messages: VecDeque<CheckListSetPendingMessage>,
2139 pending_transmits: VecDeque<CheckListSetTransmit>,
2140 pending_remove_sockets: VecDeque<CheckListSetSocket>,
2141 completed: bool,
2142 closed: bool,
2143 timing_advance: Duration,
2144 rto: Option<RequestRto>,
2145}
2146
2147impl ConnCheckListSet {
2148 pub fn builder(tie_breaker: u64, controlling: bool) -> ConnCheckListSetBuilder {
2152 ConnCheckListSetBuilder::new(tie_breaker, controlling)
2153 }
2154
2155 pub fn new_list(&mut self) -> usize {
2157 let checklist_id = CONN_CHECK_LIST_COUNT.fetch_add(1, Ordering::SeqCst);
2158 let ret = ConnCheckList::new(checklist_id, self.controlling(), self.trickle_ice);
2159 self.checklists.push(ret);
2160 checklist_id
2161 }
2162
2163 pub fn mut_list(&mut self, id: usize) -> Option<&mut ConnCheckList> {
2165 self.checklists.iter_mut().find(|cl| cl.checklist_id == id)
2166 }
2167
2168 pub fn list(&self, id: usize) -> Option<&ConnCheckList> {
2170 self.checklists.iter().find(|cl| cl.checklist_id == id)
2171 }
2172
2173 pub fn controlling(&self) -> bool {
2176 self.controlling
2177 }
2178
2179 pub fn timing_advance(&self) -> Duration {
2185 self.timing_advance
2186 }
2187
2188 pub fn set_timing_advance(&mut self, ta: Duration) {
2194 self.timing_advance = ta.max(MIN_TIMING_ADVANCE);
2195 }
2196
2197 pub fn set_request_retransmits(&mut self, rto: RequestRto) {
2198 for checklist in self.checklists.iter_mut() {
2199 let requests = checklist
2200 .pairs
2201 .iter()
2202 .filter_map(|check| check.agent_id().zip(check.stun_request))
2203 .collect::<Vec<_>>();
2204 for (agent_id, request_id) in requests {
2205 let Some(agent) = checklist.mut_agent_by_id(agent_id) else {
2206 continue;
2207 };
2208 let Some(mut transaction) = agent.mut_request_transaction(request_id) else {
2209 continue;
2210 };
2211 transaction.configure_timeout_with_max(
2212 rto.initial,
2213 rto.retransmits,
2214 rto.final_retransmit_timeout,
2215 rto.max,
2216 );
2217 }
2218 }
2219 self.rto = Some(rto);
2220 }
2221
2222 fn handle_stun<T: AsRef<[u8]>>(
2223 &mut self,
2224 checklist_i: usize,
2225 msg: Message<'_>,
2226 transmit: &Transmit<T>,
2227 agent_id: StunAgentId,
2228 turn_id: Option<(StunAgentId, SocketAddr)>,
2229 ) -> bool {
2230 debug!("received STUN message {msg}");
2231 if msg.is_response() {
2232 match self.checklists[checklist_i]
2233 .stun_auth_remote
2234 .validate_incoming_message(&msg)
2235 {
2236 Ok(Some(_algo)) => {
2237 let Some(agent) = self.checklists[checklist_i].mut_agent_by_id(agent_id) else {
2238 return false;
2239 };
2240 if !agent.handle_stun_message(&msg, transmit.from) {
2241 return false;
2242 }
2243 self.handle_stun_response(checklist_i, &msg, transmit.from);
2244 true
2245 }
2246 _ => false,
2247 }
2248 } else if msg.has_class(MessageClass::Request) {
2249 match self.checklists[checklist_i]
2250 .stun_auth_local
2251 .validate_incoming_message(&msg)
2252 {
2253 Ok(Some(_algo)) => {
2254 if !msg.has_method(BINDING) {
2255 return false;
2256 }
2257 let Some(local_cand) = self.checklists[checklist_i]
2258 .find_local_candidate(transmit.transport, transmit.to)
2259 else {
2260 warn!("Could not find local candidate for incoming data");
2261 trace!(
2262 "local candidates: {:?}",
2263 self.checklists[checklist_i].local_candidates
2264 );
2265 return false;
2266 };
2267
2268 let checklist_id = self.checklists[checklist_i].checklist_id;
2269 let response = self.handle_binding_request(
2270 checklist_i,
2271 &local_cand,
2272 agent_id,
2273 &msg,
2274 transmit.from,
2275 );
2276 self.pending_messages.push_back(CheckListSetPendingMessage {
2277 checklist_id,
2278 agent_id,
2279 is_request: false,
2280 msg: response.finish(),
2281 to: transmit.from,
2282 turn_id,
2283 });
2284 true
2285 }
2286 Ok(None) => {
2287 warn!("incoming message failed did not have integrity");
2288 let code = ErrorCode::builder(ErrorCode::UNAUTHORIZED).build().unwrap();
2289 let mut response = Message::builder_error(&msg, MessageWriteVec::new());
2290 response.add_attribute(&code).unwrap();
2291 self.pending_messages.push_back(CheckListSetPendingMessage {
2292 checklist_id: self.checklists[checklist_i].checklist_id,
2293 agent_id,
2294 is_request: false,
2295 msg: response.finish(),
2296 to: transmit.from,
2297 turn_id,
2298 });
2299 true
2300 }
2301 Err(e) => {
2302 warn!("incoming message failed integrity check: {e:?}");
2303 let code = ErrorCode::builder(ErrorCode::UNAUTHORIZED).build().unwrap();
2304 let mut response = Message::builder_error(&msg, MessageWriteVec::new());
2305 response.add_attribute(&code).unwrap();
2306 self.pending_messages.push_back(CheckListSetPendingMessage {
2307 checklist_id: self.checklists[checklist_i].checklist_id,
2308 agent_id,
2309 is_request: false,
2310 msg: response.finish(),
2311 to: transmit.from,
2312 turn_id,
2313 });
2314 true
2315 }
2316 }
2317 } else {
2318 false
2319 }
2320 }
2321
2322 #[tracing::instrument(
2323 name = "incoming_data_or_stun",
2324 level = "trace",
2325 skip(self, checklist_i, transmit)
2326 fields(
2327 transport = %transmit.transport,
2328 from = %transmit.from,
2329 to = %transmit.to,
2330 )
2331 )]
2332 fn incoming_data_or_stun<T: AsRef<[u8]> + core::fmt::Debug>(
2333 &mut self,
2334 checklist_i: usize,
2335 component_id: usize,
2336 transmit: Transmit<T>,
2337 turn_client_id: Option<(StunAgentId, SocketAddr)>,
2338 ) -> HandleRecvReply<T> {
2339 if !self.checklists[checklist_i].pending_recv.is_empty() {
2340 panic!("Previous data has not been complete handled yet");
2341 }
2342 let (agent_id, checklist_i) = self.checklists[checklist_i]
2343 .find_agent_for_5tuple(transmit.transport, transmit.to, transmit.from)
2344 .map(|agent| (agent.0, checklist_i))
2345 .unwrap_or_else(|| {
2346 self.checklists
2348 .iter()
2349 .find_map(|checklist| {
2350 checklist
2351 .find_agent_for_5tuple(transmit.transport, transmit.to, transmit.from)
2352 .map(|agent| (agent.0, checklist.checklist_id))
2353 })
2354 .unwrap_or_else(|| {
2355 let (agent_id, _agent_idx) = self.checklists[checklist_i]
2356 .add_agent_for_5tuple(
2357 transmit.transport,
2358 transmit.to,
2359 transmit.from,
2360 None,
2361 );
2362 (agent_id, checklist_i)
2363 })
2364 });
2365
2366 match transmit.transport {
2367 TransportType::Udp => match Message::from_bytes(transmit.data.as_ref()) {
2368 Ok(msg) => {
2369 if self.handle_stun(checklist_i, msg, &transmit, agent_id, turn_client_id) {
2370 return HandleRecvReply {
2371 handled: true,
2372 have_more_data: false,
2373 data: None,
2374 };
2375 }
2376 }
2377 Err(_) => {
2378 if let Some(agent) = self.checklists[checklist_i].agent_by_id(agent_id) {
2379 if agent.is_validated_peer(transmit.from) {
2380 return HandleRecvReply {
2381 handled: false,
2382 have_more_data: false,
2383 data: Some(DataAndRange {
2384 range: 0..transmit.data.as_ref().len(),
2385 data: transmit.data,
2386 }),
2387 };
2388 }
2389 }
2390 }
2391 },
2392 TransportType::Tcp => {
2393 let mut tcp_buffer = self.checklists[checklist_i]
2396 .tcp_buffers
2397 .entry((transmit.to, transmit.from))
2398 .or_default();
2399 tcp_buffer.push_data(transmit.data.as_ref());
2400
2401 let mut handled = false;
2402 let mut have_more_data = false;
2403 loop {
2404 let Some(data) = tcp_buffer.pull_data() else {
2405 break;
2406 };
2407 match Message::from_bytes(&data) {
2408 Ok(msg) => {
2409 if self.handle_stun(
2410 checklist_i,
2411 msg,
2412 &transmit,
2413 agent_id,
2414 turn_client_id,
2415 ) {
2416 handled = true;
2417 }
2418 }
2419 Err(_) => {
2420 let checklist = &mut self.checklists[checklist_i];
2421 if let Some(agent) = checklist.agent_by_id(agent_id) {
2422 if agent.is_validated_peer(transmit.from) {
2423 have_more_data = true;
2424 checklist
2425 .pending_recv
2426 .push_back(PendingRecv { component_id, data });
2427 }
2428 }
2429 }
2430 }
2431 tcp_buffer = self.checklists[checklist_i]
2432 .tcp_buffers
2433 .get_mut(&(transmit.to, transmit.from))
2434 .unwrap();
2435 }
2436 return HandleRecvReply {
2437 handled,
2438 have_more_data,
2439 data: None,
2440 };
2441 }
2442 }
2443 HandleRecvReply {
2444 handled: false,
2445 have_more_data: false,
2446 data: None,
2447 }
2448 }
2449
2450 #[tracing::instrument(
2455 name = "conncheck_incoming_data",
2456 level = "trace",
2457 ret(Display),
2458 skip(self, transmit)
2459 fields(
2460 transport = %transmit.transport,
2461 from = %transmit.from,
2462 to = %transmit.to,
2463 len = transmit.data.as_ref().len(),
2464 )
2465 )]
2466 pub fn incoming_data<T: AsRef<[u8]> + core::fmt::Debug>(
2467 &mut self,
2468 checklist_id: usize,
2469 component_id: usize,
2470 mut transmit: Transmit<T>,
2471 now: Instant,
2472 ) -> HandleRecvReply<T> {
2473 let Some(mut checklist_i) = self
2474 .checklists
2475 .iter()
2476 .position(|cl| cl.checklist_id == checklist_id)
2477 else {
2478 warn!("no such checklist with id {checklist_id}");
2479 return HandleRecvReply::default();
2480 };
2481
2482 let mut turn_client_id = None;
2484 if let Some((turn_id, turn_server_addr, checklist_i2)) = self.checklists[checklist_i]
2485 .find_turn_client_for_5tuple(transmit.transport, transmit.to, transmit.from)
2486 .map(|(id, client)| (id, client.remote_addr(), checklist_i))
2487 .or_else(|| {
2488 self.checklists.iter().find_map(|checklist| {
2489 checklist
2490 .find_turn_client_for_5tuple(transmit.transport, transmit.to, transmit.from)
2491 .map(|(id, client)| (id, client.remote_addr(), checklist_i))
2492 })
2493 })
2494 {
2495 let client = self.checklists[checklist_i]
2496 .mut_turn_client_by_id(turn_id)
2497 .unwrap();
2498 match client.recv(transmit, now) {
2499 TurnRecvRet::Handled => {
2500 trace!("TURN client handled the incoming data");
2502 return HandleRecvReply {
2503 handled: true,
2504 have_more_data: false,
2505 data: None,
2506 };
2507 }
2508 TurnRecvRet::Ignored(ignored) => {
2509 transmit = ignored;
2510 }
2511 TurnRecvRet::PeerData(peer) => {
2512 let turn_client_transport = client.transport();
2513 turn_client_id = Some((turn_id, turn_server_addr));
2514 checklist_i = checklist_i2;
2515 let transmit = Transmit::new(
2517 peer.data(),
2518 peer.transport,
2519 peer.peer,
2520 client.relayed_addresses().next().unwrap().1,
2521 );
2522 let ret = self.incoming_data_or_stun(
2523 checklist_i,
2524 component_id,
2525 transmit,
2526 turn_client_id,
2527 );
2528 if let Some(data) = ret.data.as_ref() {
2529 let checklist = &mut self.checklists[checklist_i];
2530 checklist.pending_recv.push_back(PendingRecv {
2531 component_id,
2532 data: data.as_ref().to_vec(),
2533 });
2534 }
2535 if turn_client_transport != TransportType::Udp {
2536 loop {
2537 let client = self.checklists[checklist_i]
2538 .mut_turn_client_by_id(turn_id)
2539 .unwrap();
2540 let Some(peer) = client.poll_recv(now) else {
2541 break;
2542 };
2543 let transmit = Transmit::new(
2544 peer.data(),
2545 peer.transport,
2546 peer.peer,
2547 client.relayed_addresses().next().unwrap().1,
2548 );
2549 let ret = self.incoming_data_or_stun(
2550 checklist_i,
2551 component_id,
2552 transmit,
2553 turn_client_id,
2554 );
2555 if let Some(data) = ret.data.as_ref() {
2556 let checklist = &mut self.checklists[checklist_i];
2557 checklist.pending_recv.push_back(PendingRecv {
2558 component_id,
2559 data: data.as_ref().to_vec(),
2560 });
2561 }
2562 }
2563 }
2564 return HandleRecvReply {
2565 handled: ret.handled,
2566 have_more_data: true,
2567 data: None,
2568 };
2569 }
2570 TurnRecvRet::PeerIcmp {
2571 transport,
2572 peer,
2573 icmp_type,
2574 icmp_code,
2575 icmp_data: _,
2576 } => {
2577 debug!(
2578 "conncheck received ICMP(type:{icmp_type:x}, code:{icmp_code:x}) over TURN from {transport}:{peer}"
2579 );
2580 return HandleRecvReply {
2581 handled: true,
2582 have_more_data: false,
2583 data: None,
2584 };
2585 }
2586 }
2587 }
2588
2589 self.incoming_data_or_stun(checklist_i, component_id, transmit, turn_client_id)
2590 }
2591
2592 #[allow(clippy::too_many_arguments)]
2593 fn handle_binding_request(
2594 &mut self,
2595 checklist_i: usize,
2596 local: &Candidate,
2597 agent_id: StunAgentId,
2598 msg: &Message,
2599 from: SocketAddr,
2600 ) -> MessageWriteVec {
2601 let checklist = &mut self.checklists[checklist_i];
2602 trace!("have request {}", msg);
2603
2604 if let Some(error_msg) = Message::check_attribute_types(
2605 msg,
2606 &[
2607 Username::TYPE,
2608 Fingerprint::TYPE,
2609 MessageIntegrity::TYPE,
2610 IceControlled::TYPE,
2611 IceControlling::TYPE,
2612 Priority::TYPE,
2613 UseCandidate::TYPE,
2614 ],
2615 &[
2616 Username::TYPE,
2617 Fingerprint::TYPE,
2618 MessageIntegrity::TYPE,
2619 Priority::TYPE,
2620 ],
2621 MessageWriteVec::new(),
2622 ) {
2623 return error_msg;
2625 }
2626 let peer_nominating = if let Some(use_candidate_raw) = msg.raw_attribute(UseCandidate::TYPE)
2627 {
2628 if UseCandidate::from_raw(use_candidate_raw).is_ok() {
2629 true
2630 } else {
2631 return Message::bad_request(msg, MessageWriteVec::new());
2632 }
2633 } else {
2634 false
2635 };
2636
2637 let priority = match msg.attribute::<Priority>() {
2638 Ok(p) => p.priority(),
2639 Err(_) => {
2640 return Message::bad_request(msg, MessageWriteVec::new());
2641 }
2642 };
2643
2644 let ice_controlling = msg.attribute::<IceControlling>();
2645 let ice_controlled = msg.attribute::<IceControlled>();
2646
2647 if let Ok(username) = msg.attribute::<Username>() {
2649 if !validate_username(username, &checklist.local_credentials) {
2650 warn!("binding request failed username validation -> UNAUTHORIZED");
2651 let mut response = Message::builder_error(msg, MessageWriteVec::new());
2652 let error = ErrorCode::builder(ErrorCode::UNAUTHORIZED).build().unwrap();
2653 response.add_attribute(&error).unwrap();
2654 return response;
2655 }
2656 } else {
2657 return Message::bad_request(msg, MessageWriteVec::new());
2659 }
2660
2661 trace!("checking for role conflicts");
2664 if let Ok(ice_controlling) = ice_controlling {
2665 if self.controlling {
2668 if self.tie_breaker >= ice_controlling.tie_breaker() {
2669 debug!("role conflict detected (controlling=true), returning ROLE_CONFLICT");
2670 let mut response = Message::builder_error(msg, MessageWriteVec::new());
2675 let error = ErrorCode::builder(ErrorCode::ROLE_CONFLICT)
2676 .build()
2677 .unwrap();
2678 response.add_attribute(&error).unwrap();
2679 return response_add_credentials(
2680 response,
2681 &mut self.checklists[checklist_i].stun_auth_local,
2682 )
2683 .unwrap();
2684 } else {
2685 debug!("role conflict detected, updating controlling state to false");
2686 self.controlling = false;
2690 for l in self.checklists.iter_mut() {
2691 l.set_controlling(false);
2692 }
2693 }
2694 }
2695 }
2696 if let Ok(ice_controlled) = ice_controlled {
2697 if !self.controlling {
2700 if self.tie_breaker >= ice_controlled.tie_breaker() {
2701 debug!("role conflict detected, updating controlling state to true");
2702 self.controlling = true;
2706 for l in self.checklists.iter_mut() {
2707 l.set_controlling(true);
2708 }
2709 } else {
2710 debug!("role conflict detected (controlling=false), returning ROLE_CONFLICT");
2711 let mut response = Message::builder_error(msg, MessageWriteVec::new());
2716 let error = ErrorCode::builder(ErrorCode::ROLE_CONFLICT)
2717 .build()
2718 .unwrap();
2719 response.add_attribute(&error).unwrap();
2720 return response_add_credentials(
2721 response,
2722 &mut self.checklists[checklist_i].stun_auth_local,
2723 )
2724 .unwrap();
2725 }
2726 }
2727 }
2728 trace!("checked for role conflicts");
2729 let checklist = &mut self.checklists[checklist_i];
2730 let remote = checklist
2731 .find_remote_candidate(local.component_id, local.transport_type, from)
2732 .unwrap_or_else(|| {
2733 debug!("no existing remote candidate for {from}");
2734 let mut builder = Candidate::builder(
2748 local.component_id,
2749 CandidateType::PeerReflexive,
2750 local.transport_type,
2751 "rflx",
2752 from,
2753 )
2754 .priority(priority);
2755 if local.transport_type == TransportType::Tcp {
2756 builder = builder.tcp_type(pair_tcp_type(local.tcp_type.unwrap()))
2757 }
2758 let cand = builder.build();
2759 debug!("new reflexive remote {:?}", cand);
2760 checklist.add_remote_candidate(cand.clone());
2761 cand
2762 });
2763 trace!("remote candidate {remote:?}");
2764 let pair = CandidatePair::new(local.clone(), remote);
2766 if let Some(mut check) = checklist.take_matching_check(&pair, Nominate::DontCare) {
2767 trace!("found existing {:?} check {:?}", check.state(), check);
2769 match check.state() {
2770 CandidatePairState::Succeeded => {
2773 if peer_nominating && !check.nominate() {
2774 debug!("existing pair succeeded -> nominate");
2775 let pair = check.pair.clone();
2776 let agent_id = check.agent_id().unwrap();
2777 let mut new_check = ConnCheck::new(
2778 checklist.checklist_id,
2779 pair.clone(),
2780 agent_id,
2781 true,
2782 self.controlling,
2783 checklist.remote_credentials.clone(),
2784 );
2785 checklist.add_check(check);
2786 new_check.set_state(CandidatePairState::Waiting);
2787 checklist.add_valid(new_check.conncheck_id, &pair);
2788 checklist.add_triggered(&new_check);
2789 checklist.add_check(new_check);
2790 } else {
2791 checklist.add_check(check);
2792 }
2793 }
2794 CandidatePairState::InProgress => {
2808 let old_check_id = check.conncheck_id;
2809 let pair = check.pair.clone();
2810 let agent_id = check.agent_id().unwrap();
2813 let mut new_check = ConnCheck::new(
2814 checklist.checklist_id,
2815 pair,
2816 agent_id,
2817 peer_nominating,
2818 self.controlling,
2819 checklist.remote_credentials.clone(),
2820 );
2821 checklist.check_cancel_retransmissions(old_check_id);
2822 checklist.add_check(check);
2823 new_check.set_state(CandidatePairState::Waiting);
2824 checklist.add_triggered(&new_check);
2825 checklist.add_check(new_check);
2826 }
2827 CandidatePairState::Waiting
2835 | CandidatePairState::Frozen
2836 | CandidatePairState::Failed => {
2837 let mut old_check_id = None;
2838 if peer_nominating && !check.nominate() {
2839 old_check_id = Some(check.conncheck_id);
2840 check = ConnCheck::new(
2841 checklist.checklist_id,
2842 check.pair.clone(),
2843 agent_id,
2844 peer_nominating,
2845 self.controlling,
2846 checklist.remote_credentials.clone(),
2847 );
2848 }
2849 check.set_state(CandidatePairState::Waiting);
2850 if let Some(old_check_id) = old_check_id {
2851 checklist.check_cancel(old_check_id);
2852 }
2853 checklist.add_triggered(&check);
2854 checklist.add_check(check);
2855 }
2856 }
2857 } else {
2858 debug!("creating new check for pair {:?}", pair);
2859 let mut check = ConnCheck::new(
2860 checklist.checklist_id,
2861 pair,
2862 agent_id,
2863 peer_nominating,
2864 self.controlling,
2865 checklist.remote_credentials.clone(),
2866 );
2867 check.set_state(CandidatePairState::Waiting);
2868 checklist.add_triggered(&check);
2869 checklist.add_check(check);
2870 }
2871
2872 if let Some(agent) = self.checklists[checklist_i].mut_agent_by_id(agent_id) {
2873 agent.validated_peer(from);
2874 }
2875
2876 binding_success_response(msg, from, &mut self.checklists[checklist_i].stun_auth_local)
2877 }
2878
2879 fn check_success(
2880 &mut self,
2881 checklist_i: usize,
2882 conncheck_id: ConnCheckId,
2883 addr: SocketAddr,
2884 controlling: bool,
2885 ) {
2886 let checklist = &mut self.checklists[checklist_i];
2887 let checklist_id = checklist.checklist_id;
2888 checklist.check_cancel_retransmissions(conncheck_id);
2889 let conncheck = checklist.mut_check_by_id(conncheck_id).unwrap();
2890 let conncheck_id = conncheck.conncheck_id;
2891 let nominate = conncheck.nominate();
2892 info!(
2893 component.id = conncheck.pair.local.component_id,
2894 nominate = conncheck.nominate,
2895 ttype = ?conncheck.pair.local.transport_type,
2896 local.base_address = ?conncheck.pair.local.base_address,
2897 remote.address = ?conncheck.pair.remote.address,
2898 local.ctype = ?conncheck.pair.local.candidate_type,
2899 remote.ctype = ?conncheck.pair.remote.candidate_type,
2900 foundation = %conncheck.pair.foundation(),
2901 xor_mapped_address = ?addr,
2902 "succeeded in finding a connection"
2903 );
2904 conncheck.set_state(CandidatePairState::Succeeded);
2905 let pair = conncheck.pair.clone();
2906 let ok_pair = pair_construct_valid(&pair, addr);
2907 let agent_id = conncheck.agent_id().unwrap();
2908 let mut ok_check = ConnCheck::new(
2909 checklist_id,
2910 ok_pair.clone(),
2911 agent_id,
2912 false,
2913 self.controlling,
2914 checklist.remote_credentials.clone(),
2915 );
2916
2917 if checklist.state != CheckListState::Running {
2918 debug!("checklist is not running, ignoring check response");
2919 return;
2920 }
2921
2922 let mut pair_dealt_with = false;
2923 if candidate_pair_is_same_connection(&pair, &ok_pair) {
2928 debug!(existing.id = ?conncheck_id, "found existing check");
2929 let checklist = &mut self.checklists[checklist_i];
2930 checklist.add_valid(conncheck_id, &pair);
2931 if nominate {
2932 checklist.nominated_pair(&pair);
2933 return;
2934 }
2935 pair_dealt_with = true;
2936 } else {
2937 for checklist in self.checklists.iter_mut() {
2943 if let Some(check) = checklist.matching_check(&ok_pair, Nominate::DontCare) {
2944 debug!(
2945 existing.id = *check.conncheck_id,
2946 "found existing check in checklist {}", checklist.checklist_id
2947 );
2948 checklist.add_valid(check.conncheck_id, &pair);
2949 if nominate {
2950 checklist.nominated_pair(&pair);
2951 return;
2952 }
2953 pair_dealt_with = true;
2954 break;
2955 }
2956 }
2957 }
2958 let checklist = &mut self.checklists[checklist_i];
2959 if !pair_dealt_with {
2975 debug!("no existing check");
2976 ok_check.set_state(CandidatePairState::Succeeded);
2979 let ok_id = ok_check.conncheck_id;
2980 if checklist.add_check_if_not_duplicate(ok_check) {
2981 checklist.add_valid(ok_id, &ok_pair);
2982 }
2983 checklist.add_valid(conncheck_id, &pair);
2984
2985 if nominate {
2986 checklist.nominated_pair(&pair);
2987 return;
2988 }
2989 }
2990 if controlling {
2992 checklist.try_nominate();
2993 }
2994 }
2995
2996 #[tracing::instrument(
2997 skip(self, response),
2998 fields(
2999 checklist_id = self.checklists[checklist_i].checklist_id,
3000 ),
3001 )]
3002 fn handle_stun_response(&mut self, checklist_i: usize, response: &Message, from: SocketAddr) {
3003 let checklist = &mut self.checklists[checklist_i];
3004 let checklist_id = checklist.checklist_id;
3005 let conncheck = checklist.mut_check_from_stun_response(response.transaction_id(), from);
3007 let conncheck = match conncheck {
3008 Some(conncheck) => conncheck,
3009 None => {
3010 checklist.dump_check_state();
3011 warn!("No existing check available, ignoring");
3012 return;
3013 }
3014 };
3015 let conncheck_id = conncheck.conncheck_id;
3016
3017 if from != conncheck.pair.remote.address {
3020 warn!(
3021 "response came from different ip {:?} than candidate {:?}",
3022 from, conncheck.pair.remote.address
3023 );
3024 checklist.check_response_failure(conncheck_id);
3025 return;
3026 }
3027
3028 if response.has_class(MessageClass::Error) {
3030 if let Ok(err) = response.attribute::<ErrorCode>() {
3031 if err.code() == ErrorCode::ROLE_CONFLICT {
3032 info!("Role conflict received {}", response);
3033 let new_role = !conncheck.controlling;
3034 info!(
3035 old_role = self.controlling,
3036 new_role, "Role Conflict changing controlling from"
3037 );
3038 if self.controlling != new_role {
3039 let old_pair = conncheck.pair.clone();
3040 let old_conncheck_id = conncheck.conncheck_id;
3041 self.controlling = new_role;
3042 let agent_id = conncheck.agent_id().unwrap();
3043 let mut conncheck = ConnCheck::new(
3044 checklist_id,
3045 conncheck.pair.clone(),
3046 agent_id,
3047 false,
3048 self.controlling,
3049 checklist.remote_credentials.clone(),
3050 );
3051 conncheck.set_state(CandidatePairState::Waiting);
3052 checklist.check_cancel(old_conncheck_id);
3053 checklist.add_triggered(&conncheck);
3054 checklist.add_check(conncheck);
3055 self.checklists[checklist_i].remove_valid(&old_pair);
3056 }
3057 return;
3058 }
3059 }
3060 warn!("error response {}", response);
3062 self.checklists[checklist_i].check_response_failure(conncheck_id);
3063 }
3064
3065 if let Ok(xor) = response.attribute::<XorMappedAddress>() {
3066 let xor_addr = xor.addr(response.transaction_id());
3067 return self.check_success(checklist_i, conncheck_id, xor_addr, self.controlling);
3068 }
3069
3070 self.checklists[checklist_i].check_response_failure(conncheck_id);
3071 }
3072
3073 fn perform_conncheck(
3074 &mut self,
3075 checklist_i: usize,
3076 conncheck_id: ConnCheckId,
3077 now: Instant,
3078 ) -> Result<Option<CheckListSetSocket>, StunError> {
3079 let checklist_id = self.checklists[self.checklist_i].checklist_id;
3080 let checklist = &mut self.checklists[checklist_i];
3081 let local_credentials = checklist.local_credentials.clone();
3082 let remote_credentials = checklist.remote_credentials.clone();
3083
3084 let conncheck = checklist.mut_check_by_id(conncheck_id).unwrap();
3085 let turn_id = {
3086 let transport = conncheck.pair.local.transport_type;
3087 let base_addr = conncheck.pair.local.base_address;
3088 checklist
3089 .turn_client_by_allocated_address(transport, base_addr)
3090 .map(|(id, client)| (id, client.remote_addr()))
3091 };
3092 let conncheck = checklist.mut_check_by_id(conncheck_id).unwrap();
3093 let component_id = conncheck.pair.local.component_id;
3094 for (cid, state) in checklist.component_ids.iter_mut() {
3095 if *cid == component_id
3096 && [
3097 ComponentConnectionState::New,
3098 ComponentConnectionState::Failed,
3099 ]
3100 .contains(state)
3101 {
3102 *state = ComponentConnectionState::Connecting;
3103 checklist.events.push_front(ConnCheckEvent::ComponentState(
3104 component_id,
3105 ComponentConnectionState::Connecting,
3106 ));
3107 }
3108 }
3109 let conncheck = checklist.mut_check_by_id(conncheck_id).unwrap();
3110
3111 debug!("starting connectivity check {}", conncheck.conncheck_id);
3112 if conncheck.stun_request.is_some() {
3113 panic!("Attempt was made to start an already started check");
3114 }
3115
3116 let agent_id = match &conncheck.variant {
3117 ConnCheckVariant::Tcp(_tcp) => {
3118 if let Some((turn_id, turn_addr)) = turn_id {
3119 let relayed_addr = conncheck.pair.local.base_address;
3120 let remote_addr = conncheck.pair.remote.address;
3121 let conncheck_id = conncheck.conncheck_id;
3122 checklist.pending_turn_tcp_connect.push(PendingTurnTcp {
3123 turn_id,
3124 conncheck_id,
3125 relayed_addr,
3126 turn_addr,
3127 peer_addr: remote_addr,
3128 turn_connect_id: None,
3129 allocated: false,
3130 });
3131 let Some(client) = checklist.mut_turn_client_by_id(turn_id) else {
3132 checklist.pending_turn_tcp_connect.pop();
3133 return Ok(None);
3134 };
3135 client.tcp_connect(remote_addr, now).unwrap();
3136 return Ok(None);
3137 } else {
3138 return Ok(Some(CheckListSetSocket {
3139 checklist_id,
3140 component_id: conncheck.pair.local.component_id,
3141 transport: TransportType::Tcp,
3142 local_addr: conncheck.pair.local.base_address,
3143 remote_addr: conncheck.pair.remote.address,
3144 }));
3145 }
3146 }
3147 ConnCheckVariant::Agent(agent_id) => agent_id,
3148 };
3149
3150 let stun_request = ConnCheck::generate_stun_request(
3151 &conncheck.pair,
3152 conncheck.nominate,
3153 self.controlling,
3154 self.tie_breaker,
3155 local_credentials,
3156 remote_credentials,
3157 )
3158 .unwrap();
3159 conncheck.stun_request = Some(stun_request.transaction_id());
3160 conncheck.controlling = self.controlling;
3161 let remote_addr = conncheck.pair.remote.address;
3162
3163 self.pending_messages
3164 .push_front(CheckListSetPendingMessage {
3165 checklist_id,
3166 agent_id: *agent_id,
3167 turn_id,
3168 is_request: true,
3169 msg: stun_request.finish(),
3170 to: remote_addr,
3171 });
3172 Ok(None)
3173 }
3174
3175 #[tracing::instrument(
3176 level = "info",
3177 ret,
3178 skip(self),
3179 fields(
3180 checklist_id = self.checklists[self.checklist_i].checklist_id,
3181 ),
3182 )]
3183 fn next_check(&mut self) -> Option<ConnCheckId> {
3185 let checklist = &mut self.checklists[self.checklist_i];
3186 {
3187 if checklist.state != CheckListState::Running {
3188 return None;
3190 }
3191 checklist.dump_check_state();
3192 }
3193
3194 if let Some(check) = checklist.next_triggered() {
3200 trace!("next check was a triggered check {:?}", check);
3201 Some(check.conncheck_id)
3202 } else if let Some(check) = checklist.next_waiting() {
3209 trace!("next check was a waiting check {:?}", check);
3210 Some(check.conncheck_id)
3211 } else {
3212 let mut foundations_not_waiting_in_progress = BTreeSet::new();
3222 for checklist in self.checklists.iter() {
3223 for f in checklist.foundations() {
3224 if self
3225 .checklists
3226 .iter()
3227 .all(|checklist| checklist.foundation_not_waiting_in_progress(&f))
3228 {
3229 foundations_not_waiting_in_progress.insert(f);
3230 }
3231 }
3232 }
3233 trace!(
3234 "current foundations not waiting or in progress: {:?}",
3235 foundations_not_waiting_in_progress
3236 );
3237
3238 let mut foundations_check_added = BTreeSet::new();
3239 for checklist in self.checklists.iter_mut() {
3240 for check in checklist.pairs.iter_mut() {
3241 if check.state() != CandidatePairState::Frozen {
3242 continue;
3243 }
3244 if !foundations_not_waiting_in_progress
3245 .iter()
3246 .any(|f| f == &check.pair.foundation())
3247 {
3248 continue;
3249 }
3250 if foundations_check_added
3251 .iter()
3252 .any(|f| f == &check.pair.foundation())
3253 {
3254 continue;
3255 }
3256 check.set_state(CandidatePairState::Waiting);
3257 foundations_check_added.insert(check.pair.foundation());
3258 }
3259 }
3260
3261 let checklist = &mut self.checklists[self.checklist_i];
3262 if let Some(check) = checklist.next_waiting() {
3263 trace!("next check was a frozen check {:?}", check);
3264 check.set_state(CandidatePairState::InProgress);
3265 Some(check.conncheck_id)
3266 } else {
3267 trace!("no next check for stream");
3269 None
3270 }
3271 }
3272 }
3273
3274 fn remove_check_resources(&mut self, checklist_i: usize, check: ConnCheck, now: Instant) {
3275 let ConnCheckVariant::Agent(check_agent_id) = check.variant else {
3276 return;
3277 };
3278 let checklist = &mut self.checklists[checklist_i];
3279 let checklist_id = checklist.checklist_id;
3280 if checklist.pairs.iter().any(|pair| {
3281 if let ConnCheckVariant::Agent(agent_id) = pair.variant {
3282 agent_id == check_agent_id
3283 } else {
3284 false
3285 }
3286 }) {
3287 return;
3288 }
3289
3290 let Some(agent) = checklist.agent_by_id(check_agent_id) else {
3291 return;
3292 };
3293
3294 let transport = agent.transport();
3295 let local_addr = agent.local_addr();
3296 let remote_addr = agent.remote_addr();
3297 debug!("found agent {transport}: {local_addr} -> {remote_addr:?} to maybe remove");
3298
3299 let base_addr = check.pair.local.base_address;
3300
3301 if let Some((turn_id, _turn_client)) =
3302 checklist.mut_turn_client_by_allocated_address(transport, base_addr)
3303 {
3304 if self.checklists.iter().any(|checklist| {
3305 checklist.pairs.iter().any(|pair| {
3306 pair.pair.local.candidate_type == CandidateType::Relayed
3307 && pair.pair.local.base_address == base_addr
3308 })
3309 }) {
3310 warn!(
3312 "should remove {transport} permission from {local_addr} to {}",
3313 check.pair.remote.address.ip()
3314 );
3315 return;
3316 }
3317 let checklist = &mut self.checklists[checklist_i];
3318 let mut turn_client = checklist.remove_turn_client_by_id(turn_id).unwrap();
3319 let _ = turn_client.delete(now);
3320 let checklist = &mut self.checklists[checklist_i];
3321 checklist.pending_delete_turn_clients.push(CheckTurnClient {
3322 id: turn_id,
3323 client: turn_client,
3324 local_tcp_sockets: Default::default(),
3325 });
3326 return;
3328 }
3329 let checklist = &mut self.checklists[checklist_i];
3330 if checklist
3331 .turn_clients
3332 .iter()
3333 .chain(checklist.pending_delete_turn_clients.iter())
3334 .any(|client| {
3335 client.client.transport() == transport
3336 && client.client.local_addr() == local_addr
3337 && if transport == TransportType::Tcp {
3338 remote_addr == Some(client.client.remote_addr())
3339 } else {
3340 true
3341 }
3342 })
3343 {
3344 return;
3345 }
3346 match transport {
3347 TransportType::Udp => {
3348 self.pending_remove_sockets.push_back(CheckListSetSocket {
3349 checklist_id,
3350 component_id: check.pair.local.component_id,
3351 transport,
3352 local_addr,
3353 remote_addr: "0.0.0.0:0".parse().unwrap(),
3354 });
3355 }
3356 TransportType::Tcp => {
3357 self.pending_remove_sockets.push_back(CheckListSetSocket {
3358 checklist_id,
3359 component_id: check.pair.local.component_id,
3360 transport,
3361 local_addr,
3362 remote_addr: remote_addr.unwrap(),
3363 });
3364 }
3365 }
3366 }
3367
3368 fn maybe_remove_sockets(&mut self, checklist_i: usize, now: Instant) {
3369 let checklist = &mut self.checklists[checklist_i];
3370 for failed in checklist.prune_checks_with(|check| check.state == CandidatePairState::Failed)
3371 {
3372 self.remove_check_resources(checklist_i, failed, now);
3373 }
3374 }
3375
3376 #[tracing::instrument(name = "check_set_poll", level = "debug", ret, skip(self))]
3379 pub fn poll(&mut self, now: Instant) -> CheckListSetPollRet {
3380 if !self.pending_transmits.is_empty() || !self.pending_messages.is_empty() {
3381 trace!("have pending transmits/messages");
3382 return CheckListSetPollRet::WaitUntil(now);
3383 }
3384
3385 let mut n_running = 0;
3386 let mut all_failed = true;
3387 let mut all_turn_closed = self.closed;
3388 let start_idx = self.checklist_i;
3389 loop {
3390 let mut lowest_wait = now + Duration::from_secs(99999);
3391 if self.checklists.is_empty() {
3392 if self.closed {
3393 return CheckListSetPollRet::Closed;
3394 }
3395 return CheckListSetPollRet::WaitUntil(lowest_wait);
3396 }
3397 self.checklist_i += 1;
3398 if self.checklist_i >= self.checklists.len() {
3399 self.checklist_i = 0;
3400 }
3401
3402 let checklist = &mut self.checklists[self.checklist_i];
3403 while let Some((turn_id, transport, remote_ip)) =
3404 checklist.pending_turn_permissions.pop_back()
3405 {
3406 trace!(
3407 "have pending turn permission for id {turn_id:?}, {transport:?}, {remote_ip}"
3408 );
3409 let Some(client) = checklist.mut_turn_client_by_id(turn_id) else {
3410 continue;
3411 };
3412
3413 if let Err(e) = client.create_permission(transport, remote_ip, now) {
3414 warn!(
3415 "received error trying to create a permission to {:?}: {e}",
3416 remote_ip
3417 );
3418 }
3419 }
3420
3421 let checklist_id = checklist.checklist_id;
3422 for idx in 0..checklist.turn_clients.len() {
3423 let client = &mut checklist.turn_clients[idx];
3424 let turn_id = client.id;
3425 while let Some(event) = client.client.poll_event() {
3426 match event {
3427 TurnEvent::AllocationCreated(_, _) => (),
3428 TurnEvent::AllocationCreateFailed(_family) => (),
3429 TurnEvent::PermissionCreated(transport, peer_addr) => {
3430 for idx in 0..checklist.pairs.len() {
3431 let check = &mut checklist.pairs[idx];
3432 if check.pair.local.candidate_type != CandidateType::Relayed
3433 || check.pair.remote.address.ip() != peer_addr
3434 || check.pair.local.transport_type != transport
3435 || !matches!(
3436 check.state,
3437 CandidatePairState::Failed | CandidatePairState::Succeeded
3438 )
3439 {
3440 continue;
3441 }
3442 }
3443 }
3444 TurnEvent::PermissionCreateFailed(transport, peer_addr) => {
3445 for idx in 0..checklist.pairs.len() {
3446 let check = &mut checklist.pairs[idx];
3447 if check.pair.local.candidate_type != CandidateType::Relayed
3448 || check.pair.remote.address.ip() != peer_addr
3449 || check.pair.local.transport_type != transport
3450 {
3451 continue;
3452 }
3453 check.set_state(CandidatePairState::Failed);
3454 }
3455 }
3456 TurnEvent::ChannelCreated(_transport, _peer_addr) => (),
3457 TurnEvent::ChannelCreateFailed(_transport, _addr) => (),
3458 TurnEvent::TcpConnected(peer_addr) => {
3459 let Some(idx) =
3460 checklist
3461 .pending_turn_tcp_connect
3462 .iter()
3463 .position(|pending| {
3464 pending.peer_addr == peer_addr && pending.turn_id == turn_id
3465 })
3466 else {
3467 continue;
3468 };
3469 let pending = checklist.pending_turn_tcp_connect.swap_remove(idx);
3470 let local_credentials = checklist.local_credentials.clone();
3471 let remote_credentials = checklist.remote_credentials.clone();
3472 let Some(conncheck) = checklist
3473 .pairs
3474 .iter_mut()
3475 .find(|check| check.conncheck_id == pending.conncheck_id)
3476 else {
3477 continue;
3478 };
3479 let agent_id = if let Some(local_agent) =
3480 checklist.agents.iter_mut().find(|a| {
3481 a.agent.transport() == TransportType::Tcp
3482 && a.agent.local_addr() == pending.relayed_addr
3483 && a.agent.remote_addr().unwrap() == pending.peer_addr
3484 }) {
3485 local_agent.id
3486 } else {
3487 let agent =
3488 StunAgent::builder(TransportType::Tcp, pending.relayed_addr)
3489 .remote_addr(pending.peer_addr)
3490 .build();
3491 let agent_id = StunAgentId::generate();
3492 checklist.agents.push(CheckStunAgent {
3493 id: agent_id,
3494 agent,
3495 turn_id: Some(turn_id),
3496 });
3497 agent_id
3498 };
3499 conncheck.variant = ConnCheckVariant::Agent(agent_id);
3500
3501 let stun_request = ConnCheck::generate_stun_request(
3502 &conncheck.pair,
3503 conncheck.nominate,
3504 self.controlling,
3505 self.tie_breaker,
3506 local_credentials,
3507 remote_credentials,
3508 )
3509 .unwrap();
3510 conncheck.stun_request = Some(stun_request.transaction_id());
3511 conncheck.controlling = self.controlling;
3512 self.pending_messages
3513 .push_front(CheckListSetPendingMessage {
3514 checklist_id,
3515 agent_id,
3516 is_request: true,
3517 msg: stun_request.finish(),
3518 turn_id: Some((pending.turn_id, pending.turn_addr)),
3519 to: pending.peer_addr,
3520 });
3521 }
3522 TurnEvent::TcpConnectFailed(peer_addr) => {
3523 let Some(idx) = checklist
3524 .pending_turn_tcp_connect
3525 .iter()
3526 .position(|pending| pending.peer_addr == peer_addr)
3527 else {
3528 continue;
3529 };
3530 let _pending = checklist.pending_turn_tcp_connect.swap_remove(idx);
3531 checklist
3532 .pairs
3533 .retain(|check| check.pair.remote.address != peer_addr);
3534 }
3535 }
3536 }
3537
3538 match client.client.poll(now) {
3539 TurnPollRet::Closed => (),
3540 TurnPollRet::WaitUntil(wait) => {
3541 all_turn_closed = false;
3542 if wait == now {
3543 return CheckListSetPollRet::WaitUntil(
3544 wait.max(
3545 self.last_send_time
3546 .map(|last_send| last_send + self.timing_advance)
3547 .unwrap_or(now),
3548 ),
3549 );
3550 }
3551 if wait < lowest_wait {
3552 lowest_wait = wait.max(
3553 self.last_send_time
3554 .map(|last_send| last_send + self.timing_advance)
3555 .unwrap_or(now),
3556 );
3557 }
3558 }
3559 TurnPollRet::TcpClose {
3560 local_addr,
3561 remote_addr,
3562 } => {
3563 return CheckListSetPollRet::RemoveSocket {
3564 checklist_id,
3565 component_id: 1,
3567 transport: client.client.transport(),
3568 local_addr,
3569 remote_addr,
3570 };
3571 }
3572 TurnPollRet::AllocateTcpSocket {
3573 id,
3574 socket,
3575 peer_addr,
3576 } => {
3577 let Some(pending) =
3578 checklist
3579 .pending_turn_tcp_connect
3580 .iter_mut()
3581 .find(|pending| {
3582 pending.turn_id == turn_id
3583 && pending.peer_addr == peer_addr
3584 && pending.turn_addr == socket.to
3585 })
3586 else {
3587 continue;
3588 };
3589 pending.turn_connect_id = Some(id);
3590 return CheckListSetPollRet::AllocateSocket {
3591 checklist_id,
3592 component_id: 1,
3593 transport: socket.transport,
3594 local_addr: socket.from,
3595 remote_addr: socket.to,
3596 };
3597 }
3598 }
3599 }
3600 let mut idx = 0;
3601 while let Some(client) = checklist.pending_delete_turn_clients.get_mut(idx) {
3602 match client.client.poll(now) {
3603 TurnPollRet::Closed => {
3604 let client = checklist.pending_delete_turn_clients.remove(idx).client;
3605 let transport = client.transport();
3606 if checklist
3607 .find_agent_for_5tuple(
3608 transport,
3609 client.local_addr(),
3610 client.remote_addr(),
3611 )
3612 .is_none()
3613 {
3614 return CheckListSetPollRet::RemoveSocket {
3615 checklist_id,
3616 component_id: 1,
3618 transport,
3619 local_addr: client.local_addr(),
3620 remote_addr: client.remote_addr(),
3621 };
3622 }
3623 continue;
3624 }
3625 TurnPollRet::WaitUntil(wait) => {
3626 all_turn_closed = false;
3627 if wait == now {
3628 return CheckListSetPollRet::WaitUntil(
3629 wait.max(
3630 self.last_send_time
3631 .map(|last_send| last_send + self.timing_advance)
3632 .unwrap_or(now),
3633 ),
3634 );
3635 }
3636 if wait < lowest_wait {
3637 lowest_wait = wait.max(
3638 self.last_send_time
3639 .map(|last_send| last_send + self.timing_advance)
3640 .unwrap_or(now),
3641 );
3642 }
3643 }
3644 TurnPollRet::TcpClose {
3645 local_addr,
3646 remote_addr,
3647 } => {
3648 return CheckListSetPollRet::RemoveSocket {
3649 checklist_id: checklist.checklist_id,
3650 component_id: 1,
3652 transport: client.client.transport(),
3653 local_addr,
3654 remote_addr,
3655 };
3656 }
3657 TurnPollRet::AllocateTcpSocket {
3659 id: _,
3660 socket: _,
3661 peer_addr: _,
3662 } => continue,
3663 }
3664 idx += 1;
3665 }
3666
3667 if let Some(event) = checklist.poll_event() {
3668 if matches!(event, ConnCheckEvent::SelectedPair(_, _)) {
3669 self.maybe_remove_sockets(self.checklist_i, now);
3670 }
3671 return CheckListSetPollRet::Event {
3672 checklist_id,
3673 event,
3674 };
3675 }
3676
3677 let checklist_state = checklist.state();
3678 if checklist_state == CheckListState::Running {
3679 n_running += 1;
3680 for idx in 0..checklist.pairs.len() {
3681 let check = &mut checklist.pairs[idx];
3682 if check.state != CandidatePairState::InProgress {
3683 continue;
3684 }
3685 let conncheck_id = check.conncheck_id;
3686 if let Some(agent_id) = check.agent_id() {
3687 if let Some(agent) = checklist.mut_agent_by_id(agent_id) {
3688 trace!("polling existing stun request for check {conncheck_id}");
3689 match agent.poll(now) {
3690 StunAgentPollRet::TransactionTimedOut(_request) => {
3691 checklist.check_cancel_retransmissions(conncheck_id);
3692 let check = &mut checklist.pairs[idx];
3693 check.set_state(CandidatePairState::Failed);
3694 }
3695 StunAgentPollRet::TransactionCancelled(_request) => {
3696 checklist.check_cancel_retransmissions(conncheck_id);
3697 let check = &mut checklist.pairs[idx];
3698 check.set_state(CandidatePairState::Failed);
3699 }
3700 StunAgentPollRet::WaitUntil(wait) => {
3701 if wait < lowest_wait {
3702 trace!("stun poll ret {wait:?}");
3703 lowest_wait = wait.max(
3704 self.last_send_time
3705 .map(|last_send| last_send + self.timing_advance)
3706 .unwrap_or(now),
3707 );
3708 }
3709 }
3710 }
3711 } else if let Some(client) = checklist.mut_turn_client_by_id(agent_id) {
3712 match client.poll(now) {
3713 TurnPollRet::WaitUntil(wait) => {
3714 if wait < lowest_wait {
3715 lowest_wait = wait.max(
3716 self.last_send_time
3717 .map(|last_send| last_send + self.timing_advance)
3718 .unwrap_or(now),
3719 );
3720 }
3721 }
3722 TurnPollRet::Closed => (),
3723 TurnPollRet::TcpClose {
3724 local_addr,
3725 remote_addr,
3726 } => {
3727 return CheckListSetPollRet::RemoveSocket {
3728 checklist_id,
3729 component_id: 1,
3731 transport: client.transport(),
3732 local_addr,
3733 remote_addr,
3734 };
3735 }
3736 TurnPollRet::AllocateTcpSocket {
3737 id: _,
3738 socket: _,
3739 peer_addr: _,
3740 } => unimplemented!(),
3741 }
3742 } else {
3743 unreachable!();
3744 }
3745 }
3746 }
3747 trace!("last send time {:?}", self.last_send_time);
3748 if let Some(last_send) = self.last_send_time {
3749 if last_send + self.timing_advance > now {
3750 trace!("last send time too close to the past, waiting");
3751 return CheckListSetPollRet::WaitUntil(last_send + self.timing_advance);
3752 }
3753 }
3754 }
3755 checklist.check_for_failure();
3756 trace!(
3757 "checklist id:{} state: {:?}",
3758 checklist_id,
3759 checklist.state()
3760 );
3761 if checklist.state() == CheckListState::Failed {
3762 if checklist_state == CheckListState::Running {
3763 n_running -= 1;
3764 }
3765 } else {
3766 all_failed = false;
3767 }
3768
3769 let conncheck_id = match self.next_check() {
3770 Some(c) => c,
3771 None => {
3772 if start_idx == self.checklist_i {
3773 debug!(
3774 "nothing to do yet n-running:{n_running} completed:{} all-failed:{all_failed} turn-closed:{all_turn_closed}",
3775 self.completed
3776 );
3777 if n_running == 0 && !self.completed {
3780 self.completed = true;
3781 return CheckListSetPollRet::Completed;
3782 } else if let Some(remove) = self.pending_remove_sockets.pop_front() {
3783 return remove.into_remove();
3784 } else if all_failed && all_turn_closed {
3785 return CheckListSetPollRet::Closed;
3786 } else {
3787 return CheckListSetPollRet::WaitUntil(lowest_wait);
3788 }
3789 } else {
3790 continue;
3791 }
3792 }
3793 };
3794
3795 trace!("starting conncheck");
3796 match self.perform_conncheck(self.checklist_i, conncheck_id, now) {
3797 Ok(Some(socket)) => return socket.into_allocate(),
3798 Ok(None) => {
3799 let checklist = &mut self.checklists[self.checklist_i];
3800 if let Some(event) = checklist.poll_event() {
3801 let checklist_id = checklist.checklist_id;
3802 if matches!(event, ConnCheckEvent::SelectedPair(_, _)) {
3803 self.maybe_remove_sockets(self.checklist_i, now);
3804 }
3805 return CheckListSetPollRet::Event {
3806 checklist_id,
3807 event,
3808 };
3809 } else {
3810 return CheckListSetPollRet::WaitUntil(now);
3811 }
3812 }
3813 Err(e) => warn!("failed to perform check: {e:?}"),
3814 }
3815 }
3816 }
3817
3818 #[tracing::instrument(name = "check_set_poll_transmit", level = "trace", skip(self))]
3819 pub fn poll_transmit(&mut self, now: Instant) -> Option<CheckListSetTransmit> {
3820 if let Some(pending) = self.pending_transmits.pop_back() {
3821 trace!(
3822 "pending {} {} -> {} transmit of {} bytes",
3823 pending.transmit.transport,
3824 pending.transmit.from,
3825 pending.transmit.to,
3826 pending.transmit.data.len()
3827 );
3828 return Some(pending);
3829 }
3830
3831 let rto = self.rto.clone();
3832 while let Some(pending) = self.pending_messages.pop_back() {
3833 let Some(checklist) = self.mut_list(pending.checklist_id) else {
3834 continue;
3835 };
3836 let Some(agent) = checklist.mut_agent_by_id(pending.agent_id) else {
3837 continue;
3838 };
3839 if pending.is_request {
3840 let hdr = MessageHeader::from_bytes(&pending.msg).unwrap();
3841 debug!(
3842 "Sending request {hdr:?} to {:?} using agent: {:?} and turn id {:?}",
3843 pending.to, pending.agent_id, pending.turn_id
3844 );
3845 match agent.send_request(pending.msg, pending.to, now) {
3846 Ok(transmit) => {
3847 let transport = transmit.transport;
3848 let transmit =
3849 transmit.reinterpret_data(|data| transmit_send(transport, data));
3850 if let Some(rto) = rto.as_ref() {
3851 let mut request = agent
3852 .mut_request_transaction(hdr.transaction_id())
3853 .expect("Just sent request does not exist!");
3854 request.configure_timeout_with_max(
3855 rto.initial,
3856 rto.retransmits,
3857 rto.final_retransmit_timeout,
3858 rto.max,
3859 );
3860 }
3861 if let Some((turn_id, _turn_to)) = pending.turn_id {
3862 let transport = transmit.transport;
3863 let Some(client) = checklist.mut_turn_client_by_id(turn_id) else {
3864 continue;
3865 };
3866 match client.send_to(transport, pending.to, transmit.data, now) {
3867 Ok(transmit) => {
3868 if let Some(transmit) = transmit {
3869 self.last_send_time = Some(now);
3870 return Some(CheckListSetTransmit {
3871 checklist_id: pending.checklist_id,
3872 transmit: transmit_send_build_unframed(transmit),
3873 });
3874 }
3875 }
3876 Err(e) => warn!("error sending: {e}"),
3877 }
3878 } else {
3879 self.last_send_time = Some(now);
3880 return Some(CheckListSetTransmit {
3881 checklist_id: pending.checklist_id,
3882 transmit,
3883 });
3884 }
3885 }
3886 Err(e) => warn!("error sending: {e}"),
3887 }
3888 } else {
3889 debug!("Sending response {:?} to {:?}", pending.msg, pending.to);
3890 match agent.send(pending.msg, pending.to, now) {
3891 Ok(transmit) => {
3892 let transport = transmit.transport;
3893 let transmit =
3894 transmit.reinterpret_data(|data| transmit_send(transport, data));
3895 if let Some((turn_id, _turn_to)) = pending.turn_id {
3896 let Some(client) = checklist.mut_turn_client_by_id(turn_id) else {
3897 continue;
3898 };
3899 match client.send_to(transport, pending.to, transmit.data, now) {
3900 Ok(transmit) => {
3901 if let Some(transmit) = transmit {
3902 self.last_send_time = Some(now);
3903 return Some(CheckListSetTransmit {
3904 checklist_id: pending.checklist_id,
3905 transmit: transmit_send_build_unframed(transmit),
3906 });
3907 }
3908 }
3909 Err(e) => warn!("error sending: {e}"),
3910 }
3911 } else {
3912 self.last_send_time = Some(now);
3913 return Some(CheckListSetTransmit {
3914 checklist_id: pending.checklist_id,
3915 transmit,
3916 });
3917 }
3918 }
3919 Err(e) => warn!("error sending: {e}"),
3920 }
3921 }
3922 }
3923
3924 if self
3925 .last_send_time
3926 .is_some_and(|last_send| last_send + self.timing_advance > now)
3927 {
3928 return None;
3929 }
3930
3931 for checklist_i in 0..self.checklists.len() {
3932 let checklist = &self.checklists[checklist_i];
3933 let checklist_id = checklist.checklist_id;
3934 let agents_len = self.checklists[checklist_i].agents.len();
3935 for check_agent_i in 0..agents_len {
3936 let checklist = &mut self.checklists[checklist_i];
3937 let turn_id = checklist.agents[check_agent_i].turn_id;
3938 if let Some(turn_id) = turn_id {
3939 let check_agent = &mut checklist.agents[check_agent_i];
3940 let Some(transmit) = check_agent.agent.poll_transmit(now) else {
3941 continue;
3942 };
3943 let transmit = transmit.reinterpret_data(|data| data.to_vec());
3944
3945 let transport = transmit.transport;
3946 let client = checklist.mut_turn_client_by_id(turn_id).unwrap();
3947 match client.send_to(transport, transmit.to, transmit.data, now) {
3948 Ok(transmit) => {
3949 if let Some(transmit) = transmit {
3950 self.last_send_time = Some(now);
3951 return Some(CheckListSetTransmit {
3952 checklist_id,
3953 transmit: transmit_send_build_unframed(transmit),
3954 });
3955 }
3956 }
3957 Err(e) => warn!("error sending: {e}"),
3958 }
3959 } else {
3960 let check_agent = &mut checklist.agents[check_agent_i];
3961 let Some(transmit) = check_agent.agent.poll_transmit(now) else {
3962 continue;
3963 };
3964
3965 let transport = transmit.transport;
3966 self.last_send_time = Some(now);
3967 return Some(CheckListSetTransmit {
3968 checklist_id,
3969 transmit: transmit.reinterpret_data(|data| transmit_send(transport, data)),
3970 });
3971 }
3972 }
3973
3974 let checklist = &mut self.checklists[checklist_i];
3975 for client in checklist.turn_clients.iter_mut() {
3976 let Some(transmit) = client.client.poll_transmit(now) else {
3977 continue;
3978 };
3979
3980 self.last_send_time = Some(now);
3981 return Some(CheckListSetTransmit {
3982 checklist_id,
3983 transmit: transmit_send_unframed(transmit),
3984 });
3985 }
3986
3987 for client in checklist.pending_delete_turn_clients.iter_mut() {
3988 let Some(transmit) = client.client.poll_transmit(now) else {
3989 continue;
3990 };
3991
3992 self.last_send_time = Some(now);
3993 return Some(CheckListSetTransmit {
3994 checklist_id,
3995 transmit: transmit_send_unframed(transmit),
3996 });
3997 }
3998 }
3999 None
4000 }
4001
4002 #[tracing::instrument(
4005 level = "debug",
4006 skip(self, checklist_id, component_id),
4007 fields(
4008 checklist.id = checklist_id,
4009 component.id = component_id,
4010 ?local_addr,
4011 )
4012 )]
4013 #[allow(clippy::too_many_arguments)]
4014 pub fn allocated_socket(
4015 &mut self,
4016 checklist_id: usize,
4017 component_id: usize,
4018 transport: TransportType,
4019 from: SocketAddr,
4020 to: SocketAddr,
4021 local_addr: Result<SocketAddr, StunError>,
4022 now: Instant,
4023 ) {
4024 let Some(checklist) = self
4025 .checklists
4026 .iter_mut()
4027 .find(|checklist| checklist.checklist_id == checklist_id)
4028 else {
4029 debug!("no checklist with id {checklist_id}");
4030 return;
4031 };
4032
4033 debug!(
4034 "pending TURN TCP sockets: {:?}",
4035 checklist.pending_turn_tcp_connect
4036 );
4037 if let Some(pending) = checklist
4038 .pending_turn_tcp_connect
4039 .iter_mut()
4040 .find(|pending| {
4041 transport == TransportType::Tcp
4042 && pending.turn_addr == to
4043 && pending.turn_connect_id.is_some()
4044 && !pending.allocated
4045 })
4046 {
4047 debug!("allocated TURN TCP socket");
4048 pending.allocated = true;
4049 let Some(client) = checklist.turn_clients.iter_mut().find_map(|client| {
4050 if pending.turn_id == client.id {
4051 Some(client)
4052 } else {
4053 None
4054 }
4055 }) else {
4056 warn!("no TURN client for allocated socket");
4057 return;
4058 };
4059 let local_addr = local_addr.ok();
4060 client
4061 .client
4062 .allocated_tcp_socket(
4063 pending.turn_connect_id.unwrap(),
4064 Socket5Tuple {
4065 transport: TransportType::Tcp,
4066 from,
4067 to,
4068 },
4069 pending.peer_addr,
4070 local_addr,
4071 now,
4072 )
4073 .unwrap();
4074 if let Some(local_addr) = local_addr {
4075 client.local_tcp_sockets.push(local_addr);
4076 }
4077 return;
4078 }
4079 if checklist.agents.iter().map(|a| &a.agent).any(|a| {
4082 a.transport() == TransportType::Tcp
4083 && a.local_addr() == from
4084 && a.remote_addr() == Some(to)
4085 }) {
4086 panic!("Adding an agent with the same 5-tuple multiple times is not supported");
4087 }
4088
4089 for check in checklist.pairs.iter_mut() {
4090 if check.pair.local.transport_type != TransportType::Tcp {
4091 continue;
4092 }
4093 if check.pair.remote.address != to {
4094 continue;
4095 }
4096 if from != check.pair.local.base_address {
4098 continue;
4099 }
4100 if check.stun_request.is_some() {
4101 continue;
4102 }
4103 if check.pair.local.component_id != component_id {
4104 continue;
4105 }
4106 if check.state != CandidatePairState::InProgress {
4107 continue;
4108 }
4109 trace!("found check with id {} to set agent", check.conncheck_id);
4110 match local_addr {
4111 Ok(local_addr) => {
4112 let mut new_pair = check.pair.clone();
4113 let agent = StunAgent::builder(transport, local_addr)
4114 .remote_addr(check.pair.remote.address)
4115 .build();
4116 new_pair.local.base_address = local_addr;
4118 new_pair.local.address = local_addr;
4119
4120 let Ok(stun_request) = ConnCheck::generate_stun_request(
4121 &new_pair,
4122 check.nominate,
4123 self.controlling,
4124 self.tie_breaker,
4125 checklist.local_credentials.clone(),
4126 checklist.remote_credentials.clone(),
4127 ) else {
4128 warn!("failed to generate stun request for new tcp agent");
4129 return;
4130 };
4131 let transaction_id = stun_request.transaction_id();
4132
4133 let checklist_id = check.checklist_id;
4134 let nominate = check.nominate;
4135 let conncheck_id = check.conncheck_id;
4136
4137 let (agent_id, _agent_idx) = checklist.add_agent(agent, None);
4139 self.pending_messages
4140 .push_front(CheckListSetPendingMessage {
4141 checklist_id,
4142 agent_id,
4143 is_request: true,
4144 msg: stun_request.finish(),
4145 to,
4146 turn_id: None,
4147 });
4148
4149 let mut new_check = ConnCheck::new(
4150 checklist_id,
4151 new_pair.clone(),
4152 agent_id,
4153 nominate,
4154 self.controlling,
4155 checklist.remote_credentials.clone(),
4156 );
4157 let is_triggered = checklist
4158 .triggered
4159 .iter()
4160 .any(|&check_id| conncheck_id == check_id);
4161 new_check.set_state(CandidatePairState::InProgress);
4162 new_check.stun_request = Some(transaction_id);
4163
4164 let old_conncheck_id = conncheck_id;
4165 checklist
4166 .pairs
4167 .retain(|check| check.conncheck_id != old_conncheck_id);
4168 checklist
4169 .triggered
4170 .retain(|&check_id| check_id != old_conncheck_id);
4171 checklist
4172 .valid
4173 .retain(|&check_id| check_id != old_conncheck_id);
4174 if is_triggered {
4175 checklist.add_triggered(&new_check);
4176 }
4177 checklist.add_check(new_check);
4178 }
4179 Err(_e) => {
4180 check.set_state(CandidatePairState::Failed);
4181 }
4182 }
4183 break;
4184 }
4185 }
4186
4187 pub fn close(&mut self, now: Instant) {
4188 for checklist_i in 0..self.checklists.len() {
4189 let checklist = &mut self.checklists[checklist_i];
4190 let mut checks = VecDeque::new();
4191 core::mem::swap(&mut checks, &mut checklist.pairs);
4192 for check in checks {
4193 self.remove_check_resources(checklist_i, check, now);
4194 }
4195 let checklist = &mut self.checklists[checklist_i];
4196 let mut turn_clients = Vec::new();
4197 core::mem::swap(&mut turn_clients, &mut checklist.turn_clients);
4198 for mut client in turn_clients {
4199 let _ = client.client.delete(now);
4200 checklist.pending_delete_turn_clients.push(client);
4201 }
4202 checklist.close();
4203 }
4204 self.closed = true;
4205 }
4206}
4207
4208#[derive(Debug)]
4210pub enum CheckListSetPollRet {
4211 Closed,
4213 AllocateSocket {
4216 checklist_id: usize,
4217 component_id: usize,
4218 transport: TransportType,
4219 local_addr: SocketAddr,
4220 remote_addr: SocketAddr,
4221 },
4222 RemoveSocket {
4225 checklist_id: usize,
4226 component_id: usize,
4227 transport: TransportType,
4228 local_addr: SocketAddr,
4229 remote_addr: SocketAddr,
4230 },
4231 WaitUntil(Instant),
4234 Event {
4236 checklist_id: usize,
4237 event: ConnCheckEvent,
4238 },
4239 Completed,
4242}
4243
4244#[derive(Debug)]
4245pub struct CheckListSetTransmit {
4246 pub checklist_id: usize,
4247 pub transmit: Transmit<Box<[u8]>>,
4248}
4249
4250#[derive(Debug)]
4251struct CheckListSetPendingMessage {
4252 checklist_id: usize,
4253 agent_id: StunAgentId,
4254 is_request: bool,
4255 msg: Vec<u8>,
4256 turn_id: Option<(StunAgentId, SocketAddr)>,
4257 to: SocketAddr,
4258}
4259
4260#[derive(Debug)]
4261struct CheckListSetSocket {
4262 checklist_id: usize,
4263 component_id: usize,
4264 transport: TransportType,
4265 local_addr: SocketAddr,
4266 remote_addr: SocketAddr,
4267}
4268
4269impl CheckListSetSocket {
4270 fn into_allocate(self) -> CheckListSetPollRet {
4271 CheckListSetPollRet::AllocateSocket {
4272 checklist_id: self.checklist_id,
4273 component_id: self.component_id,
4274 transport: self.transport,
4275 local_addr: self.local_addr,
4276 remote_addr: self.remote_addr,
4277 }
4278 }
4279
4280 fn into_remove(self) -> CheckListSetPollRet {
4281 CheckListSetPollRet::RemoveSocket {
4282 checklist_id: self.checklist_id,
4283 component_id: self.component_id,
4284 transport: self.transport,
4285 local_addr: self.local_addr,
4286 remote_addr: self.remote_addr,
4287 }
4288 }
4289}
4290
4291#[derive(Debug)]
4292pub struct PendingRecv {
4293 pub component_id: usize,
4294 pub data: Vec<u8>,
4295}
4296
4297fn pair_tcp_type(local: TcpType) -> TcpType {
4298 match local {
4299 TcpType::Active => TcpType::Passive,
4300 TcpType::Passive => TcpType::Active,
4301 TcpType::So => TcpType::So,
4302 }
4303}
4304
4305fn pair_construct_valid(pair: &CandidatePair, mapped_address: SocketAddr) -> CandidatePair {
4306 let mut local = pair.local.clone();
4307 local.address = mapped_address;
4308 CandidatePair {
4309 local,
4310 remote: pair.remote.clone(),
4311 }
4312}
4313
4314fn candidate_can_pair_with(local: &Candidate, remote: &Candidate) -> bool {
4316 debug!("local: {local:?}");
4317 debug!("remote: {remote:?}");
4318 if local.transport_type == TransportType::Tcp
4319 && remote.transport_type == TransportType::Tcp
4320 && (local.tcp_type.is_none()
4321 || remote.tcp_type.is_none()
4322 || pair_tcp_type(local.tcp_type.unwrap()) != remote.tcp_type.unwrap())
4323 {
4324 return false;
4325 }
4326 local.transport_type == remote.transport_type
4327 && local.component_id == remote.component_id
4328 && local.base_address.is_ipv4() == remote.address.is_ipv4()
4329 && local.base_address.is_ipv6() == remote.address.is_ipv6()
4330}
4331
4332fn validate_username(username: Username, local_credentials: &Credentials) -> bool {
4333 let username = username.username().as_bytes();
4334 let local_user = local_credentials.ufrag.as_bytes();
4335 if local_user.len()
4336 == local_user
4337 .iter()
4338 .zip(username)
4339 .take_while(|(l, r)| l == r)
4340 .count()
4341 {
4342 true
4343 } else {
4344 debug!("binding request failed username validation");
4345 false
4346 }
4347}
4348
4349pub(crate) fn transmit_send<T: AsRef<[u8]>>(transport: TransportType, data: T) -> Box<[u8]> {
4350 match transport {
4351 TransportType::Udp => data.as_ref().into(),
4352 TransportType::Tcp => {
4353 let len = data.as_ref().len();
4354 let mut ret = Vec::with_capacity(2 + len);
4355 ret.resize(2, 0);
4356 BigEndian::write_u16(&mut ret, len as u16);
4357 ret.extend_from_slice(data.as_ref());
4358 ret.into_boxed_slice()
4359 }
4360 }
4361}
4362
4363fn transmit_send_build_unframed<T: DelayedTransmitBuild + core::fmt::Debug>(
4364 transmit: TransmitBuild<T>,
4365) -> Transmit<Box<[u8]>> {
4366 Transmit::new(
4367 transmit.data.build().into_boxed_slice(),
4368 transmit.transport,
4369 transmit.from,
4370 transmit.to,
4371 )
4372}
4373
4374fn transmit_send_unframed(transmit: Transmit<Data<'_>>) -> Transmit<Box<[u8]>> {
4375 transmit.reinterpret_data(|data| match data {
4376 Data::Owned(owned) => owned.take(),
4377 Data::Borrowed(borrowed) => borrowed.take().into(),
4378 })
4379}
4380
4381fn new_agent(transport: TransportType, local: SocketAddr, remote: SocketAddr) -> StunAgent {
4382 let mut agent = StunAgent::builder(transport, local);
4383 if transport == TransportType::Tcp {
4384 agent = agent.remote_addr(remote);
4385 }
4386 agent.build()
4387}
4388
4389#[cfg(test)]
4390mod tests {
4391 use alloc::borrow::ToOwned;
4392 use alloc::vec;
4393
4394 use turn_client_proto::{
4395 tcp::TurnClientTcp,
4396 types::{
4397 TurnCredentials,
4398 message::{ALLOCATE, CONNECT, CONNECTION_BIND, CREATE_PERMISSION},
4399 },
4400 udp::TurnClientUdp,
4401 };
4402 use turn_server_proto::api::{TurnServerApi, TurnServerPollRet};
4403 use turn_server_proto::server::TurnServer;
4404
4405 use super::*;
4406 use crate::candidate::*;
4407
4408 #[test]
4409 fn nominate_eq_bool() {
4410 let _log = crate::tests::test_init_log();
4411 assert!(Nominate::DontCare.eq(&true));
4412 assert!(Nominate::DontCare.eq(&false));
4413 assert!(Nominate::True.eq(&true));
4414 assert!(Nominate::False.eq(&false));
4415 assert!(!Nominate::False.eq(&true));
4416 assert!(!Nominate::True.eq(&false));
4417 }
4418
4419 #[test]
4420 fn nominate_eq_nominate() {
4421 let _log = crate::tests::test_init_log();
4422 assert!(Nominate::DontCare.eq(&Nominate::DontCare));
4423 assert!(Nominate::DontCare.eq(&Nominate::True));
4424 assert!(Nominate::DontCare.eq(&Nominate::False));
4425 assert!(Nominate::True.eq(&Nominate::DontCare));
4426 assert!(Nominate::False.eq(&Nominate::DontCare));
4427 assert!(Nominate::True.eq(&Nominate::True));
4428 assert!(Nominate::False.eq(&Nominate::False));
4429 assert!(!Nominate::True.eq(&Nominate::False));
4430 assert!(!Nominate::False.eq(&Nominate::True));
4431 }
4432
4433 #[test]
4434 fn candidate_pair_ordering() {
4435 assert!(
4436 CandidatePairState::Failed
4437 .cmp_progression(&CandidatePairState::Failed)
4438 .is_eq()
4439 );
4440 assert!(
4441 CandidatePairState::Failed
4442 .cmp_progression(&CandidatePairState::Frozen)
4443 .is_lt()
4444 );
4445 assert!(
4446 CandidatePairState::Failed
4447 .cmp_progression(&CandidatePairState::Waiting)
4448 .is_lt()
4449 );
4450 assert!(
4451 CandidatePairState::Failed
4452 .cmp_progression(&CandidatePairState::InProgress)
4453 .is_lt()
4454 );
4455 assert!(
4456 CandidatePairState::Failed
4457 .cmp_progression(&CandidatePairState::Succeeded)
4458 .is_lt()
4459 );
4460
4461 assert!(
4462 CandidatePairState::Frozen
4463 .cmp_progression(&CandidatePairState::Failed)
4464 .is_gt()
4465 );
4466 assert!(
4467 CandidatePairState::Frozen
4468 .cmp_progression(&CandidatePairState::Frozen)
4469 .is_eq()
4470 );
4471 assert!(
4472 CandidatePairState::Frozen
4473 .cmp_progression(&CandidatePairState::Waiting)
4474 .is_lt()
4475 );
4476 assert!(
4477 CandidatePairState::Frozen
4478 .cmp_progression(&CandidatePairState::InProgress)
4479 .is_lt()
4480 );
4481 assert!(
4482 CandidatePairState::Frozen
4483 .cmp_progression(&CandidatePairState::Succeeded)
4484 .is_lt()
4485 );
4486
4487 assert!(
4488 CandidatePairState::Waiting
4489 .cmp_progression(&CandidatePairState::Failed)
4490 .is_gt()
4491 );
4492 assert!(
4493 CandidatePairState::Waiting
4494 .cmp_progression(&CandidatePairState::Frozen)
4495 .is_gt()
4496 );
4497 assert!(
4498 CandidatePairState::Waiting
4499 .cmp_progression(&CandidatePairState::Waiting)
4500 .is_eq()
4501 );
4502 assert!(
4503 CandidatePairState::Waiting
4504 .cmp_progression(&CandidatePairState::InProgress)
4505 .is_lt()
4506 );
4507 assert!(
4508 CandidatePairState::Waiting
4509 .cmp_progression(&CandidatePairState::Succeeded)
4510 .is_lt()
4511 );
4512
4513 assert!(
4514 CandidatePairState::InProgress
4515 .cmp_progression(&CandidatePairState::Failed)
4516 .is_gt()
4517 );
4518 assert!(
4519 CandidatePairState::InProgress
4520 .cmp_progression(&CandidatePairState::Frozen)
4521 .is_gt()
4522 );
4523 assert!(
4524 CandidatePairState::InProgress
4525 .cmp_progression(&CandidatePairState::Waiting)
4526 .is_gt()
4527 );
4528 assert!(
4529 CandidatePairState::InProgress
4530 .cmp_progression(&CandidatePairState::InProgress)
4531 .is_eq()
4532 );
4533 assert!(
4534 CandidatePairState::InProgress
4535 .cmp_progression(&CandidatePairState::Succeeded)
4536 .is_lt()
4537 );
4538
4539 assert!(
4540 CandidatePairState::Succeeded
4541 .cmp_progression(&CandidatePairState::Failed)
4542 .is_gt()
4543 );
4544 assert!(
4545 CandidatePairState::Succeeded
4546 .cmp_progression(&CandidatePairState::Frozen)
4547 .is_gt()
4548 );
4549 assert!(
4550 CandidatePairState::Succeeded
4551 .cmp_progression(&CandidatePairState::Waiting)
4552 .is_gt()
4553 );
4554 assert!(
4555 CandidatePairState::Succeeded
4556 .cmp_progression(&CandidatePairState::InProgress)
4557 .is_gt()
4558 );
4559 assert!(
4560 CandidatePairState::Succeeded
4561 .cmp_progression(&CandidatePairState::Succeeded)
4562 .is_eq()
4563 );
4564 }
4565
4566 #[derive(Debug)]
4567 struct Peer {
4568 candidate: Candidate,
4569 local_credentials: Option<Credentials>,
4570 remote_credentials: Option<Credentials>,
4571 }
4572
4573 impl Peer {
4574 fn default() -> Self {
4575 Peer::builder().build()
4576 }
4577
4578 fn builder() -> PeerBuilder {
4579 PeerBuilder::default()
4580 }
4581
4582 fn stun_agent_with_remote(
4583 &self,
4584 remote_addr: SocketAddr,
4585 ) -> (StunAgent, ShortTermAuth, ShortTermAuth) {
4586 let mut agent =
4587 StunAgent::builder(self.candidate.transport_type, self.candidate.base_address);
4588 if self.candidate.transport_type == TransportType::Tcp {
4589 agent = agent.remote_addr(remote_addr)
4590 }
4591 let agent = agent.build();
4592 let mut local_auth = ShortTermAuth::new();
4593 let mut remote_auth = ShortTermAuth::new();
4594 self.configure_stun_auth(&mut local_auth, &mut remote_auth);
4595 (agent, local_auth, remote_auth)
4596 }
4597
4598 fn stun_agent(&self) -> (StunAgent, ShortTermAuth, ShortTermAuth) {
4599 if self.candidate.transport_type == TransportType::Tcp {
4600 unreachable!();
4601 }
4602 let agent =
4603 StunAgent::builder(self.candidate.transport_type, self.candidate.base_address);
4604 let agent = agent.build();
4605 let mut local_auth = ShortTermAuth::new();
4606 let mut remote_auth = ShortTermAuth::new();
4607 self.configure_stun_auth(&mut local_auth, &mut remote_auth);
4608 (agent, local_auth, remote_auth)
4609 }
4610
4611 fn configure_stun_auth(
4612 &self,
4613 local_auth: &mut ShortTermAuth,
4614 remote_auth: &mut ShortTermAuth,
4615 ) {
4616 let local_credentials = self
4617 .local_credentials
4618 .clone()
4619 .unwrap_or_else(|| Credentials::new(String::from("user"), String::from("pass")));
4620 local_auth.set_credentials(local_credentials.into(), IntegrityAlgorithm::Sha1);
4621 if let Some(remote_credentials) = self.remote_credentials.as_ref() {
4622 remote_auth
4623 .set_credentials(remote_credentials.clone().into(), IntegrityAlgorithm::Sha1);
4624 }
4625 }
4626 }
4627
4628 #[derive(Debug, Default)]
4629 struct PeerBuilder {
4630 foundation: Option<String>,
4631 local_credentials: Option<Credentials>,
4632 remote_credentials: Option<Credentials>,
4633 component_id: Option<usize>,
4634 priority: Option<u32>,
4635 transport: Option<TransportType>,
4636 local_addr: Option<SocketAddr>,
4637 candidate: Option<Candidate>,
4638 tcp_type: Option<TcpType>,
4639 }
4640
4641 impl PeerBuilder {
4642 fn foundation(mut self, foundation: &str) -> Self {
4643 self.foundation = Some(foundation.to_owned());
4644 self
4645 }
4646
4647 fn local_credentials(mut self, credentials: Credentials) -> Self {
4648 self.local_credentials = Some(credentials);
4649 self
4650 }
4651
4652 fn remote_credentials(mut self, credentials: Credentials) -> Self {
4653 self.remote_credentials = Some(credentials);
4654 self
4655 }
4656
4657 fn component_id(mut self, component_id: usize) -> Self {
4658 self.component_id = Some(component_id);
4659 self
4660 }
4661
4662 fn priority(mut self, priority: u32) -> Self {
4663 self.priority = Some(priority);
4664 self
4665 }
4666
4667 fn transport(mut self, transport: TransportType) -> Self {
4668 self.transport = Some(transport);
4669 self
4670 }
4671
4672 fn tcp_type(mut self, tcp_type: TcpType) -> Self {
4673 self.tcp_type = Some(tcp_type);
4674 self
4675 }
4676
4677 fn local_addr(mut self, addr: SocketAddr) -> Self {
4678 self.local_addr = Some(addr);
4679 self
4680 }
4681
4682 fn build(self) -> Peer {
4683 let addr = self.candidate.as_ref().map(|c| c.base_address).unwrap_or(
4684 self.local_addr
4685 .unwrap_or_else(|| "127.0.0.1:0".parse().unwrap()),
4686 );
4687 let ttype = self
4688 .candidate
4689 .as_ref()
4690 .map(|c| c.transport_type)
4691 .unwrap_or(self.transport.unwrap_or(TransportType::Udp));
4692
4693 let tcp_type = match ttype {
4694 TransportType::Udp => {
4695 assert!(self.tcp_type.is_none());
4696 None
4697 }
4698 TransportType::Tcp => Some(self.tcp_type.unwrap_or(TcpType::Passive)),
4699 };
4700
4701 if let Some(candidate) = &self.candidate {
4702 if let Some(component_id) = self.component_id {
4703 if component_id != candidate.component_id {
4704 panic!("mismatched component ids");
4705 }
4706 }
4707 if let Some(foundation) = self.foundation.clone() {
4708 if foundation != candidate.foundation {
4709 panic!("mismatched foundations");
4710 }
4711 }
4712 }
4713 let candidate = self.candidate.unwrap_or_else(|| {
4714 let mut builder = Candidate::builder(
4715 self.component_id.unwrap_or(1),
4716 CandidateType::Host,
4717 ttype,
4718 &self.foundation.unwrap_or(String::from("0")),
4719 addr,
4720 );
4721 if let Some(priority) = self.priority {
4722 builder = builder.priority(priority);
4723 }
4724 if let Some(tcp_type) = tcp_type {
4725 builder = builder.tcp_type(tcp_type);
4726 }
4727 builder.build()
4728 });
4729
4730 Peer {
4731 candidate,
4732 local_credentials: self.local_credentials,
4733 remote_credentials: self.remote_credentials,
4734 }
4735 }
4736 }
4737
4738 #[test]
4739 fn get_candidates() {
4740 let _log = crate::tests::test_init_log();
4741 let mut set = ConnCheckListSet::builder(0, true).build();
4742 let list = set.new_list();
4743 let list = set.mut_list(list).unwrap();
4744 list.add_component(1);
4745
4746 let local = Peer::default();
4747 let remote = Peer::default();
4748
4749 list.add_local_candidate(local.candidate.clone());
4750 list.add_remote_candidate(remote.candidate.clone());
4751
4752 let mut locals = list.local_candidates();
4754 assert_eq!(locals.next(), Some(&local.candidate));
4755 assert_eq!(locals.next(), None);
4756 let remotes = list.remote_candidates();
4757 assert_eq!(remotes.len(), 1);
4758 assert_eq!(remotes[0], remote.candidate);
4759 }
4760
4761 fn handle_binding_request(
4765 local_auth: &ShortTermAuth,
4766 local_credentials: &Credentials,
4767 msg: &Message,
4768 from: SocketAddr,
4769 error_response: Option<u16>,
4770 response_address: Option<SocketAddr>,
4771 ) -> Result<Vec<u8>, StunError> {
4772 let local_stun_credentials = local_auth.credentials().unwrap().0.clone();
4773
4774 if let Some(error_msg) = Message::check_attribute_types(
4775 msg,
4776 &[
4777 Username::TYPE,
4778 Fingerprint::TYPE,
4779 MessageIntegrity::TYPE,
4780 IceControlled::TYPE,
4781 IceControlling::TYPE,
4782 Priority::TYPE,
4783 UseCandidate::TYPE,
4784 ],
4785 &[
4786 Username::TYPE,
4787 Fingerprint::TYPE,
4788 MessageIntegrity::TYPE,
4789 Priority::TYPE,
4790 ],
4791 MessageWriteVec::new(),
4792 ) {
4793 return Ok(error_msg.finish());
4795 }
4796
4797 if msg
4798 .validate_integrity(&local_stun_credentials.clone().into())
4799 .is_err()
4800 {
4801 let code = ErrorCode::builder(ErrorCode::UNAUTHORIZED).build().unwrap();
4802 let mut response = Message::builder_error(msg, MessageWriteVec::new());
4803 response.add_attribute(&code).unwrap();
4804 return Ok(response.finish());
4805 }
4806
4807 let ice_controlling = msg.attribute::<IceControlling>();
4808 let ice_controlled = msg.attribute::<IceControlled>();
4809 let username = msg.attribute::<Username>();
4810 let valid_username = username
4811 .map(|username| validate_username(username, local_credentials))
4812 .unwrap_or(false);
4813
4814 let mut response = if ice_controlling.is_err() && ice_controlled.is_err() {
4815 warn!("missing ice controlled/controlling attribute");
4816 let mut response = Message::builder_error(msg, MessageWriteVec::new());
4817 let error = ErrorCode::builder(ErrorCode::BAD_REQUEST).build()?;
4818 response.add_attribute(&error)?;
4819 response
4820 } else if !valid_username {
4821 let mut response = Message::builder_error(msg, MessageWriteVec::new());
4822 let error = ErrorCode::builder(ErrorCode::UNAUTHORIZED).build()?;
4823 response.add_attribute(&error)?;
4824 response
4825 } else if let Some(error_code) = error_response {
4826 info!("responding with error {}", error_code);
4827 let mut response = Message::builder_error(msg, MessageWriteVec::new());
4828 let error = ErrorCode::builder(error_code).build()?;
4829 response.add_attribute(&error)?;
4830 response
4831 } else {
4832 let mut response = Message::builder_success(msg, MessageWriteVec::new());
4833 let xor_addr =
4834 XorMappedAddress::new(response_address.unwrap_or(from), msg.transaction_id());
4835 response.add_attribute(&xor_addr).unwrap();
4836 response
4837 };
4838 response.add_message_integrity(&local_stun_credentials.into(), IntegrityAlgorithm::Sha1)?;
4839 response.add_fingerprint()?;
4840 Ok(response.finish())
4841 }
4842
4843 fn reply_to_conncheck<T: AsRef<[u8]>>(
4844 agent: &mut StunAgent,
4845 auth: &ShortTermAuth,
4846 credentials: &Credentials,
4847 transmit: Transmit<T>,
4848 error_response: Option<u16>,
4849 response_address: Option<SocketAddr>,
4850 now: Instant,
4851 ) -> Option<Transmit<Box<[u8]>>> {
4852 let offset = match transmit.transport {
4853 TransportType::Udp => 0,
4854 TransportType::Tcp => 2,
4855 };
4856 trace!("data: {:x?}", transmit.data.as_ref());
4857 match Message::from_bytes(&transmit.data.as_ref()[offset..]) {
4858 Err(e) => error!("error parsing STUN message {e:?}"),
4859 Ok(msg) => {
4860 debug!("received {} -> {}: {}", transmit.from, transmit.to, msg);
4861 if msg.has_class(MessageClass::Request) && msg.has_method(BINDING) {
4862 let transmit = agent
4863 .send(
4864 handle_binding_request(
4865 auth,
4866 credentials,
4867 &msg,
4868 transmit.from,
4869 error_response,
4870 response_address,
4871 )
4872 .unwrap(),
4873 transmit.from,
4874 now,
4875 )
4876 .unwrap();
4877 let transport = transmit.transport;
4878 return Some(transmit.reinterpret_data(|data| transmit_send(transport, data)));
4879 }
4880 }
4881 }
4882 None
4883 }
4884
4885 #[test]
4886 fn conncheck_list_transmit() {
4887 let _log = crate::tests::test_init_log();
4888 let mut state = FineControl::builder().build();
4889 let now = Instant::ZERO;
4890
4891 let CheckListSetPollRet::Event {
4892 checklist_id: _,
4893 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
4894 } = state.local.checklist_set.poll(now)
4895 else {
4896 unreachable!();
4897 };
4898
4899 let CheckListSetPollRet::WaitUntil(_) = state.local.checklist_set.poll(now) else {
4900 unreachable!();
4901 };
4902 let Some(CheckListSetTransmit {
4903 checklist_id: _,
4904 transmit,
4905 }) = state.local.checklist_set.poll_transmit(now)
4906 else {
4907 unreachable!()
4908 };
4909 assert_eq!(
4910 transmit.transport,
4911 state.local.peer.candidate.transport_type
4912 );
4913 assert_eq!(transmit.from, state.local.peer.candidate.base_address);
4914 assert_eq!(transmit.to, state.remote.candidate.base_address);
4915 state.local_list().dump_check_state();
4916 }
4917
4918 fn assert_list_contains_checks(list: &mut ConnCheckList, pairs: Vec<&CandidatePair>) {
4919 list.dump_check_state();
4920 trace!("pairs {:?}", pairs);
4921
4922 for (pair, check) in pairs.into_iter().zip(list.pairs.iter()) {
4923 assert_eq!(&check.pair, pair);
4924 }
4925 }
4926
4927 #[test]
4928 fn checklist_generate_checks() {
4929 let _log = crate::tests::test_init_log();
4930 let mut set = ConnCheckListSet::builder(0, true).build();
4931 let list = set.new_list();
4932 let list = set.mut_list(list).unwrap();
4933 list.add_component(1);
4934 list.add_component(2);
4935 let local1_removed = Peer::builder()
4936 .priority(1)
4937 .local_addr("127.0.0.1:1".parse().unwrap())
4938 .build();
4939 let local1 = Peer::builder()
4940 .priority(100)
4941 .local_addr("127.0.0.1:100".parse().unwrap())
4942 .build();
4943 let local1_ignored2 = Peer::builder()
4944 .priority(99)
4945 .local_addr("127.0.0.1:100".parse().unwrap())
4946 .build();
4947 let remote1 = Peer::builder()
4948 .priority(2)
4949 .local_addr("127.0.0.1:2".parse().unwrap())
4950 .build();
4951 let local2 = Peer::builder()
4952 .component_id(2)
4953 .priority(4)
4954 .local_addr("127.0.0.2:3".parse().unwrap())
4955 .build();
4956 let remote2 = Peer::builder()
4957 .component_id(2)
4958 .priority(6)
4959 .local_addr("127.0.0.2:4".parse().unwrap())
4960 .build();
4961 let local3 = Peer::builder()
4962 .priority(10)
4963 .local_addr("127.0.0.3:5".parse().unwrap())
4964 .build();
4965 let remote3 = Peer::builder()
4966 .priority(15)
4967 .local_addr("127.0.0.3:6".parse().unwrap())
4968 .build();
4969
4970 assert!(list.add_local_candidate(local1_removed.candidate.clone()));
4971 assert!(list.add_local_candidate(local1.candidate.clone()));
4972 assert!(!list.add_local_candidate(local1_ignored2.candidate.clone()));
4973 list.add_remote_candidate(remote1.candidate.clone());
4974 assert!(list.add_local_candidate(local2.candidate.clone()));
4975 list.add_remote_candidate(remote2.candidate.clone());
4976 assert!(list.add_local_candidate(local3.candidate.clone()));
4977 list.add_remote_candidate(remote3.candidate.clone());
4978
4979 let pair1 = CandidatePair::new(local1.candidate.clone(), remote3.candidate.clone());
4980 let pair2 = CandidatePair::new(local3.candidate.clone(), remote3.candidate);
4981 let pair3 = CandidatePair::new(local2.candidate, remote2.candidate);
4982 let pair4 = CandidatePair::new(local1.candidate, remote1.candidate.clone());
4983 let pair5 = CandidatePair::new(local3.candidate, remote1.candidate);
4984 assert_list_contains_checks(list, vec![&pair1, &pair2, &pair3, &pair4, &pair5]);
4985 }
4986
4987 #[test]
4988 fn checklists_initial_thaw() {
4989 let _log = crate::tests::test_init_log();
4990 let mut set = ConnCheckListSet::builder(0, true).build();
4991 let list1_id = set.new_list();
4992 let list2_id = set.new_list();
4993 let now = Instant::ZERO;
4994
4995 let local1 = Peer::builder()
4996 .foundation("0")
4997 .priority(1)
4998 .local_addr("127.0.0.1:1".parse().unwrap())
4999 .build();
5000 let remote1 = Peer::builder()
5001 .foundation("0")
5002 .priority(2)
5003 .local_addr("127.0.0.1:2".parse().unwrap())
5004 .build();
5005 let local2 = Peer::builder()
5006 .foundation("0")
5007 .priority(3)
5008 .local_addr("127.0.0.2:3".parse().unwrap())
5009 .build();
5010 let remote2 = Peer::builder()
5011 .foundation("0")
5012 .priority(4)
5013 .local_addr("127.0.0.2:4".parse().unwrap())
5014 .build();
5015 let local3 = Peer::builder()
5016 .foundation("1")
5017 .priority(7)
5018 .local_addr("127.0.0.3:5".parse().unwrap())
5019 .build();
5020 let remote3 = Peer::builder()
5021 .foundation("1")
5022 .priority(10)
5023 .local_addr("127.0.0.3:6".parse().unwrap())
5024 .build();
5025
5026 let pair1 = CandidatePair::new(local1.candidate.clone(), remote1.candidate.clone());
5028 let pair2 = CandidatePair::new(local3.candidate.clone(), remote3.candidate.clone());
5029 let pair3 = CandidatePair::new(local3.candidate.clone(), remote2.candidate.clone());
5030 let pair4 = CandidatePair::new(local2.candidate.clone(), remote3.candidate.clone());
5031 let pair5 = CandidatePair::new(local2.candidate.clone(), remote2.candidate.clone());
5032
5033 let list1 = set.mut_list(list1_id).unwrap();
5034 list1.add_component(1);
5035 list1.add_local_candidate(local1.candidate.clone());
5036 list1.add_remote_candidate(remote1.candidate.clone());
5037
5038 assert_list_contains_checks(list1, vec![&pair1]);
5039
5040 let list2 = set.mut_list(list2_id).unwrap();
5041 list2.add_component(1);
5042 list2.add_local_candidate(local2.candidate.clone());
5043 list2.add_remote_candidate(remote2.candidate.clone());
5044 list2.add_local_candidate(local3.candidate.clone());
5045 list2.add_remote_candidate(remote3.candidate.clone());
5046
5047 assert_list_contains_checks(list2, vec![&pair2, &pair3, &pair4, &pair5]);
5048
5049 let CheckListSetPollRet::Event {
5051 checklist_id: _,
5052 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
5053 } = set.poll(now)
5054 else {
5055 unreachable!();
5056 };
5057
5058 set.poll_transmit(now).unwrap();
5059
5060 let list2 = set.mut_list(list2_id).unwrap();
5061 list2.dump_check_state();
5062 let check2 = list2.matching_check(&pair2, Nominate::DontCare).unwrap();
5063 assert_eq!(check2.pair, pair2);
5064 assert_eq!(check2.state(), CandidatePairState::InProgress);
5065 let check3 = list2.matching_check(&pair3, Nominate::DontCare).unwrap();
5066 assert_eq!(check3.pair, pair3);
5067 assert_eq!(check3.state(), CandidatePairState::Waiting);
5068 let check4 = list2.matching_check(&pair4, Nominate::DontCare).unwrap();
5069 assert_eq!(check4.pair, pair4);
5070 assert_eq!(check4.state(), CandidatePairState::Waiting);
5071 let check5 = list2.matching_check(&pair5, Nominate::DontCare).unwrap();
5072 assert_eq!(check5.pair, pair5);
5073 assert_eq!(check5.state(), CandidatePairState::Frozen);
5074
5075 let list1 = set.mut_list(list1_id).unwrap();
5076 list1.dump_check_state();
5077 let check1 = list1.matching_check(&pair1, Nominate::DontCare).unwrap();
5078 assert_eq!(check1.pair, pair1);
5079 assert_eq!(check1.state(), CandidatePairState::Waiting);
5080
5081 let now = wait_advance(&mut set, now);
5084 let CheckListSetPollRet::WaitUntil(_) = set.poll(now) else {
5085 unreachable!();
5086 };
5087 set.poll_transmit(now).unwrap();
5088
5089 let list1 = set.mut_list(list1_id).unwrap();
5090 list1.dump_check_state();
5091 let check1 = list1.matching_check(&pair1, Nominate::DontCare).unwrap();
5092 assert_eq!(check1.pair, pair1);
5093 assert_eq!(check1.state(), CandidatePairState::Waiting);
5094
5095 let list2 = set.mut_list(list2_id).unwrap();
5096 list2.dump_check_state();
5097 let check2 = list2.matching_check(&pair2, Nominate::DontCare).unwrap();
5098 assert_eq!(check2.pair, pair2);
5099 assert_eq!(check2.state(), CandidatePairState::InProgress);
5100 let check3 = list2.matching_check(&pair3, Nominate::DontCare).unwrap();
5101 assert_eq!(check3.pair, pair3);
5102 assert_eq!(check3.state(), CandidatePairState::InProgress);
5103 let check4 = list2.matching_check(&pair4, Nominate::DontCare).unwrap();
5104 assert_eq!(check4.pair, pair4);
5105 assert_eq!(check4.state(), CandidatePairState::Waiting);
5106 let check5 = list2.matching_check(&pair5, Nominate::DontCare).unwrap();
5107 assert_eq!(check5.pair, pair5);
5108 assert_eq!(check5.state(), CandidatePairState::Frozen);
5109 }
5110
5111 #[derive(Debug)]
5112 struct FineControlPeer {
5113 component_id: usize,
5114 peer: Peer,
5115 checklist_set: ConnCheckListSet,
5116 checklist_id: usize,
5117 }
5118
5119 #[derive(Debug)]
5120 struct FineControl {
5121 local: FineControlPeer,
5122 remote: Peer,
5123 }
5124
5125 struct FineControlBuilder {
5126 trickle_ice: bool,
5127 controlling: bool,
5128 local_peer_builder: PeerBuilder,
5129 remote_peer_builder: PeerBuilder,
5130 }
5131
5132 impl Default for FineControlBuilder {
5133 fn default() -> Self {
5134 let local_credentials = Credentials::new("luser".into(), "lpass".into());
5135 let remote_credentials = Credentials::new("ruser".into(), "rpass".into());
5136 Self {
5137 trickle_ice: false,
5138 controlling: true,
5139 local_peer_builder: Peer::builder()
5140 .foundation("0")
5141 .local_credentials(local_credentials.clone())
5142 .remote_credentials(remote_credentials.clone())
5143 .local_addr("127.0.0.1:1".parse().unwrap()),
5144 remote_peer_builder: Peer::builder()
5145 .foundation("0")
5146 .local_credentials(remote_credentials.clone())
5147 .remote_credentials(local_credentials.clone())
5148 .local_addr("127.0.0.1:2".parse().unwrap()),
5149 }
5150 }
5151 }
5152
5153 impl FineControlBuilder {
5154 fn controlling(mut self, controlling: bool) -> Self {
5155 self.controlling = controlling;
5156 self
5157 }
5158
5159 fn trickle_ice(mut self, trickle_ice: bool) -> Self {
5160 self.trickle_ice = trickle_ice;
5161 self
5162 }
5163
5164 fn local_candidate(mut self, candidate: Candidate) -> Self {
5165 self.local_peer_builder.candidate = Some(candidate);
5166 self
5167 }
5168
5169 fn build(self) -> FineControl {
5170 let mut local_set = ConnCheckListSet::builder(0, self.controlling)
5171 .trickle_ice(self.trickle_ice)
5172 .build();
5173 let local_list = local_set.new_list();
5174 let local_list = local_set.mut_list(local_list).unwrap();
5175 local_list.add_component(1);
5176 let checklist_id = local_list.checklist_id;
5177
5178 let local_peer = self.local_peer_builder.build();
5179 let remote_peer = self.remote_peer_builder.build();
5180
5181 local_list.set_local_credentials(local_peer.local_credentials.clone().unwrap());
5182 local_list.set_remote_credentials(local_peer.remote_credentials.clone().unwrap());
5183 if !self.trickle_ice {
5184 local_list.add_local_candidate(local_peer.candidate.clone());
5185 local_list.add_remote_candidate(remote_peer.candidate.clone());
5186 }
5187
5188 FineControl {
5189 local: FineControlPeer {
5190 component_id: 1,
5191 peer: local_peer,
5192 checklist_set: local_set,
5193 checklist_id,
5194 },
5195 remote: remote_peer,
5196 }
5197 }
5198 }
5199
5200 impl FineControl {
5201 fn builder() -> FineControlBuilder {
5202 FineControlBuilder::default()
5203 }
5204
5205 fn local_list(&mut self) -> &mut ConnCheckList {
5206 self.local
5207 .checklist_set
5208 .mut_list(self.local.checklist_id)
5209 .unwrap()
5210 }
5211
5212 fn set_remote_credentials(&mut self, credentials: Credentials) {
5213 self.local.peer.remote_credentials = Some(credentials.clone());
5214 self.remote.local_credentials = Some(credentials.clone());
5215 self.local_list().set_remote_credentials(credentials);
5216 }
5217
5218 fn check_nomination(&mut self, pair: &CandidatePair, now: Instant) {
5219 let nominate_check = self
5220 .local_list()
5221 .matching_check(pair, Nominate::True)
5222 .unwrap();
5223 assert_eq!(nominate_check.state(), CandidatePairState::Waiting);
5224 let pair = nominate_check.pair.clone();
5225 let check_id = nominate_check.conncheck_id;
5226 assert!(self.local_list().is_triggered(&pair));
5227
5228 send_next_check_and_response(&self.local.peer, &self.remote)
5230 .perform(&mut self.local.checklist_set, now);
5231
5232 let nominate_check = self.local_list().check_by_id(check_id).unwrap();
5233 assert_eq!(nominate_check.state(), CandidatePairState::Succeeded);
5234
5235 assert_eq!(self.local_list().state(), CheckListState::Completed);
5237
5238 let CheckListSetPollRet::Event {
5239 checklist_id: _,
5240 event: ConnCheckEvent::SelectedPair(_cid, _selected_pair),
5241 } = self.local.checklist_set.poll(now)
5242 else {
5243 unreachable!();
5244 };
5245 let CheckListSetPollRet::Event {
5246 checklist_id: _,
5247 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connected),
5248 } = self.local.checklist_set.poll(now)
5249 else {
5250 unreachable!();
5251 };
5252
5253 assert!(matches!(
5255 self.local.checklist_set.poll(now),
5256 CheckListSetPollRet::Completed
5257 ));
5258 }
5259
5260 fn recv_data<T: AsRef<[u8]> + core::fmt::Debug>(&mut self, data: T, now: Instant) {
5261 let pair = CandidatePair::new(
5262 self.local.peer.candidate.clone(),
5263 self.remote.candidate.clone(),
5264 );
5265 self.recv_data_with_pair(&pair, data, now);
5266 }
5267
5268 fn recv_data_with_pair<T: AsRef<[u8]> + core::fmt::Debug>(
5269 &mut self,
5270 pair: &CandidatePair,
5271 data: T,
5272 now: Instant,
5273 ) {
5274 let checklist_id = self.local.checklist_id;
5275 let transmit = Transmit::new(
5276 data.as_ref(),
5277 TransportType::Udp,
5278 pair.remote.address,
5279 pair.local.address,
5280 );
5281 let reply = self.local.checklist_set.incoming_data(
5282 checklist_id,
5283 pair.local.component_id,
5284 transmit,
5285 now,
5286 );
5287 assert_eq!(reply.data.unwrap().as_ref(), data.as_ref());
5288 }
5289 }
5290
5291 struct NextCheckAndResponse {
5292 #[allow(unused)]
5293 local_cand: Candidate,
5294 remote_agent: StunAgent,
5295 remote_auth: ShortTermAuth,
5296 remote_credentials: Credentials,
5297 turn_server: Option<TurnServer>,
5298 error_response: Option<u16>,
5299 response_address: Option<SocketAddr>,
5300 unhandled_reply: bool,
5301 }
5302
5303 impl NextCheckAndResponse {
5304 fn error_response(mut self, error_response: u16) -> Self {
5305 self.error_response = Some(error_response);
5306 self
5307 }
5308
5309 fn response_address(mut self, address: SocketAddr) -> Self {
5310 self.response_address = Some(address);
5311 self
5312 }
5313
5314 fn turn_server(mut self, server: TurnServer) -> Self {
5315 self.turn_server = Some(server);
5316 self
5317 }
5318
5319 fn take_turn_server(&mut self) -> Option<TurnServer> {
5320 self.turn_server.take()
5321 }
5322
5323 fn unhandled_reply(mut self) -> Self {
5324 self.unhandled_reply = true;
5325 self
5326 }
5327
5328 fn send(&mut self, set: &mut ConnCheckListSet, now: Instant) -> Transmit<Box<[u8]>> {
5329 match set.poll(now) {
5331 CheckListSetPollRet::WaitUntil(next) => assert_eq!(next, now),
5332 ret => {
5333 error!("{ret:?}");
5334 unreachable!()
5335 }
5336 }
5337 let Some(transmit) = set.poll_transmit(now) else {
5338 unreachable!()
5339 };
5340 let mut transmit = transmit.transmit;
5341 debug!("tick");
5342
5343 if let Some(turn) = self.turn_server.as_mut() {
5345 transmit = turn
5346 .recv(transmit, now)
5347 .unwrap()
5348 .build()
5349 .reinterpret_data(|data| data.into_boxed_slice());
5350 }
5351 transmit
5352 }
5353
5354 fn response<T: AsRef<[u8]>>(
5355 &mut self,
5356 set: &mut ConnCheckListSet,
5357 transmit: Transmit<T>,
5358 now: Instant,
5359 ) {
5360 let mut reply = reply_to_conncheck(
5361 &mut self.remote_agent,
5362 &self.remote_auth,
5363 &self.remote_credentials,
5364 transmit,
5365 self.error_response,
5366 self.response_address,
5367 now,
5368 )
5369 .unwrap();
5370 info!("reply: {reply:?}");
5371
5372 if let Some(turn) = self.turn_server.as_mut() {
5373 reply = turn
5374 .recv(reply, now)
5375 .unwrap()
5376 .build()
5377 .reinterpret_data(|data| data.into_boxed_slice());
5378 }
5379
5380 let checklist_id = set
5381 .checklists
5382 .iter()
5383 .map(|checklist| checklist.checklist_id)
5384 .next()
5385 .unwrap();
5386 let reply = set.incoming_data(checklist_id, 1, reply, now);
5387 trace!("reply: {reply:?}");
5388 if !self.unhandled_reply {
5389 assert!(reply.handled);
5390 }
5391 }
5392
5393 fn perform(&mut self, set: &mut ConnCheckListSet, now: Instant) {
5394 let transmit = self.send(set, now);
5395 self.response(set, transmit, now)
5396 }
5397 }
5398
5399 fn send_next_check_and_response(local_peer: &Peer, remote_peer: &Peer) -> NextCheckAndResponse {
5400 let (remote_agent, remote_auth, _local_auth) =
5401 remote_peer.stun_agent_with_remote(local_peer.candidate.address);
5402 NextCheckAndResponse {
5403 local_cand: local_peer.candidate.clone(),
5404 remote_agent,
5405 remote_auth,
5406 remote_credentials: remote_peer.local_credentials.clone().unwrap(),
5407 turn_server: None,
5408 error_response: None,
5409 response_address: None,
5410 unhandled_reply: false,
5411 }
5412 }
5413
5414 fn send_next_check_and_response2(
5415 local_cand: Candidate,
5416 remote_peer: &Peer,
5417 ) -> NextCheckAndResponse {
5418 let (remote_agent, remote_auth, _local_auth) =
5419 remote_peer.stun_agent_with_remote(local_cand.address);
5420 NextCheckAndResponse {
5421 local_cand,
5422 remote_agent,
5423 remote_auth,
5424 remote_credentials: remote_peer.local_credentials.clone().unwrap(),
5425 turn_server: None,
5426 error_response: None,
5427 response_address: None,
5428 unhandled_reply: false,
5429 }
5430 }
5431
5432 #[test]
5433 fn very_fine_control1() {
5434 let _log = crate::tests::test_init_log();
5435 let mut state = FineControl::builder().build();
5436 let now = Instant::ZERO;
5437 assert_eq!(state.local.component_id, 1);
5438
5439 let pair = CandidatePair::new(
5440 state.local.peer.candidate.clone(),
5441 state.remote.candidate.clone(),
5442 );
5443 let check = state
5444 .local_list()
5445 .matching_check(&pair, Nominate::False)
5446 .unwrap();
5447 assert_eq!(check.state(), CandidatePairState::Frozen);
5448 let check_id = check.conncheck_id;
5449
5450 let CheckListSetPollRet::Event {
5451 checklist_id: _,
5452 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
5453 } = state.local.checklist_set.poll(now)
5454 else {
5455 unreachable!();
5456 };
5457
5458 send_next_check_and_response(&state.local.peer, &state.remote)
5460 .perform(&mut state.local.checklist_set, now);
5461 let check = state.local_list().check_by_id(check_id).unwrap();
5462 assert_eq!(check.state(), CandidatePairState::Succeeded);
5463
5464 let now = wait_advance(&mut state.local.checklist_set, now);
5465
5466 state.check_nomination(&pair, now);
5467
5468 state.local.checklist_set.close(now);
5469
5470 let CheckListSetPollRet::RemoveSocket {
5471 checklist_id: _,
5472 component_id: 1,
5473 transport: TransportType::Udp,
5474 local_addr,
5475 remote_addr: _,
5476 } = state.local.checklist_set.poll(now)
5477 else {
5478 unreachable!();
5479 };
5480 assert_eq!(local_addr, pair.local.base_address);
5481 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
5482 unreachable!();
5483 };
5484 }
5485
5486 #[test]
5487 fn role_conflict_response() {
5488 let _log = crate::tests::test_init_log();
5489 let mut state = FineControl::builder().controlling(false).build();
5492 let now = Instant::ZERO;
5493
5494 let pair = CandidatePair::new(
5495 state.local.peer.candidate.clone(),
5496 state.remote.candidate.clone(),
5497 );
5498 let check = state
5499 .local_list()
5500 .matching_check(&pair, Nominate::False)
5501 .unwrap();
5502 assert_eq!(check.state(), CandidatePairState::Frozen);
5503 let check_id = check.conncheck_id;
5504
5505 let CheckListSetPollRet::Event {
5506 checklist_id: _,
5507 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
5508 } = state.local.checklist_set.poll(now)
5509 else {
5510 unreachable!();
5511 };
5512
5513 send_next_check_and_response(&state.local.peer, &state.remote)
5515 .error_response(ErrorCode::ROLE_CONFLICT)
5516 .perform(&mut state.local.checklist_set, now);
5517 state.local_list().dump_check_state();
5518 let check = state.local_list().check_by_id(check_id).unwrap();
5519 assert_eq!(check.state(), CandidatePairState::Failed);
5520
5521 let triggered_check = state
5524 .local_list()
5525 .matching_check(&pair, Nominate::False)
5526 .unwrap();
5527 let check_id = triggered_check.conncheck_id;
5528 let pair = triggered_check.pair.clone();
5529 assert!(state.local_list().is_triggered(&pair));
5530
5531 let now = wait_advance(&mut state.local.checklist_set, now);
5533 send_next_check_and_response(&state.local.peer, &state.remote)
5534 .perform(&mut state.local.checklist_set, now);
5535 let triggered_check = state.local_list().check_by_id(check_id).unwrap();
5536 assert_eq!(triggered_check.state(), CandidatePairState::Succeeded);
5537
5538 let now = wait_advance(&mut state.local.checklist_set, now);
5539 state.check_nomination(&pair, now);
5540
5541 state.local.checklist_set.close(now);
5542
5543 let CheckListSetPollRet::RemoveSocket {
5544 checklist_id: _,
5545 component_id: 1,
5546 transport: TransportType::Udp,
5547 local_addr,
5548 remote_addr: _,
5549 } = state.local.checklist_set.poll(now)
5550 else {
5551 unreachable!();
5552 };
5553 assert_eq!(local_addr, pair.local.base_address);
5554 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
5555 unreachable!();
5556 };
5557 }
5558
5559 #[test]
5560 fn bad_username_conncheck() {
5561 let _log = crate::tests::test_init_log();
5562 let mut state = FineControl::builder().build();
5563 let now = Instant::ZERO;
5564 let local_list = state
5565 .local
5566 .checklist_set
5567 .mut_list(state.local.checklist_id)
5568 .unwrap();
5569
5570 let wrong_credentials =
5572 Credentials::new(String::from("wronguser"), String::from("wrongpass"));
5573 local_list.set_local_credentials(wrong_credentials);
5574
5575 let pair = CandidatePair::new(
5576 state.local.peer.candidate.clone(),
5577 state.remote.candidate.clone(),
5578 );
5579 let check = local_list.matching_check(&pair, Nominate::False).unwrap();
5580 let check_id = check.conncheck_id;
5581 assert_eq!(check.state(), CandidatePairState::Frozen);
5582
5583 let CheckListSetPollRet::Event {
5584 checklist_id: _,
5585 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
5586 } = state.local.checklist_set.poll(now)
5587 else {
5588 unreachable!();
5589 };
5590
5591 send_next_check_and_response(&state.local.peer, &state.remote)
5593 .error_response(ErrorCode::UNAUTHORIZED)
5594 .perform(&mut state.local.checklist_set, now);
5595 let check = state.local_list().check_by_id(check_id).unwrap();
5596 assert_eq!(check.state(), CandidatePairState::Failed);
5597
5598 }
5607
5608 #[test]
5609 fn conncheck_tcp_active() {
5610 let _log = crate::tests::test_init_log();
5611 let mut state = FineControl::builder();
5612 state.local_peer_builder = state
5613 .local_peer_builder
5614 .transport(TransportType::Tcp)
5615 .tcp_type(TcpType::Active);
5616 state.remote_peer_builder = state
5617 .remote_peer_builder
5618 .transport(TransportType::Tcp)
5619 .tcp_type(TcpType::Passive);
5620 let mut state = state.build();
5621 let pair = CandidatePair::new(
5622 state.local.peer.candidate.clone(),
5623 state.remote.candidate.clone(),
5624 );
5625 let local_agent =
5626 StunAgent::builder(TransportType::Tcp, state.local.peer.candidate.base_address)
5627 .remote_addr(state.remote.candidate.address)
5628 .build();
5629 let mut local_auth = ShortTermAuth::new();
5630 let mut remote_auth = ShortTermAuth::new();
5631 state
5632 .local
5633 .peer
5634 .configure_stun_auth(&mut local_auth, &mut remote_auth);
5635 let mut remote_agent =
5636 StunAgent::builder(TransportType::Tcp, state.remote.candidate.address)
5637 .remote_addr(state.local.peer.candidate.base_address)
5638 .build();
5639 let now = Instant::ZERO;
5640
5641 let CheckListSetPollRet::AllocateSocket {
5642 checklist_id: id,
5643 component_id: cid,
5644 transport,
5645 local_addr: from,
5646 remote_addr: to,
5647 } = state.local.checklist_set.poll(now)
5648 else {
5649 unreachable!();
5650 };
5651 assert_eq!(id, state.local.checklist_id);
5652 assert_eq!(cid, state.local.peer.candidate.component_id);
5653 assert_eq!(from, state.local.peer.candidate.base_address);
5654 assert_eq!(to, state.remote.candidate.address);
5655 assert_eq!(transport, TransportType::Tcp);
5656 error!("tcp connect");
5657
5658 let CheckListSetPollRet::Event {
5659 checklist_id: _,
5660 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
5661 } = state.local.checklist_set.poll(now)
5662 else {
5663 unreachable!();
5664 };
5665
5666 state.local.checklist_set.allocated_socket(
5667 id,
5668 cid,
5669 transport,
5670 from,
5671 to,
5672 Ok(local_agent.local_addr()),
5673 now,
5674 );
5675 error!("tcp connect replied");
5676
5677 let Some(transmit) = state.local.checklist_set.poll_transmit(now) else {
5678 unreachable!();
5679 };
5680 assert_eq!(transmit.checklist_id, state.local.checklist_id);
5681 assert_eq!(
5682 transmit.transmit.from,
5683 state.local.peer.candidate.base_address
5684 );
5685 assert_eq!(transmit.transmit.to, state.remote.candidate.address);
5686 error!("tcp transmit");
5687
5688 let Some(response) = reply_to_conncheck(
5689 &mut remote_agent,
5690 &remote_auth,
5691 state.local.peer.remote_credentials.as_ref().unwrap(),
5692 transmit.transmit,
5693 None,
5694 None,
5695 now,
5696 ) else {
5697 unreachable!();
5698 };
5699 error!("tcp reply");
5700
5701 let check = state
5702 .local_list()
5703 .matching_check(&pair, Nominate::DontCare)
5704 .unwrap();
5705 assert_eq!(check.state(), CandidatePairState::InProgress);
5706
5707 state
5708 .local
5709 .checklist_set
5710 .incoming_data(state.local.checklist_id, 1, response, now);
5711 error!("tcp replied");
5712
5713 let now = wait_advance(&mut state.local.checklist_set, now);
5714 let CheckListSetPollRet::WaitUntil(_) = state.local.checklist_set.poll(now) else {
5715 unreachable!();
5716 };
5717 let transmit = state.local.checklist_set.poll_transmit(now).unwrap();
5718
5719 let Some(response) = reply_to_conncheck(
5720 &mut remote_agent,
5721 &remote_auth,
5722 state.local.peer.remote_credentials.as_ref().unwrap(),
5723 transmit.transmit,
5724 None,
5725 None,
5726 now,
5727 ) else {
5728 unreachable!();
5729 };
5730 state
5731 .local
5732 .checklist_set
5733 .incoming_data(state.local.checklist_id, 1, response, now);
5734
5735 let CheckListSetPollRet::Event {
5736 checklist_id: _,
5737 event: ConnCheckEvent::SelectedPair(_cid, selected_pair),
5738 } = state.local.checklist_set.poll(now)
5739 else {
5740 unreachable!();
5741 };
5742 let CheckListSetPollRet::Event {
5743 checklist_id: _,
5744 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connected),
5745 } = state.local.checklist_set.poll(now)
5746 else {
5747 unreachable!();
5748 };
5749 assert_eq!(selected_pair.candidate_pair, pair);
5750
5751 assert!(matches!(
5752 state.local.checklist_set.poll(now),
5753 CheckListSetPollRet::Completed
5754 ));
5755
5756 state.local.checklist_set.close(now);
5757
5758 let CheckListSetPollRet::RemoveSocket {
5759 checklist_id: _,
5760 component_id: 1,
5761 transport: TransportType::Tcp,
5762 local_addr,
5763 remote_addr,
5764 } = state.local.checklist_set.poll(now)
5765 else {
5766 unreachable!();
5767 };
5768 assert_eq!(local_addr, pair.local.base_address);
5769 assert_eq!(remote_addr, pair.remote.address);
5770 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
5771 unreachable!();
5772 };
5773 }
5774
5775 #[test]
5776 fn conncheck_tcp_passive() {
5777 let _log = crate::tests::test_init_log();
5778 let mut state = FineControl::builder();
5779 state.local_peer_builder = state
5780 .local_peer_builder
5781 .transport(TransportType::Tcp)
5782 .local_addr("127.0.0.1:1000".parse().unwrap())
5783 .tcp_type(TcpType::Passive);
5784 state.remote_peer_builder = state
5785 .remote_peer_builder
5786 .transport(TransportType::Tcp)
5787 .local_addr("127.0.0.1:9".parse().unwrap())
5788 .tcp_type(TcpType::Active)
5789 .priority(10);
5790 let mut state = state.build();
5791 let now = Instant::ZERO;
5792 let remote_addr = SocketAddr::new(state.remote.candidate.base_address.ip(), 2000);
5793 let mut remote_cand = state.remote.candidate.clone();
5794 remote_cand.address = remote_addr;
5795 remote_cand.base_address = remote_addr;
5796
5797 let pair = CandidatePair::new(state.local.peer.candidate.clone(), remote_cand.clone());
5798 let mut local_auth = ShortTermAuth::new();
5799 let mut remote_auth = ShortTermAuth::new();
5800 state
5801 .local
5802 .peer
5803 .configure_stun_auth(&mut local_auth, &mut remote_auth);
5804 let mut remote_agent = StunAgent::builder(TransportType::Tcp, remote_addr)
5805 .remote_addr(state.local.peer.candidate.base_address)
5806 .build();
5807
5808 let request = ConnCheck::generate_stun_request(
5809 &pair,
5810 false,
5811 false,
5812 100,
5813 state.remote.local_credentials.clone().unwrap(),
5814 state.remote.remote_credentials.clone().unwrap(),
5815 )
5816 .unwrap();
5817
5818 let transport = remote_agent.transport();
5819 assert!(
5820 state
5821 .local
5822 .checklist_set
5823 .incoming_data(
5824 state.local.checklist_id,
5825 1,
5826 remote_agent
5827 .send_request(
5828 request.finish(),
5829 state.local.peer.candidate.base_address,
5830 now
5831 )
5832 .unwrap()
5833 .reinterpret_data(|data| transmit_send(transport, data)),
5834 now,
5835 )
5836 .handled
5837 );
5838
5839 let check = state
5840 .local_list()
5841 .matching_check(&pair, Nominate::False)
5842 .unwrap();
5843 assert_eq!(check.state(), CandidatePairState::Waiting);
5844
5845 let now = Instant::ZERO;
5847 let transmit = state.local.checklist_set.poll_transmit(now).unwrap();
5848 assert_eq!(transmit.checklist_id, state.local.checklist_id);
5849 assert_eq!(
5850 transmit.transmit.from,
5851 state.local.peer.candidate.base_address
5852 );
5853 assert_eq!(transmit.transmit.to, remote_cand.address);
5854
5855 let response = Message::from_bytes(&transmit.transmit.data[2..]).unwrap();
5856 assert!(response.has_class(MessageClass::Success));
5857
5858 let now = wait_advance(&mut state.local.checklist_set, now);
5859 let CheckListSetPollRet::Event {
5860 checklist_id: _,
5861 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
5862 } = state.local.checklist_set.poll(now)
5863 else {
5864 unreachable!();
5865 };
5866
5867 let Some(transmit) = state.local.checklist_set.poll_transmit(now) else {
5869 unreachable!();
5870 };
5871 assert_eq!(transmit.checklist_id, state.local.checklist_id);
5872 assert_eq!(
5873 transmit.transmit.from,
5874 state.local.peer.candidate.base_address
5875 );
5876 assert_eq!(transmit.transmit.to, remote_cand.address);
5877
5878 let Some(response) = reply_to_conncheck(
5879 &mut remote_agent,
5880 &remote_auth,
5881 state.local.peer.remote_credentials.as_ref().unwrap(),
5882 transmit.transmit,
5883 None,
5884 None,
5885 now,
5886 ) else {
5887 unreachable!();
5888 };
5889 state.local_list().dump_check_state();
5890
5891 let check = state
5892 .local_list()
5893 .matching_check(&pair, Nominate::DontCare)
5894 .unwrap();
5895 assert_eq!(check.state(), CandidatePairState::InProgress);
5896
5897 state
5898 .local
5899 .checklist_set
5900 .incoming_data(state.local.checklist_id, 1, response, now);
5901 error!("tcp replied");
5902
5903 let now = wait_advance(&mut state.local.checklist_set, now);
5904 let CheckListSetPollRet::WaitUntil(_) = state.local.checklist_set.poll(now) else {
5905 unreachable!();
5906 };
5907 let transmit = state.local.checklist_set.poll_transmit(now).unwrap();
5909
5910 let Some(response) = reply_to_conncheck(
5911 &mut remote_agent,
5912 &remote_auth,
5913 state.local.peer.remote_credentials.as_ref().unwrap(),
5914 transmit.transmit,
5915 None,
5916 None,
5917 now,
5918 ) else {
5919 unreachable!();
5920 };
5921
5922 state
5923 .local
5924 .checklist_set
5925 .incoming_data(state.local.checklist_id, 1, response, now);
5926
5927 let CheckListSetPollRet::Event {
5928 checklist_id: _,
5929 event: ConnCheckEvent::SelectedPair(_cid, selected_pair),
5930 } = state.local.checklist_set.poll(now)
5931 else {
5932 unreachable!();
5933 };
5934 let CheckListSetPollRet::Event {
5935 checklist_id: _,
5936 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connected),
5937 } = state.local.checklist_set.poll(now)
5938 else {
5939 unreachable!();
5940 };
5941 assert!(candidate_pair_is_same_connection(
5942 &selected_pair.candidate_pair,
5943 &pair
5944 ));
5945
5946 assert!(matches!(
5947 state.local.checklist_set.poll(now),
5948 CheckListSetPollRet::Completed
5949 ));
5950
5951 state.local.checklist_set.close(now);
5952
5953 let CheckListSetPollRet::RemoveSocket {
5954 checklist_id: _,
5955 component_id: 1,
5956 transport: TransportType::Tcp,
5957 local_addr,
5958 remote_addr,
5959 } = state.local.checklist_set.poll(now)
5960 else {
5961 unreachable!();
5962 };
5963 assert_eq!(local_addr, pair.local.base_address);
5964 assert_eq!(remote_addr, pair.remote.address);
5965 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
5966 unreachable!();
5967 };
5968 }
5969
5970 fn remote_generate_check<'a>(
5971 remote_peer: &Peer,
5972 remote_agent: &'a mut StunAgent,
5973 to: SocketAddr,
5974 nominate: bool,
5975 controlling: bool,
5976 now: Instant,
5977 ) -> Transmit<Data<'a>> {
5978 let mut request = Message::builder_request(BINDING, MessageWriteVec::new());
5981 let priority = Priority::new(remote_peer.candidate.priority);
5982 request.add_attribute(&priority).unwrap();
5983 if controlling {
5984 request.add_attribute(&IceControlling::new(200)).unwrap();
5985 } else {
5986 request.add_attribute(&IceControlled::new(200)).unwrap();
5987 }
5988 let username = Username::new(
5989 &(remote_peer.remote_credentials.clone().unwrap().ufrag
5990 + ":"
5991 + &remote_peer.local_credentials.clone().unwrap().ufrag),
5992 )
5993 .unwrap();
5994 request.add_attribute(&username).unwrap();
5995 if nominate {
5996 request.add_attribute(&UseCandidate::new()).unwrap();
5997 }
5998 request
5999 .add_message_integrity(
6000 &MessageIntegrityCredentials::ShortTerm(
6001 remote_peer.remote_credentials.clone().unwrap().into(),
6002 ),
6003 IntegrityAlgorithm::Sha1,
6004 )
6005 .unwrap();
6006 request.add_fingerprint().unwrap();
6007
6008 remote_agent
6009 .send_request(request.finish(), to, now)
6010 .unwrap()
6011 }
6012
6013 #[test]
6014 fn conncheck_incoming_prflx() {
6015 let _log = crate::tests::test_init_log();
6016 let mut state = FineControl::builder().build();
6017 let now = Instant::ZERO;
6018
6019 let pair = CandidatePair::new(
6020 state.local.peer.candidate.clone(),
6021 state.remote.candidate.clone(),
6022 );
6023 let initial_check = state
6024 .local_list()
6025 .matching_check(&pair, Nominate::False)
6026 .unwrap();
6027 assert_eq!(initial_check.state(), CandidatePairState::Frozen);
6028
6029 let unknown_remote_peer = Peer::builder()
6030 .local_addr("127.0.0.1:90".parse().unwrap())
6031 .foundation("1")
6032 .local_credentials(state.remote.local_credentials.clone().unwrap())
6033 .remote_credentials(state.local.peer.local_credentials.clone().unwrap())
6034 .build();
6035 let (mut remote_agent, _remote_auth, mut local_auth) = unknown_remote_peer.stun_agent();
6036
6037 let local_addr = state.local.peer.candidate.base_address;
6038 let transmit = remote_generate_check(
6039 &unknown_remote_peer,
6040 &mut remote_agent,
6041 local_addr,
6042 false,
6043 false,
6044 now,
6045 );
6046
6047 info!("sending prflx request");
6048 let reply =
6049 state
6050 .local
6051 .checklist_set
6052 .incoming_data(state.local.checklist_id, 1, transmit, now);
6053 assert!(reply.handled);
6054
6055 let Some(transmit) = state.local.checklist_set.poll_transmit(now) else {
6056 unreachable!();
6057 };
6058
6059 let response = Message::from_bytes(&transmit.transmit.data).unwrap();
6060 assert!(matches!(
6061 local_auth.validate_incoming_message(&response).unwrap(),
6062 Some(IntegrityAlgorithm::Sha1)
6063 ));
6064 assert!(remote_agent.handle_stun_message(&response, transmit.transmit.from));
6065 assert_eq!(transmit.transmit.from, local_addr);
6066 assert!(response.has_class(MessageClass::Success));
6067 info!("have prflx response");
6068
6069 let mut prflx_remote_candidate = unknown_remote_peer.candidate.clone();
6071 prflx_remote_candidate.candidate_type = CandidateType::PeerReflexive;
6072 let pair = CandidatePair::new(
6073 state.local.peer.candidate.clone(),
6074 unknown_remote_peer.candidate.clone(),
6075 );
6076 state.local_list().dump_check_state();
6077 let triggered_check = state
6078 .local_list()
6079 .matching_check(&pair, Nominate::False)
6080 .unwrap();
6081 assert_eq!(triggered_check.state(), CandidatePairState::Waiting);
6082 let check_id = triggered_check.conncheck_id;
6083
6084 let now = wait_advance(&mut state.local.checklist_set, now);
6085 let CheckListSetPollRet::Event {
6086 checklist_id: _,
6087 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
6088 } = state.local.checklist_set.poll(now)
6089 else {
6090 unreachable!();
6091 };
6092
6093 info!("perform triggered check");
6095 send_next_check_and_response(&state.local.peer, &unknown_remote_peer)
6096 .perform(&mut state.local.checklist_set, now);
6097
6098 info!("have reply to triggered check");
6099 let triggered_check = state.local_list().check_by_id(check_id).unwrap();
6100 assert_eq!(triggered_check.state(), CandidatePairState::Succeeded);
6101 let nominated_check = state
6102 .local_list()
6103 .matching_check(&pair, Nominate::True)
6104 .unwrap();
6105 assert_eq!(nominated_check.state(), CandidatePairState::Waiting);
6106 let check_id = nominated_check.conncheck_id;
6107 info!("perform nominated check");
6108 let now = wait_advance(&mut state.local.checklist_set, now);
6109 send_next_check_and_response(&state.local.peer, &unknown_remote_peer)
6110 .perform(&mut state.local.checklist_set, now);
6111
6112 info!("have reply to nominated check");
6113 let nominated_check = state.local_list().check_by_id(check_id).unwrap();
6114 assert_eq!(nominated_check.state(), CandidatePairState::Succeeded);
6115
6116 let CheckListSetPollRet::Event {
6117 checklist_id: _,
6118 event: ConnCheckEvent::SelectedPair(_cid, _selected_pair),
6119 } = state.local.checklist_set.poll(now)
6120 else {
6121 unreachable!();
6122 };
6123 let CheckListSetPollRet::Event {
6124 checklist_id: _,
6125 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connected),
6126 } = state.local.checklist_set.poll(now)
6127 else {
6128 unreachable!();
6129 };
6130
6131 assert!(matches!(
6132 state.local.checklist_set.poll(now),
6133 CheckListSetPollRet::Completed,
6134 ));
6135
6136 state.local.checklist_set.close(now);
6137
6138 let CheckListSetPollRet::RemoveSocket {
6139 checklist_id: _,
6140 component_id: 1,
6141 transport: TransportType::Udp,
6142 local_addr,
6143 remote_addr: _,
6144 } = state.local.checklist_set.poll(now)
6145 else {
6146 unreachable!();
6147 };
6148 assert_eq!(local_addr, pair.local.base_address);
6149 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
6150 unreachable!();
6151 };
6152 }
6153
6154 #[test]
6155 fn conncheck_response_prflx() {
6156 let _log = crate::tests::test_init_log();
6157 let mut state = FineControl::builder().build();
6158 let now = Instant::ZERO;
6159
6160 let pair = CandidatePair::new(
6161 state.local.peer.candidate.clone(),
6162 state.remote.candidate.clone(),
6163 );
6164 let initial_check = state
6165 .local_list()
6166 .matching_check(&pair, Nominate::False)
6167 .unwrap();
6168 assert_eq!(initial_check.state(), CandidatePairState::Frozen);
6169 let check_id = initial_check.conncheck_id;
6170
6171 let unknown_remote_peer = Peer::builder()
6172 .foundation("1")
6173 .local_credentials(state.remote.local_credentials.clone().unwrap())
6174 .remote_credentials(state.local.peer.local_credentials.clone().unwrap())
6175 .build();
6176 let (remote_agent, _remote_auth, _local_auth) = unknown_remote_peer.stun_agent();
6177
6178 let CheckListSetPollRet::Event {
6179 checklist_id: _,
6180 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
6181 } = state.local.checklist_set.poll(now)
6182 else {
6183 unreachable!();
6184 };
6185
6186 send_next_check_and_response(&state.local.peer, &state.remote)
6189 .response_address(remote_agent.local_addr())
6190 .perform(&mut state.local.checklist_set, now);
6191 let initial_check = state.local_list().check_by_id(check_id).unwrap();
6192 assert_eq!(initial_check.state(), CandidatePairState::Succeeded);
6193
6194 let unknown_pair = CandidatePair::new(
6196 Candidate::builder(
6197 unknown_remote_peer.candidate.component_id,
6198 CandidateType::PeerReflexive,
6199 TransportType::Udp,
6200 "0",
6201 unknown_remote_peer.candidate.address,
6202 )
6203 .base_address(state.local.peer.candidate.base_address)
6204 .build(),
6205 state.remote.candidate.clone(),
6206 );
6207 let nominated_check = state
6208 .local_list()
6209 .matching_check(&unknown_pair, Nominate::True)
6210 .unwrap();
6211 assert_eq!(nominated_check.state(), CandidatePairState::Waiting);
6212 let check_id = nominated_check.conncheck_id;
6213
6214 state.local_list().dump_check_state();
6215
6216 let now = wait_advance(&mut state.local.checklist_set, now);
6217 send_next_check_and_response(&state.local.peer, &state.remote)
6218 .response_address(unknown_remote_peer.candidate.address)
6219 .perform(&mut state.local.checklist_set, now);
6220 let nominated_check = state.local_list().check_by_id(check_id).unwrap();
6221 assert_eq!(nominated_check.state(), CandidatePairState::Succeeded);
6222
6223 let CheckListSetPollRet::Event {
6224 checklist_id: _,
6225 event: ConnCheckEvent::SelectedPair(_cid, _selected_pair),
6226 } = state.local.checklist_set.poll(now)
6227 else {
6228 unreachable!();
6229 };
6230 let CheckListSetPollRet::Event {
6231 checklist_id: _,
6232 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connected),
6233 } = state.local.checklist_set.poll(now)
6234 else {
6235 unreachable!();
6236 };
6237
6238 assert!(matches!(
6239 state.local.checklist_set.poll(now),
6240 CheckListSetPollRet::Completed,
6241 ));
6242
6243 state.local.checklist_set.close(now);
6244
6245 let CheckListSetPollRet::RemoveSocket {
6246 checklist_id: _,
6247 component_id: 1,
6248 transport: TransportType::Udp,
6249 local_addr,
6250 remote_addr: _,
6251 } = state.local.checklist_set.poll(now)
6252 else {
6253 unreachable!();
6254 };
6255 assert_eq!(local_addr, pair.local.base_address);
6256 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
6257 unreachable!();
6258 };
6259 }
6260
6261 #[test]
6262 fn conncheck_trickle_ice() {
6263 let _log = crate::tests::test_init_log();
6264 let mut state = FineControl::builder().trickle_ice(true).build();
6265 let now = Instant::ZERO;
6266 assert_eq!(state.local.component_id, 1);
6267
6268 let set_ret = state.local.checklist_set.poll(now);
6271 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
6273
6274 let local_candidate = state.local.peer.candidate.clone();
6275 state.local_list().add_local_candidate(local_candidate);
6276
6277 let set_ret = state.local.checklist_set.poll(now);
6278 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
6280
6281 let remote_candidate = state.remote.candidate.clone();
6282 state.local_list().add_remote_candidate(remote_candidate);
6283
6284 let pair = CandidatePair::new(
6288 state.local.peer.candidate.clone(),
6289 state.remote.candidate.clone(),
6290 );
6291 let check = state
6292 .local_list()
6293 .matching_check(&pair, Nominate::False)
6294 .unwrap();
6295 assert_eq!(check.state(), CandidatePairState::Waiting);
6296 let check_id = check.conncheck_id;
6297
6298 let CheckListSetPollRet::Event {
6299 checklist_id: _,
6300 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
6301 } = state.local.checklist_set.poll(now)
6302 else {
6303 unreachable!();
6304 };
6305
6306 send_next_check_and_response(&state.local.peer, &state.remote)
6308 .perform(&mut state.local.checklist_set, now);
6309 let check = state.local_list().check_by_id(check_id).unwrap();
6310 assert_eq!(check.state(), CandidatePairState::Succeeded);
6311
6312 state.local_list().dump_check_state();
6313
6314 let now = wait_advance(&mut state.local.checklist_set, now);
6315 state.check_nomination(&pair, now);
6316
6317 state.local.checklist_set.close(now);
6318
6319 let CheckListSetPollRet::RemoveSocket {
6320 checklist_id: _,
6321 component_id: 1,
6322 transport: TransportType::Udp,
6323 local_addr,
6324 remote_addr: _,
6325 } = state.local.checklist_set.poll(now)
6326 else {
6327 unreachable!();
6328 };
6329 assert_eq!(local_addr, pair.local.base_address);
6330 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
6331 unreachable!();
6332 };
6333 }
6334
6335 #[test]
6336 fn conncheck_trickle_ice_no_remote_candidates_fail() {
6337 let _log = crate::tests::test_init_log();
6338 let mut state = FineControl::builder().trickle_ice(true).build();
6339 let local_candidate = state.local.peer.candidate.clone();
6340
6341 let now = Instant::ZERO;
6344
6345 let set_ret = state.local.checklist_set.poll(now);
6346 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
6348
6349 state.local_list().add_local_candidate(local_candidate);
6350 state.local_list().end_of_local_candidates();
6351
6352 let set_ret = state.local.checklist_set.poll(now);
6353 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
6355
6356 state.local_list().end_of_remote_candidates();
6357
6358 let CheckListSetPollRet::Event {
6359 checklist_id: _,
6360 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Failed),
6361 } = state.local.checklist_set.poll(now)
6362 else {
6363 unreachable!();
6364 };
6365
6366 let set_ret = state.local.checklist_set.poll(now);
6367 assert!(matches!(set_ret, CheckListSetPollRet::Completed));
6368 assert_eq!(state.local_list().state(), CheckListState::Failed);
6370
6371 state.local.checklist_set.close(now);
6372 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
6373 unreachable!();
6374 };
6375 }
6376
6377 #[test]
6378 fn conncheck_set_trickle_no_checks() {
6379 let _log = crate::tests::test_init_log();
6380 let mut set = ConnCheckListSet::builder(0, false)
6382 .trickle_ice(true)
6383 .build();
6384 let _list1_id = set.new_list();
6385 let _list2_id = set.new_list();
6386
6387 let now = Instant::ZERO;
6388 let CheckListSetPollRet::WaitUntil(_now) = set.poll(now) else {
6389 unreachable!();
6390 };
6391
6392 set.close(now);
6393
6394 let CheckListSetPollRet::Completed = set.poll(now) else {
6395 unreachable!();
6396 };
6397
6398 let CheckListSetPollRet::Closed = set.poll(now) else {
6399 unreachable!();
6400 };
6401 }
6402
6403 #[test]
6404 fn conncheck_incoming_request_while_local_in_progress() {
6405 let _log = crate::tests::test_init_log();
6406 let mut state = FineControl::builder().build();
6407
6408 let pair = CandidatePair::new(
6409 state.local.peer.candidate.clone(),
6410 state.remote.candidate.clone(),
6411 );
6412 let initial_check = state
6413 .local_list()
6414 .matching_check(&pair, Nominate::False)
6415 .unwrap();
6416 assert_eq!(initial_check.state(), CandidatePairState::Frozen);
6417 let check_id = initial_check.conncheck_id;
6418
6419 let now = Instant::ZERO;
6422
6423 let CheckListSetPollRet::Event {
6424 checklist_id: _,
6425 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
6426 } = state.local.checklist_set.poll(now)
6427 else {
6428 unreachable!();
6429 };
6430
6431 let set_ret = state.local.checklist_set.poll(now);
6433 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
6434 let Some(_) = state.local.checklist_set.poll_transmit(now) else {
6435 unreachable!()
6436 };
6437 let initial_check = state.local_list().check_by_id(check_id).unwrap();
6438 assert_eq!(initial_check.state(), CandidatePairState::InProgress);
6439 let set_ret = state.local.checklist_set.poll(now);
6440 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
6441
6442 let (mut remote_agent, _remote_auth, _local_auth) = state.remote.stun_agent();
6443 let local_addr = state.local.peer.stun_agent().0.local_addr();
6444 let transmit = remote_generate_check(
6445 &state.remote,
6446 &mut remote_agent,
6447 local_addr,
6448 false,
6449 false,
6450 now,
6451 );
6452
6453 info!("sending request");
6454 let reply =
6455 state
6456 .local
6457 .checklist_set
6458 .incoming_data(state.local.checklist_id, 1, transmit, now);
6459 assert!(reply.handled);
6460 state.local.checklist_set.poll_transmit(now).unwrap();
6462 let now = wait_advance(&mut state.local.checklist_set, now);
6463
6464 let initial_check = state.local_list().check_by_id(check_id).unwrap();
6467 assert_eq!(initial_check.state(), CandidatePairState::InProgress);
6468 let triggered_check = state
6472 .local_list()
6473 .pairs
6474 .iter()
6475 .find(|check| {
6476 check.conncheck_id != check_id
6477 && check.pair == pair
6478 && Nominate::False == check.nominate
6479 })
6480 .unwrap();
6481 assert_ne!(check_id, triggered_check.conncheck_id);
6482 let check_id = triggered_check.conncheck_id;
6483 info!("perform triggered check");
6484 send_next_check_and_response(&state.local.peer, &state.remote)
6485 .perform(&mut state.local.checklist_set, now);
6486 let triggered_check = state.local_list().check_by_id(check_id).unwrap();
6487 assert_eq!(triggered_check.state(), CandidatePairState::Succeeded);
6488
6489 let now = wait_advance(&mut state.local.checklist_set, now);
6490 state.check_nomination(&pair, now);
6491
6492 state.local.checklist_set.close(now);
6493
6494 let CheckListSetPollRet::RemoveSocket {
6495 checklist_id: _,
6496 component_id: 1,
6497 transport: TransportType::Udp,
6498 local_addr,
6499 remote_addr: _,
6500 } = state.local.checklist_set.poll(now)
6501 else {
6502 unreachable!();
6503 };
6504 assert_eq!(local_addr, pair.local.base_address);
6505 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
6506 unreachable!();
6507 };
6508 }
6509
6510 #[test]
6511 fn conncheck_check_double_triggered() {
6512 let _log = crate::tests::test_init_log();
6513 let mut state = FineControl::builder().controlling(false).build();
6514
6515 let pair = CandidatePair::new(
6516 state.local.peer.candidate.clone(),
6517 state.remote.candidate.clone(),
6518 );
6519 let initial_check = state
6520 .local_list()
6521 .matching_check(&pair, Nominate::False)
6522 .unwrap();
6523 assert_eq!(initial_check.state(), CandidatePairState::Frozen);
6524 let check_id = initial_check.conncheck_id;
6525
6526 let now = Instant::ZERO;
6529
6530 let CheckListSetPollRet::Event {
6531 checklist_id: _,
6532 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
6533 } = state.local.checklist_set.poll(now)
6534 else {
6535 unreachable!();
6536 };
6537
6538 send_next_check_and_response(&state.local.peer, &state.remote)
6541 .error_response(ErrorCode::ROLE_CONFLICT)
6542 .perform(&mut state.local.checklist_set, now);
6543 let initial_check = state.local_list().check_by_id(check_id).unwrap();
6544 assert_eq!(initial_check.state(), CandidatePairState::Failed);
6545
6546 let triggered_check = state
6548 .local_list()
6549 .matching_check(&pair, Nominate::False)
6550 .unwrap();
6551 let check_id = triggered_check.conncheck_id;
6552 let pair = triggered_check.pair.clone();
6553 assert!(state.local_list().is_triggered(&pair));
6554 let now = wait_advance(&mut state.local.checklist_set, now);
6555 let set_ret = state.local.checklist_set.poll(now);
6556 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
6557
6558 let (mut remote_agent, _remote_auth, _local_auth) = state.remote.stun_agent();
6561 let local_addr = state.local.peer.stun_agent().0.local_addr();
6562 let transmit = remote_generate_check(
6563 &state.remote,
6564 &mut remote_agent,
6565 local_addr,
6566 false,
6567 false,
6568 now,
6569 );
6570
6571 info!("sending request");
6572 let reply =
6573 state
6574 .local
6575 .checklist_set
6576 .incoming_data(state.local.checklist_id, 1, transmit, now);
6577 assert!(reply.handled);
6578 let Some(CheckListSetTransmit {
6580 checklist_id: _,
6581 transmit: _,
6582 }) = state.local.checklist_set.poll_transmit(now)
6583 else {
6584 unreachable!()
6585 };
6586 state.local.checklist_set.poll_transmit(now).unwrap();
6588
6589 let triggered_check = state.local_list().check_by_id(check_id).unwrap();
6592 assert_eq!(triggered_check.state(), CandidatePairState::InProgress);
6593
6594 let triggered_check = state
6596 .local_list()
6597 .matching_check(&pair, Nominate::False)
6598 .unwrap();
6599 assert_eq!(check_id, triggered_check.conncheck_id);
6600
6601 info!("perform triggered check 2");
6605 let now = wait_advance(&mut state.local.checklist_set, now);
6606 send_next_check_and_response(&state.local.peer, &state.remote)
6607 .perform(&mut state.local.checklist_set, now);
6608 let triggered_check = state.local_list().check_by_id(check_id).unwrap();
6610 assert_eq!(triggered_check.state(), CandidatePairState::InProgress);
6611
6612 let now = wait_advance(&mut state.local.checklist_set, now);
6613 state.check_nomination(&pair, now);
6614
6615 state.local.checklist_set.close(now);
6616
6617 let CheckListSetPollRet::RemoveSocket {
6618 checklist_id: _,
6619 component_id: 1,
6620 transport: TransportType::Udp,
6621 local_addr,
6622 remote_addr: _,
6623 } = state.local.checklist_set.poll(now)
6624 else {
6625 unreachable!();
6626 };
6627 assert_eq!(local_addr, pair.local.base_address);
6628 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
6629 unreachable!();
6630 };
6631 }
6632
6633 #[test]
6634 fn conncheck_trickle_ice_prflx_check_before_remote_credentials() {
6635 let _log = crate::tests::test_init_log();
6636 let mut state = FineControl::builder()
6637 .controlling(true)
6638 .trickle_ice(true)
6639 .build();
6640
6641 let local_candidate = state.local.peer.candidate.clone();
6642 state.local_list().add_local_candidate(local_candidate);
6643
6644 let remote_credentials = generate_random_credentials();
6645 state.local.peer.remote_credentials = Some(remote_credentials.clone());
6646 state.remote.local_credentials = Some(remote_credentials.clone());
6647 let remote_peer = Peer::builder()
6648 .local_addr(state.remote.candidate.base_address)
6649 .foundation(&state.remote.candidate.foundation)
6650 .local_credentials(remote_credentials.clone())
6651 .remote_credentials(state.local.peer.local_credentials.clone().unwrap())
6652 .build();
6653 let (mut remote_agent, _remote_auth, _local_auth) = state.remote.stun_agent();
6654 let now = Instant::ZERO;
6655 let to = state.local.peer.candidate.base_address;
6656 let transmit =
6657 remote_generate_check(&remote_peer, &mut remote_agent, to, false, false, now);
6658
6659 info!("sending prflx request");
6660 let reply =
6661 state
6662 .local
6663 .checklist_set
6664 .incoming_data(state.local.checklist_id, 1, transmit, now);
6665 assert!(reply.handled);
6666
6667 let mut peer_reflexive_remote = state.remote.candidate.clone();
6668 peer_reflexive_remote.candidate_type = CandidateType::PeerReflexive;
6669 peer_reflexive_remote.foundation = String::from("rflx");
6671 let pair = CandidatePair::new(state.local.peer.candidate.clone(), peer_reflexive_remote);
6672
6673 let prflx_check = state
6674 .local_list()
6675 .matching_check(&pair, Nominate::False)
6676 .unwrap();
6677 assert_eq!(prflx_check.state(), CandidatePairState::Waiting);
6678 let check_id = prflx_check.conncheck_id;
6679 let ret = state.local.checklist_set.poll_transmit(now);
6680 let Some(CheckListSetTransmit {
6682 checklist_id: _,
6683 transmit,
6684 }) = ret
6685 else {
6686 error!("{ret:?}");
6687 unreachable!()
6688 };
6689 assert_eq!(transmit.from, state.local.peer.candidate.base_address);
6690 assert_eq!(transmit.to, state.remote.candidate.base_address);
6691 let response = Message::from_bytes(&transmit.data).unwrap();
6692 response
6693 .validate_integrity(&MessageIntegrityCredentials::ShortTerm(
6694 state.local.peer.local_credentials.clone().unwrap().into(),
6695 ))
6696 .unwrap();
6697
6698 let now = wait_advance(&mut state.local.checklist_set, now);
6699 let CheckListSetPollRet::Event {
6700 checklist_id: _,
6701 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
6702 } = state.local.checklist_set.poll(now)
6703 else {
6704 unreachable!();
6705 };
6706
6707 send_next_check_and_response(&state.local.peer, &state.remote)
6709 .unhandled_reply()
6710 .perform(&mut state.local.checklist_set, now);
6711 let prflx_check = state.local_list().check_by_id(check_id).unwrap();
6712 assert_eq!(prflx_check.state(), CandidatePairState::InProgress);
6713
6714 info!("Correct remote credentials set");
6716 state.set_remote_credentials(remote_credentials);
6717
6718 let now = wait_advance(&mut state.local.checklist_set, now);
6720 send_next_check_and_response(&state.local.peer, &state.remote)
6721 .perform(&mut state.local.checklist_set, now);
6722 let prflx_check = state
6723 .local_list()
6724 .matching_check(&pair, Nominate::False)
6725 .unwrap();
6726 assert_eq!(prflx_check.state(), CandidatePairState::Succeeded);
6727
6728 let now = wait_advance(&mut state.local.checklist_set, now);
6729 state.check_nomination(&pair, now);
6730
6731 state.local.checklist_set.close(now);
6732
6733 let CheckListSetPollRet::RemoveSocket {
6734 checklist_id: _,
6735 component_id: 1,
6736 transport: TransportType::Udp,
6737 local_addr,
6738 remote_addr: _,
6739 } = state.local.checklist_set.poll(now)
6740 else {
6741 unreachable!();
6742 };
6743 assert_eq!(local_addr, pair.local.base_address);
6744 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
6745 unreachable!();
6746 };
6747 }
6748
6749 fn turn_allocate(
6750 client: &mut TurnClient,
6751 server: &mut TurnServer,
6752 turn_alloc_addr: SocketAddr,
6753 now: Instant,
6754 ) -> Instant {
6755 let transmit = client.poll_transmit(now).unwrap();
6756 let msg = Message::from_bytes(&transmit.data).unwrap();
6757 assert!(msg.has_method(ALLOCATE));
6758 let transmit = server.recv(transmit, now).unwrap().build();
6759 let ret = client.recv(transmit, now);
6760 assert!(matches!(ret, TurnRecvRet::Handled));
6761 let TurnPollRet::WaitUntil(now) = client.poll(now) else {
6762 unreachable!();
6763 };
6764 let transmit = client.poll_transmit(now).unwrap();
6765 let msg = Message::from_bytes(&transmit.data).unwrap();
6766 assert!(msg.has_method(ALLOCATE));
6767 assert!(server.recv(transmit, now).is_none());
6768 let TurnServerPollRet::AllocateSocket {
6769 transport,
6770 listen_addr,
6771 client_addr,
6772 allocation_transport,
6773 family,
6774 } = server.poll(now)
6775 else {
6776 unreachable!();
6777 };
6778 server.allocated_socket(
6779 transport,
6780 listen_addr,
6781 client_addr,
6782 allocation_transport,
6783 family,
6784 Ok(turn_alloc_addr),
6785 now,
6786 );
6787 let transmit = server.poll_transmit(now).unwrap();
6788 let ret = client.recv(transmit, now);
6789 assert!(matches!(ret, TurnRecvRet::Handled));
6790 assert!(client.relayed_addresses().count() > 0);
6791 now
6792 }
6793
6794 fn set_handle_permission(
6795 set: &mut ConnCheckListSet,
6796 turn_server: &mut TurnServer,
6797 now: Instant,
6798 ) -> Instant {
6799 let Some(transmit) = set.poll_transmit(now) else {
6800 unreachable!()
6801 };
6802 let msg = Message::from_bytes(&transmit.transmit.data).unwrap();
6803 assert_eq!(msg.method(), CREATE_PERMISSION);
6804 let checklist_id = transmit.checklist_id;
6805 let transmit = turn_server.recv(transmit.transmit, now).unwrap().build();
6806 let msg = Message::from_bytes(&transmit.data).unwrap();
6807 assert_eq!(msg.method(), CREATE_PERMISSION);
6808
6809 let transmit = Transmit::new(
6810 Data::from(transmit.data.as_slice()),
6811 transmit.transport,
6812 transmit.from,
6813 transmit.to,
6814 );
6815 set.incoming_data(checklist_id, 1, transmit, now);
6816 match set.poll(now) {
6817 CheckListSetPollRet::WaitUntil(now) => now,
6818 ret => {
6819 error!("{ret:?}");
6820 unreachable!()
6821 }
6822 }
6823 }
6824
6825 fn turn_allocate_udp(client_transport: TransportType) {
6826 let local_addr = "127.0.0.1:1".parse::<SocketAddr>().unwrap();
6827 let turn_addr = "127.0.0.1:3478".parse::<SocketAddr>().unwrap();
6828 let turn_alloc_addr = "127.0.0.1:3000".parse::<SocketAddr>().unwrap();
6829 let turn_credentials = TurnCredentials::new("tuser", "tpass");
6830 let mut state = FineControl::builder()
6831 .local_candidate(
6832 Candidate::builder(
6833 1,
6834 CandidateType::Relayed,
6835 TransportType::Udp,
6836 "0",
6837 turn_alloc_addr,
6838 )
6839 .priority(8000)
6840 .base_address(turn_alloc_addr)
6841 .related_address(local_addr)
6842 .build(),
6843 )
6844 .trickle_ice(true)
6845 .build();
6846
6847 let now = Instant::ZERO;
6848 let mut turn_server = TurnServer::new(client_transport, turn_addr, "realm".to_owned());
6849 turn_server.add_user(
6850 turn_credentials.username().to_owned(),
6851 turn_credentials.password().to_owned(),
6852 );
6853 let mut turn_client = match client_transport {
6854 TransportType::Udp => TurnClientUdp::allocate(
6855 local_addr,
6856 turn_addr,
6857 turn_client_proto::api::TurnConfig::new(turn_credentials),
6858 )
6859 .into(),
6860 TransportType::Tcp => TurnClientTcp::allocate(
6861 local_addr,
6862 turn_addr,
6863 turn_client_proto::api::TurnConfig::new(turn_credentials),
6864 )
6865 .into(),
6866 };
6867 let now = turn_allocate(&mut turn_client, &mut turn_server, turn_alloc_addr, now);
6868
6869 let remote_candidate = state.remote.candidate.clone();
6870 state.local_list().add_remote_candidate(remote_candidate);
6871 let local_candidate = state.local.peer.candidate.clone();
6872 state
6873 .local_list()
6874 .add_local_gathered_candidate(GatheredCandidate {
6875 candidate: local_candidate,
6876 turn_agent: Some(Box::new(turn_client)),
6877 });
6878 assert_eq!(state.local.component_id, 1);
6879
6880 let now = match state.local.checklist_set.poll(now) {
6881 CheckListSetPollRet::WaitUntil(now) => now,
6882 ret => {
6883 error!("{ret:?}");
6884 unreachable!()
6885 }
6886 };
6887 let now = set_handle_permission(&mut state.local.checklist_set, &mut turn_server, now);
6888
6889 let CheckListSetPollRet::Event {
6890 checklist_id: _,
6891 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
6892 } = state.local.checklist_set.poll(now)
6893 else {
6894 unreachable!();
6895 };
6896
6897 let pair = CandidatePair::new(
6898 state.local.peer.candidate.clone(),
6899 state.remote.candidate.clone(),
6900 );
6901 let check = state
6902 .local_list()
6903 .matching_check(&pair, Nominate::False)
6904 .unwrap();
6905 assert_eq!(check.state(), CandidatePairState::InProgress);
6906 let check_id = check.conncheck_id;
6907
6908 let mut response =
6910 send_next_check_and_response(&state.local.peer, &state.remote).turn_server(turn_server);
6911 response.perform(&mut state.local.checklist_set, now);
6912 let turn_server = response.take_turn_server().unwrap();
6913 let check = state.local_list().check_by_id(check_id).unwrap();
6914 assert_eq!(check.state(), CandidatePairState::Succeeded);
6915
6916 let nominate_check = state
6919 .local_list()
6920 .matching_check(&pair, Nominate::True)
6921 .unwrap();
6922 let pair = nominate_check.pair.clone();
6923 let check_id = nominate_check.conncheck_id;
6924 assert!(state.local_list().is_triggered(&pair));
6925
6926 let now = wait_advance(&mut state.local.checklist_set, now);
6928 let mut response =
6929 send_next_check_and_response(&state.local.peer, &state.remote).turn_server(turn_server);
6930 response.perform(&mut state.local.checklist_set, now);
6931 let mut turn_server = response.take_turn_server().unwrap();
6932
6933 error!("nominated id {check_id:?}");
6934 let nominate_check = state.local_list().check_by_id(check_id).unwrap();
6935 assert_eq!(nominate_check.state(), CandidatePairState::Succeeded);
6936
6937 assert_eq!(state.local_list().state(), CheckListState::Completed);
6939
6940 let CheckListSetPollRet::Event {
6941 checklist_id: _,
6942 event: ConnCheckEvent::SelectedPair(_cid, _selected_pair),
6943 } = state.local.checklist_set.poll(now)
6944 else {
6945 unreachable!();
6946 };
6947 let CheckListSetPollRet::Event {
6948 checklist_id: _,
6949 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connected),
6950 } = state.local.checklist_set.poll(now)
6951 else {
6952 unreachable!();
6953 };
6954
6955 assert!(matches!(
6957 state.local.checklist_set.poll(now),
6958 CheckListSetPollRet::Completed
6959 ));
6960
6961 state.local.checklist_set.close(now);
6962
6963 let CheckListSetPollRet::WaitUntil(now) = state.local.checklist_set.poll(now) else {
6965 unreachable!();
6966 };
6967
6968 let Some(transmit) = state.local.checklist_set.poll_transmit(now) else {
6969 unreachable!();
6970 };
6971
6972 let checklist_id = transmit.checklist_id;
6973 let transmit = turn_server.recv(transmit.transmit, now).unwrap().build();
6974 let transmit = Transmit::new(
6975 Data::from(transmit.data.as_slice()),
6976 transmit.transport,
6977 transmit.from,
6978 transmit.to,
6979 );
6980 let reply = state
6981 .local
6982 .checklist_set
6983 .incoming_data(checklist_id, 1, transmit, now);
6984 assert!(reply.handled);
6985
6986 let CheckListSetPollRet::RemoveSocket {
6987 checklist_id: _,
6988 component_id: 1,
6989 transport,
6990 local_addr: remove_local_addr,
6991 remote_addr: _,
6992 } = state.local.checklist_set.poll(now)
6993 else {
6994 unreachable!();
6995 };
6996 assert_eq!(transport, client_transport);
6997 assert_eq!(remove_local_addr, local_addr);
6998
6999 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
7000 unreachable!();
7001 };
7002 }
7003
7004 #[test]
7005 fn turn_udp_allocate_udp() {
7006 let _log = crate::tests::test_init_log();
7007 turn_allocate_udp(TransportType::Udp);
7008 }
7009
7010 #[test]
7011 fn turn_tcp_allocate_udp() {
7012 let _log = crate::tests::test_init_log();
7013 turn_allocate_udp(TransportType::Tcp);
7014 }
7015
7016 #[test]
7017 fn turn_udp_delayed_create_permission() {
7018 let _log = crate::tests::test_init_log();
7019 let local_addr = "127.0.0.1:1".parse::<SocketAddr>().unwrap();
7020 let turn_addr = "127.0.0.1:3478".parse::<SocketAddr>().unwrap();
7021 let turn_alloc_addr = "127.0.0.1:3000".parse::<SocketAddr>().unwrap();
7022 let turn_credentials = TurnCredentials::new("tuser", "tpass");
7023 let mut state = FineControl::builder()
7024 .local_candidate(
7025 Candidate::builder(
7026 1,
7027 CandidateType::Relayed,
7028 TransportType::Udp,
7029 "0",
7030 turn_alloc_addr,
7031 )
7032 .priority(8000)
7033 .base_address(turn_alloc_addr)
7034 .related_address(local_addr)
7035 .build(),
7036 )
7037 .trickle_ice(true)
7038 .build();
7039
7040 let now = Instant::ZERO;
7041 let mut turn_server = TurnServer::new(TransportType::Udp, turn_addr, "realm".to_owned());
7042 turn_server.add_user(
7043 turn_credentials.username().to_owned(),
7044 turn_credentials.password().to_owned(),
7045 );
7046 let mut turn_client = TurnClientUdp::allocate(
7047 local_addr,
7048 turn_addr,
7049 turn_client_proto::api::TurnConfig::new(turn_credentials),
7050 )
7051 .into();
7052 let now = turn_allocate(&mut turn_client, &mut turn_server, turn_alloc_addr, now);
7053
7054 let remote_candidate = state.remote.candidate.clone();
7055 state.local_list().add_remote_candidate(remote_candidate);
7056 let local_candidate = state.local.peer.candidate.clone();
7057 state
7058 .local_list()
7059 .add_local_gathered_candidate(GatheredCandidate {
7060 candidate: local_candidate,
7061 turn_agent: Some(Box::new(turn_client)),
7062 });
7063 assert_eq!(state.local.component_id, 1);
7064
7065 let pair = CandidatePair::new(
7066 state.local.peer.candidate.clone(),
7067 state.remote.candidate.clone(),
7068 );
7069 let check = state
7070 .local_list()
7071 .matching_check(&pair, Nominate::False)
7072 .unwrap();
7073 assert_eq!(check.state(), CandidatePairState::Frozen);
7074 let check_id = check.conncheck_id;
7075
7076 let now = match state.local.checklist_set.poll(now) {
7077 CheckListSetPollRet::WaitUntil(now) => now,
7078 ret => {
7079 error!("{ret:?}");
7080 unreachable!()
7081 }
7082 };
7083 let Some(transmit) = state.local.checklist_set.poll_transmit(now) else {
7084 unreachable!()
7085 };
7086 let msg = Message::from_bytes(&transmit.transmit.data).unwrap();
7087 assert_eq!(msg.method(), CREATE_PERMISSION);
7088 let checklist_id = transmit.checklist_id;
7089 let transmit = turn_server.recv(transmit.transmit, now).unwrap().build();
7090 let msg = Message::from_bytes(&transmit.data).unwrap();
7091 assert_eq!(msg.method(), CREATE_PERMISSION);
7092
7093 let CheckListSetPollRet::WaitUntil(now) = state.local.checklist_set.poll(now) else {
7094 unreachable!();
7095 };
7096
7097 let transmit = Transmit::new(
7098 Data::from(transmit.data.as_slice()),
7099 transmit.transport,
7100 transmit.from,
7101 transmit.to,
7102 );
7103 state
7104 .local
7105 .checklist_set
7106 .incoming_data(checklist_id, 1, transmit, now);
7107
7108 let CheckListSetPollRet::Event {
7109 checklist_id: _,
7110 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
7111 } = state.local.checklist_set.poll(now)
7112 else {
7113 unreachable!();
7114 };
7115
7116 let mut response =
7118 send_next_check_and_response(&state.local.peer, &state.remote).turn_server(turn_server);
7119 response.perform(&mut state.local.checklist_set, now);
7120 let turn_server = response.take_turn_server().unwrap();
7121 let check = state.local_list().check_by_id(check_id).unwrap();
7122 assert_eq!(check.state(), CandidatePairState::Succeeded);
7123
7124 let nominate_check = state
7127 .local_list()
7128 .matching_check(&pair, Nominate::True)
7129 .unwrap();
7130 let pair = nominate_check.pair.clone();
7131 let check_id = nominate_check.conncheck_id;
7132 assert!(state.local_list().is_triggered(&pair));
7133
7134 let now = wait_advance(&mut state.local.checklist_set, now);
7136 let mut response =
7137 send_next_check_and_response(&state.local.peer, &state.remote).turn_server(turn_server);
7138 response.perform(&mut state.local.checklist_set, now);
7139
7140 error!("nominated id {check_id:?}");
7141 let nominate_check = state.local_list().check_by_id(check_id).unwrap();
7142 assert_eq!(nominate_check.state(), CandidatePairState::Succeeded);
7143
7144 assert_eq!(state.local_list().state(), CheckListState::Completed);
7146
7147 let CheckListSetPollRet::Event {
7148 checklist_id: _,
7149 event: ConnCheckEvent::SelectedPair(_cid, _selected_pair),
7150 } = state.local.checklist_set.poll(now)
7151 else {
7152 unreachable!();
7153 };
7154 let CheckListSetPollRet::Event {
7155 checklist_id: _,
7156 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connected),
7157 } = state.local.checklist_set.poll(now)
7158 else {
7159 unreachable!();
7160 };
7161
7162 assert!(matches!(
7164 state.local.checklist_set.poll(now),
7165 CheckListSetPollRet::Completed
7166 ));
7167 }
7168
7169 fn set_handle_tcp_connect(
7170 set: &mut ConnCheckListSet,
7171 turn_server: &mut TurnServer,
7172 tcp_local_addr: SocketAddr,
7173 now: Instant,
7174 ) -> Instant {
7175 let transmit = set.poll_transmit(now).unwrap();
7176 let msg = Message::from_bytes(&transmit.transmit.data).unwrap();
7177 assert_eq!(msg.method(), CONNECT);
7178 let checklist_id = transmit.checklist_id;
7179 assert!(turn_server.recv(transmit.transmit, now).is_none());
7180
7181 let TurnServerPollRet::TcpConnect {
7182 relayed_addr,
7183 peer_addr,
7184 listen_addr,
7185 client_addr,
7186 } = turn_server.poll(now)
7187 else {
7188 unreachable!();
7189 };
7190 turn_server.tcp_connected(
7191 relayed_addr,
7192 peer_addr,
7193 listen_addr,
7194 client_addr,
7195 Ok(listen_addr),
7196 now,
7197 );
7198 let transmit = turn_server.poll_transmit(now).unwrap();
7199 let msg = Message::from_bytes(&transmit.data).unwrap();
7200 assert_eq!(msg.method(), CONNECT);
7201
7202 let transmit = Transmit::new(
7203 Data::from(transmit.data.as_slice()),
7204 transmit.transport,
7205 transmit.from,
7206 transmit.to,
7207 );
7208 let reply = set.incoming_data(checklist_id, 1, transmit, now);
7209 assert!(reply.handled);
7210 let CheckListSetPollRet::AllocateSocket {
7211 checklist_id,
7212 component_id,
7213 transport,
7214 local_addr,
7215 remote_addr,
7216 } = set.poll(now)
7217 else {
7218 unreachable!();
7219 };
7220 set.allocated_socket(
7221 checklist_id,
7222 component_id,
7223 transport,
7224 local_addr,
7225 remote_addr,
7226 Ok(tcp_local_addr),
7227 now,
7228 );
7229 let CheckListSetPollRet::WaitUntil(now) = set.poll(now) else {
7230 unreachable!();
7231 };
7232 let transmit = set.poll_transmit(now).unwrap();
7233 let msg = Message::from_bytes(&transmit.transmit.data).unwrap();
7234 assert!(msg.has_method(CONNECTION_BIND));
7235 let transmit = turn_server.recv(transmit.transmit, now).unwrap().build();
7236 let reply = set.incoming_data(checklist_id, 1, transmit, now);
7237 assert!(reply.handled);
7238 match set.poll(now) {
7239 CheckListSetPollRet::WaitUntil(now) => now,
7240 ret => {
7241 error!("{ret:?}");
7242 unreachable!()
7243 }
7244 }
7245 }
7246
7247 #[test]
7248 fn turn_tcp_create_permission() {
7249 let _log = crate::tests::test_init_log();
7250 let local_addr = "127.0.0.1:1".parse::<SocketAddr>().unwrap();
7251 let turn_addr = "127.0.0.1:3478".parse::<SocketAddr>().unwrap();
7252 let turn_alloc_addr = "127.0.0.1:3000".parse::<SocketAddr>().unwrap();
7253 let local_tcp_addr = "127.0.0.1:999".parse::<SocketAddr>().unwrap();
7254 let turn_credentials = TurnCredentials::new("tuser", "tpass");
7255 let mut builder = FineControl::builder()
7256 .local_candidate(
7257 Candidate::builder(
7258 1,
7259 CandidateType::Relayed,
7260 TransportType::Tcp,
7261 "0",
7262 turn_alloc_addr,
7263 )
7264 .priority(8000)
7265 .base_address(turn_alloc_addr)
7266 .related_address(local_addr)
7267 .tcp_type(TcpType::Active)
7268 .build(),
7269 )
7270 .trickle_ice(true);
7271 builder.remote_peer_builder = builder
7272 .remote_peer_builder
7273 .transport(TransportType::Tcp)
7274 .tcp_type(TcpType::Passive);
7275 let mut state = builder.build();
7276
7277 let mut local_auth = ShortTermAuth::new();
7278 let mut remote_auth = ShortTermAuth::new();
7279 state
7280 .remote
7281 .configure_stun_auth(&mut remote_auth, &mut local_auth);
7282
7283 let now = Instant::ZERO;
7284 let mut turn_server = TurnServer::new(TransportType::Tcp, turn_addr, "realm".to_owned());
7285 turn_server.add_user(
7286 turn_credentials.username().to_owned(),
7287 turn_credentials.password().to_owned(),
7288 );
7289 let mut config = turn_client_proto::api::TurnConfig::new(turn_credentials);
7290 config.set_allocation_transport(TransportType::Tcp);
7291 let mut turn_client =
7292 TurnClient::from(TurnClientTcp::allocate(local_addr, turn_addr, config));
7293 let now = turn_allocate(&mut turn_client, &mut turn_server, turn_alloc_addr, now);
7294
7295 let remote_candidate = state.remote.candidate.clone();
7296 state.local_list().add_remote_candidate(remote_candidate);
7297 let local_candidate = state.local.peer.candidate.clone();
7298 state
7299 .local_list()
7300 .add_local_gathered_candidate(GatheredCandidate {
7301 candidate: local_candidate,
7302 turn_agent: Some(Box::new(turn_client)),
7303 });
7304 assert_eq!(state.local.component_id, 1);
7305
7306 let now = match state.local.checklist_set.poll(now) {
7307 CheckListSetPollRet::WaitUntil(now) => now,
7308 ret => {
7309 error!("{ret:?}");
7310 unreachable!()
7311 }
7312 };
7313 let now = set_handle_permission(&mut state.local.checklist_set, &mut turn_server, now);
7314 error!("{state:?}");
7315
7316 let CheckListSetPollRet::Event {
7317 checklist_id: _,
7318 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
7319 } = state.local.checklist_set.poll(now)
7320 else {
7321 unreachable!();
7322 };
7323
7324 let now = set_handle_tcp_connect(
7325 &mut state.local.checklist_set,
7326 &mut turn_server,
7327 local_tcp_addr,
7328 now,
7329 );
7330
7331 let pair = CandidatePair::new(
7332 state.local.peer.candidate.clone(),
7333 state.remote.candidate.clone(),
7334 );
7335 let check = state
7336 .local_list()
7337 .matching_check(&pair, Nominate::False)
7338 .unwrap();
7339 assert_eq!(check.state(), CandidatePairState::InProgress);
7340 let check_id = check.conncheck_id;
7341
7342 let mut response =
7344 send_next_check_and_response(&state.local.peer, &state.remote).turn_server(turn_server);
7345 response.perform(&mut state.local.checklist_set, now);
7346 let turn_server = response.take_turn_server().unwrap();
7347 let check = state.local_list().check_by_id(check_id).unwrap();
7348 assert_eq!(check.state(), CandidatePairState::Succeeded);
7349
7350 let nominate_check = state
7353 .local_list()
7354 .matching_check(&pair, Nominate::True)
7355 .unwrap();
7356 let pair = nominate_check.pair.clone();
7357 let check_id = nominate_check.conncheck_id;
7358 assert!(state.local_list().is_triggered(&pair));
7359
7360 let now = wait_advance(&mut state.local.checklist_set, now);
7362 let mut response =
7363 send_next_check_and_response(&state.local.peer, &state.remote).turn_server(turn_server);
7364 response.perform(&mut state.local.checklist_set, now);
7365 let mut turn_server = response.take_turn_server().unwrap();
7366
7367 error!("nominated id {check_id:?}");
7368 let nominate_check = state.local_list().check_by_id(check_id).unwrap();
7369 assert_eq!(nominate_check.state(), CandidatePairState::Succeeded);
7370
7371 assert_eq!(state.local_list().state(), CheckListState::Completed);
7373
7374 let CheckListSetPollRet::Event {
7375 checklist_id: _,
7376 event: ConnCheckEvent::SelectedPair(_cid, _selected_pair),
7377 } = state.local.checklist_set.poll(now)
7378 else {
7379 unreachable!();
7380 };
7381 let CheckListSetPollRet::Event {
7382 checklist_id: _,
7383 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connected),
7384 } = state.local.checklist_set.poll(now)
7385 else {
7386 unreachable!();
7387 };
7388
7389 assert!(matches!(
7391 state.local.checklist_set.poll(now),
7392 CheckListSetPollRet::Completed
7393 ));
7394
7395 state.local.checklist_set.close(now);
7396
7397 let CheckListSetPollRet::WaitUntil(now) = state.local.checklist_set.poll(now) else {
7399 unreachable!();
7400 };
7401
7402 let Some(transmit) = state.local.checklist_set.poll_transmit(now) else {
7403 unreachable!();
7404 };
7405
7406 let checklist_id = transmit.checklist_id;
7407 let transmit = turn_server.recv(transmit.transmit, now).unwrap().build();
7408 let transmit = Transmit::new(
7409 Data::from(transmit.data.as_slice()),
7410 transmit.transport,
7411 transmit.from,
7412 transmit.to,
7413 );
7414 let reply = state
7415 .local
7416 .checklist_set
7417 .incoming_data(checklist_id, 1, transmit, now);
7418 assert!(reply.handled);
7419
7420 let CheckListSetPollRet::RemoveSocket {
7421 checklist_id: _,
7422 component_id: 1,
7423 transport,
7424 local_addr: remove_local_addr,
7425 remote_addr: _,
7426 } = state.local.checklist_set.poll(now)
7427 else {
7428 unreachable!();
7429 };
7430 assert_eq!(transport, turn_server.transport());
7431 assert_eq!(remove_local_addr, local_addr);
7432
7433 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
7434 unreachable!();
7435 };
7436 }
7437
7438 fn wait_advance(set: &mut ConnCheckListSet, now: Instant) -> Instant {
7439 let CheckListSetPollRet::WaitUntil(next) = set.poll(now) else {
7440 unreachable!();
7441 };
7442 assert!(next > now);
7443 next
7444 }
7445
7446 #[test]
7447 fn timing_advance() {
7448 let _log = crate::tests::test_init_log();
7449 for ta in [Duration::from_millis(10), Duration::from_secs(1)] {
7450 let mut state = FineControl::builder().build();
7451 state.local.checklist_set.set_timing_advance(ta);
7452 let mut now = Instant::ZERO;
7453 assert_eq!(state.local.component_id, 1);
7454
7455 let local2 = Peer::builder()
7456 .foundation("1")
7457 .component_id(1)
7458 .priority(state.local.peer.candidate.priority - 1)
7459 .local_addr("127.0.0.2:3".parse().unwrap())
7460 .build();
7461 state
7462 .local_list()
7463 .add_local_candidate(local2.candidate.clone());
7464
7465 let pair1 = CandidatePair::new(
7466 state.local.peer.candidate.clone(),
7467 state.remote.candidate.clone(),
7468 );
7469 let check = state
7470 .local_list()
7471 .matching_check(&pair1, Nominate::False)
7472 .unwrap();
7473 assert_eq!(check.state(), CandidatePairState::Frozen);
7474
7475 let pair2 =
7476 CandidatePair::new(local2.candidate.clone(), state.remote.candidate.clone());
7477 let check = state
7478 .local_list()
7479 .matching_check(&pair2, Nominate::False)
7480 .unwrap();
7481 assert_eq!(check.state(), CandidatePairState::Frozen);
7482
7483 let CheckListSetPollRet::Event {
7484 checklist_id: _,
7485 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
7486 } = state.local.checklist_set.poll(now)
7487 else {
7488 unreachable!();
7489 };
7490 let mut pending_checks = vec![];
7491 for pair in [&pair1, &pair2] {
7492 let check = state
7493 .local_list()
7494 .matching_check(pair, Nominate::False)
7495 .unwrap();
7496 assert!(
7497 [CandidatePairState::Waiting, CandidatePairState::InProgress]
7498 .contains(&check.state())
7499 );
7500 let check_id = check.conncheck_id;
7501
7502 let mut response = send_next_check_and_response2(pair.local.clone(), &state.remote);
7504 let transmit = response.send(&mut state.local.checklist_set, now);
7505
7506 let check = state.local_list().check_by_id(check_id).unwrap();
7507 assert_eq!(check.state(), CandidatePairState::InProgress);
7508 pending_checks.push((response, transmit));
7509 let new_now = wait_advance(&mut state.local.checklist_set, now);
7510 assert_eq!(new_now - now, ta);
7511 now = new_now;
7512 }
7513 for (mut response, transmit) in pending_checks {
7514 response.response(&mut state.local.checklist_set, transmit, now);
7515 }
7516
7517 state.check_nomination(&pair1, now);
7518
7519 state.local.checklist_set.close(now);
7520
7521 let CheckListSetPollRet::RemoveSocket {
7522 checklist_id: _,
7523 component_id: 1,
7524 transport: TransportType::Udp,
7525 local_addr,
7526 remote_addr: _,
7527 } = state.local.checklist_set.poll(now)
7528 else {
7529 unreachable!();
7530 };
7531 assert_eq!(local_addr, pair1.local.base_address);
7532 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
7533 unreachable!();
7534 };
7535 }
7536 }
7537
7538 #[test]
7539 fn conncheck_request_retransmit_timings() {
7540 let _log = crate::tests::test_init_log();
7541 let mut state = FineControl::builder().build();
7542 state
7543 .local
7544 .checklist_set
7545 .set_request_retransmits(RequestRto::from_parts(
7546 Duration::from_secs(1),
7547 Duration::from_secs(2),
7548 4,
7549 Duration::from_secs(4),
7550 ));
7551 state.local_list().end_of_local_candidates();
7552 state.local_list().end_of_remote_candidates();
7553
7554 let pair = CandidatePair::new(
7555 state.local.peer.candidate.clone(),
7556 state.remote.candidate.clone(),
7557 );
7558 let initial_check = state
7559 .local_list()
7560 .matching_check(&pair, Nominate::False)
7561 .unwrap();
7562 assert_eq!(initial_check.state(), CandidatePairState::Frozen);
7563 let check_id = initial_check.conncheck_id;
7564
7565 let mut now = Instant::ZERO;
7568
7569 let CheckListSetPollRet::Event {
7570 checklist_id: _,
7571 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
7572 } = state.local.checklist_set.poll(now)
7573 else {
7574 unreachable!();
7575 };
7576
7577 let set_ret = state.local.checklist_set.poll(now);
7579 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
7580 state.local.checklist_set.poll_transmit(now).unwrap();
7581 let new_now = wait_advance(&mut state.local.checklist_set, now);
7582 let new_now = wait_advance(&mut state.local.checklist_set, new_now);
7583 assert_eq!(new_now - now, Duration::from_secs(1));
7584 now = new_now;
7585
7586 let initial_check = state.local_list().check_by_id(check_id).unwrap();
7587 assert_eq!(initial_check.state(), CandidatePairState::InProgress);
7588
7589 let set_ret = state.local.checklist_set.poll(now);
7590 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
7591 state.local.checklist_set.poll_transmit(now).unwrap();
7592 let new_now = wait_advance(&mut state.local.checklist_set, now);
7593 let new_now = wait_advance(&mut state.local.checklist_set, new_now);
7594 assert_eq!(new_now - now, Duration::from_secs(2));
7595 now = new_now;
7596
7597 let set_ret = state.local.checklist_set.poll(now);
7598 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
7599 state.local.checklist_set.poll_transmit(now).unwrap();
7600 let new_now = wait_advance(&mut state.local.checklist_set, now);
7601 let new_now = wait_advance(&mut state.local.checklist_set, new_now);
7602 assert_eq!(new_now - now, Duration::from_secs(2));
7603 now = new_now;
7604
7605 let set_ret = state.local.checklist_set.poll(now);
7606 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
7607 state.local.checklist_set.poll_transmit(now).unwrap();
7608 let new_now = wait_advance(&mut state.local.checklist_set, now);
7609 let new_now = wait_advance(&mut state.local.checklist_set, new_now);
7610 assert_eq!(new_now - now, Duration::from_secs(4));
7611 now = new_now;
7612
7613 let CheckListSetPollRet::Completed = state.local.checklist_set.poll(now) else {
7614 unreachable!();
7615 };
7616
7617 let initial_check = state.local_list().check_by_id(check_id).unwrap();
7618 assert_eq!(initial_check.state(), CandidatePairState::Failed);
7619
7620 let CheckListSetPollRet::Event {
7621 checklist_id: _,
7622 event: ConnCheckEvent::ComponentState(1, ComponentConnectionState::Failed),
7623 } = state.local.checklist_set.poll(now)
7624 else {
7625 unreachable!();
7626 };
7627
7628 state.local.checklist_set.close(now);
7629
7630 let CheckListSetPollRet::RemoveSocket {
7631 checklist_id: _,
7632 component_id: 1,
7633 transport: TransportType::Udp,
7634 local_addr,
7635 remote_addr: _,
7636 } = state.local.checklist_set.poll(now)
7637 else {
7638 unreachable!();
7639 };
7640 assert_eq!(local_addr, pair.local.base_address);
7641 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
7642 unreachable!();
7643 };
7644 }
7645
7646 #[test]
7647 fn conncheck_trickle_ice_controlled_renomination() {
7648 let _log = crate::tests::test_init_log();
7649 let mut state = FineControl::builder()
7650 .trickle_ice(true)
7651 .controlling(false)
7652 .build();
7653 let now = Instant::ZERO;
7654 assert_eq!(state.local.component_id, 1);
7655
7656 let set_ret = state.local.checklist_set.poll(now);
7659 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
7661
7662 let local_candidate = state.local.peer.candidate.clone();
7663 let local_ipv6_addr = "[f8e0::1]:8".parse().unwrap();
7664 let mut local_candidate2 = state.local.peer.candidate.clone();
7665 local_candidate2.address = local_ipv6_addr;
7666 local_candidate2.base_address = local_ipv6_addr;
7667 local_candidate2.priority -= 1;
7668 local_candidate2.foundation = "ipv6".to_owned();
7669 state
7670 .local_list()
7671 .add_local_candidate(local_candidate.clone());
7672 state
7673 .local_list()
7674 .add_local_candidate(local_candidate2.clone());
7675
7676 let set_ret = state.local.checklist_set.poll(now);
7677 assert!(matches!(set_ret, CheckListSetPollRet::WaitUntil(_)));
7679
7680 let remote_candidate = state.remote.candidate.clone();
7681 let mut remote_candidate2 = state.remote.candidate.clone();
7682 let remote_ipv6_addr = "[f8e0::2]:9".parse().unwrap();
7683 remote_candidate2.address = remote_ipv6_addr;
7684 remote_candidate2.base_address = remote_ipv6_addr;
7685 remote_candidate2.priority -= 1;
7686 remote_candidate2.foundation = "ipv6".to_owned();
7687 state
7688 .local_list()
7689 .add_remote_candidate(remote_candidate.clone());
7690
7691 let ipv4_pair = CandidatePair::new(
7695 state.local.peer.candidate.clone(),
7696 state.remote.candidate.clone(),
7697 );
7698 let ipv6_pair = CandidatePair::new(local_candidate2.clone(), remote_candidate2.clone());
7699 let check = state
7700 .local_list()
7701 .matching_check(&ipv4_pair, Nominate::False)
7702 .unwrap();
7703 assert_eq!(check.state(), CandidatePairState::Waiting);
7704 let check_id = check.conncheck_id;
7705
7706 let CheckListSetPollRet::Event {
7707 checklist_id: _,
7708 event: ConnCheckEvent::ComponentState(_cid, ComponentConnectionState::Connecting),
7709 } = state.local.checklist_set.poll(now)
7710 else {
7711 unreachable!();
7712 };
7713
7714 send_next_check_and_response(&state.local.peer, &state.remote)
7716 .perform(&mut state.local.checklist_set, now);
7717 let check = state.local_list().check_by_id(check_id).unwrap();
7718 assert_eq!(check.state(), CandidatePairState::Succeeded);
7719
7720 state.local_list().dump_check_state();
7721
7722 let now = wait_advance(&mut state.local.checklist_set, now);
7723
7724 let mut local_auth = ShortTermAuth::new();
7725 local_auth.set_credentials(
7726 state.local.peer.local_credentials.clone().unwrap().into(),
7727 IntegrityAlgorithm::Sha1,
7728 );
7729 let mut remote_agent = StunAgent::builder(
7730 state.remote.candidate.transport_type,
7731 state.remote.candidate.base_address,
7732 )
7733 .build();
7734 let transmit = remote_generate_check(
7735 &state.remote,
7736 &mut remote_agent,
7737 state.local.peer.candidate.address,
7738 true,
7739 true,
7740 now,
7741 );
7742 let reply =
7743 state
7744 .local
7745 .checklist_set
7746 .incoming_data(state.local.checklist_id, 1, transmit, now);
7747 assert!(reply.handled);
7748 let Some(transmit) = state.local.checklist_set.poll_transmit(now) else {
7749 unreachable!();
7750 };
7751
7752 let response = Message::from_bytes(&transmit.transmit.data).unwrap();
7753 trace!("received: {response}");
7754 assert!(matches!(
7755 local_auth.validate_incoming_message(&response).unwrap(),
7756 Some(IntegrityAlgorithm::Sha1)
7757 ));
7758 assert!(remote_agent.handle_stun_message(&response, transmit.transmit.from));
7759 assert_eq!(transmit.transmit.from, state.local.peer.candidate.address);
7760 assert!(response.has_class(MessageClass::Success));
7761
7762 let now = wait_advance(&mut state.local.checklist_set, now);
7763 state.check_nomination(&ipv4_pair, now);
7764
7765 let recv = [8; 9];
7766 state.recv_data(recv, now);
7767
7768 state
7770 .local_list()
7771 .add_remote_candidate(remote_candidate2.clone());
7772 let mut remote_agent =
7773 StunAgent::builder(state.remote.candidate.transport_type, remote_ipv6_addr).build();
7774 let transmit = remote_generate_check(
7775 &state.remote,
7776 &mut remote_agent,
7777 local_ipv6_addr,
7778 true,
7779 true,
7780 now,
7781 );
7782 let reply =
7783 state
7784 .local
7785 .checklist_set
7786 .incoming_data(state.local.checklist_id, 1, transmit, now);
7787 assert!(reply.handled);
7788 let Some(transmit) = state.local.checklist_set.poll_transmit(now) else {
7789 unreachable!();
7790 };
7791
7792 let response = Message::from_bytes(&transmit.transmit.data).unwrap();
7793 trace!("received: {response}");
7794 assert!(matches!(
7795 local_auth.validate_incoming_message(&response).unwrap(),
7796 Some(IntegrityAlgorithm::Sha1)
7797 ));
7798 assert!(remote_agent.handle_stun_message(&response, transmit.transmit.from));
7799 assert_eq!(transmit.transmit.from, local_candidate2.address);
7800 assert!(response.has_class(MessageClass::Success));
7801
7802 let recv = [12; 5];
7803 state.recv_data_with_pair(&ipv6_pair, recv, now);
7804
7805 state.local.checklist_set.close(now);
7806
7807 let CheckListSetPollRet::RemoveSocket {
7808 checklist_id: _,
7809 component_id: 1,
7810 transport: TransportType::Udp,
7811 local_addr,
7812 remote_addr: _,
7813 } = state.local.checklist_set.poll(now)
7814 else {
7815 unreachable!();
7816 };
7817 assert_eq!(local_addr, ipv4_pair.local.base_address);
7818 let CheckListSetPollRet::RemoveSocket {
7819 checklist_id: _,
7820 component_id: 1,
7821 transport: TransportType::Udp,
7822 local_addr,
7823 remote_addr: _,
7824 } = state.local.checklist_set.poll(now)
7825 else {
7826 unreachable!();
7827 };
7828 assert_eq!(local_addr, ipv6_pair.local.base_address);
7829 let CheckListSetPollRet::Closed = state.local.checklist_set.poll(now) else {
7830 unreachable!();
7831 };
7832 }
7833}