1pub mod conn;
2#[cfg(feature = "std")] pub mod mdns;
4#[cfg(feature = "std")] pub mod shared_tcp;
6
7#[cfg(not(feature = "std"))]
9#[derive(Debug, Clone)]
10pub struct SharedTcpRegistration;
11pub mod shared_udp;
12pub mod stun;
13#[cfg(all(test, feature = "std"))]
14mod tests;
15pub mod turn;
16#[cfg(feature = "std")] pub mod upnp;
18
19#[cfg(feature = "std")]
21pub use upnp::{
22 DEFAULT_LEASE_DURATION, DEFAULT_UPNP_DISCOVERY_TIMEOUT, MAX_LEASE_DURATION, MIN_LEASE_DURATION,
23 UpnpPortMapper,
24};
25
26use crate::config::{BufferDropStrategy, IceServer, IceTransportPolicy, RtcConfiguration};
27use crate::platform::atomic64::AtomicU64;
28use crate::prelude::*;
29use crate::transports::ice::turn::{TurnClient, TurnCredentials};
30use crate::transports::{PacketReceiver, get_local_ip};
31use alloc::collections::{BTreeMap, VecDeque};
32use alloc::sync::Arc;
33use bytes::Bytes;
34use core::net::{IpAddr, SocketAddr};
35use core::sync::atomic::AtomicU32;
36use core::sync::atomic::Ordering;
37use futures::future::BoxFuture;
38use futures::stream::{FuturesUnordered, StreamExt};
39#[cfg(feature = "std")]
40use std::io::ErrorKind;
41
42#[cfg(not(feature = "std"))]
43use crate::platform::time::Instant;
44use core::time::Duration;
45#[cfg(feature = "std")]
46use std::time::Instant;
47
48use crate::errors::{RtcError, RtcResult};
49#[cfg(feature = "std")]
50use crate::platform::net::UdpSocket as NetUdpSocket;
51#[cfg(feature = "std")]
52use tokio::net::UdpSocket;
53#[cfg(feature = "std")]
54use tokio::net::{TcpListener, TcpStream};
55#[cfg(not(feature = "std"))]
56#[derive(Debug, Clone)]
60pub struct UdpSocket;
61
62#[cfg(not(feature = "std"))]
63impl UdpSocket {
64 pub async fn bind(_addr: SocketAddr) -> RtcResult<Self> {
65 unimplemented!("direct UDP sockets are std-only; use Platform sockets (WP3)")
66 }
67 pub fn local_addr(&self) -> RtcResult<SocketAddr> {
68 unimplemented!("direct UDP sockets are std-only")
69 }
70 pub async fn send_to(&self, _: &[u8], _: SocketAddr) -> RtcResult<usize> {
71 unimplemented!("direct UDP sockets are std-only")
72 }
73 pub async fn recv_from(&self, _: &mut [u8]) -> RtcResult<(usize, SocketAddr)> {
74 unimplemented!("direct UDP sockets are std-only")
75 }
76 pub fn try_send_to(&self, _: &[u8], _: SocketAddr) -> RtcResult<usize> {
77 unimplemented!("direct UDP sockets are std-only")
78 }
79 pub async fn writable(&self) -> RtcResult<()> {
80 unimplemented!("direct UDP sockets are std-only")
81 }
82 pub fn diag(&self) -> SocketAddr {
83 unimplemented!("direct UDP sockets are std-only")
84 }
85}
86
87#[cfg(not(feature = "std"))]
90#[derive(Debug, Clone)]
91pub struct TcpStream;
92
93#[cfg(not(feature = "std"))]
94impl TcpStream {
95 pub async fn connect(_addr: SocketAddr) -> RtcResult<Self> {
96 unimplemented!("ICE-TCP is excluded from the embedded target")
97 }
98 pub fn local_addr(&self) -> RtcResult<SocketAddr> {
99 unimplemented!("ICE-TCP is excluded from the embedded target")
100 }
101 pub fn set_nodelay(&self, _: bool) -> RtcResult<()> {
102 Ok(())
103 }
104 pub async fn write_all(&self, _: &[u8]) -> RtcResult<()> {
105 unimplemented!("ICE-TCP is excluded from the embedded target")
106 }
107 pub async fn read_exact(&self, _: &mut [u8]) -> RtcResult<()> {
108 unimplemented!("ICE-TCP is excluded from the embedded target")
109 }
110 pub fn into_split(self) -> (TcpReadHalf, TcpWriteHalf) {
111 unimplemented!("ICE-TCP is excluded from the embedded target")
112 }
113}
114
115#[cfg(not(feature = "std"))]
117#[derive(Debug, Clone)]
118pub struct TcpListener;
119
120#[cfg(not(feature = "std"))]
121impl TcpListener {
122 pub async fn bind(_addr: SocketAddr) -> RtcResult<Self> {
123 unimplemented!("ICE-TCP is excluded from the embedded target")
124 }
125 pub fn local_addr(&self) -> RtcResult<SocketAddr> {
126 unimplemented!("ICE-TCP is excluded from the embedded target")
127 }
128}
129
130#[cfg(not(feature = "std"))]
132pub type TcpReadHalf = TcpStream;
133#[cfg(not(feature = "std"))]
134pub type TcpWriteHalf = TcpStream;
135
136#[cfg(not(feature = "std"))]
139#[derive(Debug, Clone)]
140pub struct UpnpPortMapper;
141
142#[cfg(not(feature = "std"))]
143impl UpnpPortMapper {
144 pub fn with_lease_duration(_local_addr: SocketAddr, _lease: u32) -> Self {
145 unimplemented!("UPnP is excluded from the embedded target")
146 }
147 pub async fn discover(&mut self) -> RtcResult<()> {
148 unimplemented!("UPnP is excluded from the embedded target")
149 }
150 pub async fn add_mapping(&mut self, _port: u16) -> RtcResult<SocketAddr> {
151 unimplemented!("UPnP is excluded from the embedded target")
152 }
153 pub async fn renew_all_stale(&self) -> RtcResult<()> {
154 unimplemented!("UPnP is excluded from the embedded target")
155 }
156 pub async fn discover_with_timeout(&mut self, _: core::time::Duration) -> RtcResult<()> {
157 unimplemented!("UPnP is excluded from the embedded target")
158 }
159 pub async fn add_mapping_random_port(&mut self, _: u16) -> RtcResult<u16> {
160 unimplemented!("UPnP is excluded from the embedded target")
161 }
162 pub async fn cleanup(&self) -> RtcResult<()> {
163 Ok(())
164 }
165 pub async fn get_external_ip(&self) -> RtcResult<core::net::Ipv4Addr> {
166 unimplemented!("UPnP is excluded from the embedded target")
167 }
168}
169use crate::platform::sync::{AsyncMutex as Mutex, broadcast, mpsc, oneshot, watch};
170use crate::platform::time::with_timeout;
171use tracing::{debug, error, instrument, trace, warn};
172
173#[cfg(any(test, feature = "simulator"))]
174use self::stun::random_u32;
175use self::stun::{
176 StunAttribute, StunClass, StunDecoded, StunMessage, StunMethod, random_bytes, random_u64,
177};
178
179pub(crate) const MAX_STUN_MESSAGE: usize = 1500;
180#[cfg(any(test, feature = "simulator"))]
181static PACKET_LOSS_RATE: AtomicU32 = AtomicU32::new(u32::MAX);
182
183pub(crate) fn should_drop_packet() -> bool {
184 #[cfg(not(any(test, feature = "simulator")))]
185 return false;
186
187 #[cfg(any(test, feature = "simulator"))]
188 {
189 let mut rate = PACKET_LOSS_RATE.load(Ordering::Relaxed);
190 if rate == u32::MAX {
191 #[cfg(feature = "std")]
192 {
193 rate = std::env::var("RUSTRTC_PACKET_LOSS")
194 .ok()
195 .and_then(|s| s.parse::<f64>().ok())
196 .map(|f| (f * 100.0) as u32)
197 .unwrap_or(0);
198 }
199 #[cfg(not(feature = "std"))]
200 {
201 rate = 0;
202 }
203 PACKET_LOSS_RATE.store(rate, Ordering::Relaxed);
204 }
205
206 if rate == 0 {
207 return false;
208 }
209
210 let rand_val = random_u32() % 10000;
211 let drop = rand_val < rate;
212 if drop {
213 trace!("SIMULATOR: Dropping packet (rate={}%)", rate as f64 / 100.0);
214 }
215 drop
216 }
217}
218
219#[cfg(any(test, feature = "simulator"))]
227async fn simulate_stun_respond_delay(sender: &IceSocketWrapper) {
228 #[cfg(not(feature = "std"))]
229 {
230 let _ = sender;
232 }
233 #[cfg(feature = "std")]
234 {
235 let spec = match std::env::var("RUSTRTC_STUN_RESPOND_DELAY_MS").ok() {
236 Some(s) => s,
237 None => return,
238 };
239 let Ok(ms) = spec.trim().parse::<u64>() else {
240 return;
241 };
242 if ms == 0 {
243 return;
244 }
245 let is_relayed_or_tcp = matches!(sender, IceSocketWrapper::Turn(_, _)) || matches!(
246 sender,
247 IceSocketWrapper::TcpListener(_) | IceSocketWrapper::TcpStream(_, _, _)
248 );
249 if is_relayed_or_tcp {
250 return;
251 }
252 trace!("SIMULATOR: delaying STUN response by {}ms", ms);
253 crate::platform::task::sleep(Duration::from_millis(ms)).await;
254 }
255}
256
257#[derive(Debug)]
259struct BufferStats {
260 pub packets_received: AtomicU64,
261 pub packets_dropped: AtomicU64,
262 pub current_size: AtomicU32,
263 pub peak_size: AtomicU32,
264 pub last_log_time: crate::platform::sync::Mutex<Instant>,
265}
266
267impl Default for BufferStats {
268 fn default() -> Self {
269 Self {
270 packets_received: AtomicU64::new(0),
271 packets_dropped: AtomicU64::new(0),
272 current_size: AtomicU32::new(0),
273 peak_size: AtomicU32::new(0),
274 last_log_time: crate::platform::sync::Mutex::new(Instant::now()),
275 }
276 }
277}
278
279#[derive(Debug)]
280enum IceCommand {
281 StartGathering,
282 RunChecks,
283}
284
285#[derive(Debug, Clone)]
286pub struct IceTransport {
287 inner: Arc<IceTransportInner>,
288}
289
290pub(crate) struct IceTransportInner {
291 state: watch::Sender<IceTransportState>,
292 _state_rx_keeper: watch::Receiver<IceTransportState>,
293 gathering_state: watch::Sender<IceGathererState>,
294 _gathering_state_rx_keeper: watch::Receiver<IceGathererState>,
301 role: crate::platform::sync::Mutex<IceRole>,
302 selected_pair: crate::platform::sync::Mutex<Option<IceCandidatePair>>,
303 local_candidates: Mutex<Vec<IceCandidate>>,
304 remote_candidates: crate::platform::sync::Mutex<Vec<IceCandidate>>,
305 gather_state: crate::platform::sync::Mutex<IceGathererState>,
306 config: RtcConfiguration,
307 gatherer: IceGatherer,
308 local_parameters: crate::platform::sync::Mutex<IceParameters>,
309 remote_parameters: crate::platform::sync::Mutex<Option<IceParameters>>,
310 pending_transactions:
311 crate::platform::sync::Mutex<BTreeMap<[u8; 12], oneshot::Sender<StunDecoded>>>,
312 data_receiver: crate::platform::sync::Mutex<Option<Arc<dyn PacketReceiver>>>,
313 buffered_packets: crate::platform::sync::Mutex<VecDeque<(Vec<u8>, SocketAddr)>>,
316 buffer_stats: Arc<BufferStats>,
318 selected_socket: watch::Sender<Option<IceSocketWrapper>>,
319 _socket_rx_keeper: watch::Receiver<Option<IceSocketWrapper>>,
320 selected_rtcp_socket: watch::Sender<Option<IceSocketWrapper>>,
321 _rtcp_socket_rx_keeper: watch::Receiver<Option<IceSocketWrapper>>,
322 selected_pair_notifier: watch::Sender<Option<IceCandidatePair>>,
323 _selected_pair_rx_keeper: watch::Receiver<Option<IceCandidatePair>>,
324 created_at: Instant,
326 last_received_nanos: AtomicU64,
330 candidate_tx: broadcast::Sender<IceCandidate>,
331 cmd_tx: mpsc::UnboundedSender<IceCommand>,
332 checking_pairs: Mutex<alloc::collections::BTreeSet<(SocketAddr, SocketAddr)>>,
333 nomination_complete: watch::Sender<Option<bool>>,
337 _nomination_complete_rx: watch::Receiver<Option<bool>>,
338 restart_requested: core::sync::atomic::AtomicBool,
343 nomination_generation: crate::platform::atomic64::AtomicU64,
350 mdns_hostname: Option<String>,
352 turn_refresh_in_progress: core::sync::atomic::AtomicBool,
356 upnp_refresh_in_progress: core::sync::atomic::AtomicBool,
359}
360
361impl core::fmt::Debug for IceTransportInner {
362 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
363 f.debug_struct("IceTransportInner")
364 .field("state", &self.state)
365 .field("role", &self.role)
366 .field("selected_pair", &self.selected_pair)
367 .field("local_candidates", &self.local_candidates)
368 .field("remote_candidates", &self.remote_candidates)
369 .field("gather_state", &self.gather_state)
370 .field("config", &self.config)
371 .field("gatherer", &self.gatherer)
372 .field("local_parameters", &self.local_parameters)
373 .field("remote_parameters", &self.remote_parameters)
374 .field("pending_transactions", &self.pending_transactions)
375 .field("data_receiver", &"PacketReceiver")
376 .field("buffered_packets", &self.buffered_packets.lock().len())
377 .field("buffer_stats", &self.buffer_stats)
378 .field("selected_socket", &self.selected_socket)
379 .field("selected_rtcp_socket", &self.selected_rtcp_socket)
380 .field("selected_pair_notifier", &self.selected_pair_notifier)
381 .field("candidate_tx", &self.candidate_tx)
382 .field("cmd_tx", &self.cmd_tx)
383 .field("nomination_complete", &self.nomination_complete)
384 .finish()
385 }
386}
387
388#[cfg(feature = "std")]
391fn start_mdns_responder(
392 inner: &Arc<IceTransportInner>,
393) -> anyhow::Result<crate::transports::ice::mdns::MdnsResponder> {
394 let mut addresses: Vec<core::net::IpAddr> = Vec::new();
395 if let Some(bind) = &inner.config.bind_ip
396 && let Ok(ip) = bind.parse::<core::net::IpAddr>()
397 {
398 addresses.push(ip);
399 }
400 #[cfg(feature = "std")]
401 use local_ip_address::list_afinet_netifas;
402 if let Ok(interfaces) = list_afinet_netifas() {
403 for (_name, addr) in interfaces {
404 if !addr.is_loopback() && !addresses.contains(&addr) {
405 addresses.push(addr);
406 }
407 }
408 }
409 let hostname = inner
410 .mdns_hostname
411 .clone()
412 .unwrap_or_else(crate::transports::ice::mdns::MdnsResponder::generate_hostname);
413 crate::transports::ice::mdns::MdnsResponder::start(hostname, addresses)
414}
415
416struct IceTransportRunner {
417 inner: Arc<IceTransportInner>,
418 socket_rx: mpsc::UnboundedReceiver<IceSocketWrapper>,
419 candidate_rx: broadcast::Receiver<IceCandidate>,
420 cmd_rx: mpsc::UnboundedReceiver<IceCommand>,
421 state_rx: watch::Receiver<IceTransportState>,
422}
423
424impl IceTransportRunner {
425 async fn run(mut self) {
426
427 #[cfg(feature = "std")]
430 let _mdns: Option<crate::transports::ice::mdns::MdnsResponder> =
431 if self.inner.config.enable_mdns {
432 match start_mdns_responder(&self.inner) {
433 Ok(responder) => {
434 debug!("mDNS responder started for {}", responder.hostname());
435 Some(responder)
436 }
437 Err(e) => {
438 debug!("mDNS responder failed to start: {}", e);
439 None
440 }
441 }
442 } else {
443 None
444 };
445 let mut interval =
446 crate::platform::task::interval_after(Duration::from_secs(1), Duration::from_secs(1));
447 let mut turn_refresh_interval =
455 crate::platform::task::interval_after(Duration::from_secs(25), Duration::from_secs(25));
456 let mut upnp_refresh_interval = crate::platform::task::interval_after(
460 self.inner.config.upnp_refresh_interval,
461 self.inner.config.upnp_refresh_interval,
462 );
463 let mut read_futures: FuturesUnordered<BoxFuture<'static, ()>> = FuturesUnordered::new();
464 let mut gathering_future: BoxFuture<'static, ()> = Box::pin(futures::future::pending());
465 let mut turn_refresh_future: BoxFuture<'static, ()> = Box::pin(futures::future::pending());
466 let mut upnp_refresh_future: BoxFuture<'static, ()> = Box::pin(futures::future::pending());
467
468 loop {
469 enum GatherArm {
475 State(Result<(), watch::RecvError>),
476 Socket(IceSocketWrapper),
477 Candidate(Result<(), broadcast::RecvError>),
478 Cmd(IceCommand),
479 Keepalive,
480 TurnRefreshTick,
481 TurnRefreshDone,
482 UpnpTick,
483 UpnpDone,
484 ReadLoopDone,
485 GatheringDone,
486 }
487 let mut socket_rx_open = true;
488 let mut cmd_rx_open = true;
489
490 let arm = core::future::poll_fn(|cx| {
491 use core::task::Poll;
492 let mut state_fut = core::pin::pin!(self.state_rx.changed());
493 let mut socket_fut = core::pin::pin!(self.socket_rx.recv());
494 let mut cand_fut = core::pin::pin!(self.candidate_rx.recv());
495 let mut cmd_fut = core::pin::pin!(self.cmd_rx.recv());
496 let mut ka_fut = core::pin::pin!(interval.tick());
497 let mut turn_tick_fut = core::pin::pin!(turn_refresh_interval.tick());
498 let mut upnp_tick_fut = core::pin::pin!(upnp_refresh_interval.tick());
499 let mut read_next_fut = core::pin::pin!(read_futures.next());
500 loop {
501 if let Poll::Ready(res) = state_fut.as_mut().poll(cx) {
502 return Poll::Ready(GatherArm::State(res));
503 }
504 if socket_rx_open && let Poll::Ready(v) = socket_fut.as_mut().poll(cx) {
505 match v {
506 Some(socket) => return Poll::Ready(GatherArm::Socket(socket)),
507 None => socket_rx_open = false,
508 }
509 }
510 if let Poll::Ready(res) = cand_fut.as_mut().poll(cx) {
511 return Poll::Ready(GatherArm::Candidate(res.map(|_| ())));
512 }
513 if cmd_rx_open && let Poll::Ready(v) = cmd_fut.as_mut().poll(cx) {
514 match v {
515 Some(cmd) => return Poll::Ready(GatherArm::Cmd(cmd)),
516 None => cmd_rx_open = false,
517 }
518 }
519 if ka_fut.as_mut().poll(cx).is_ready() {
520 return Poll::Ready(GatherArm::Keepalive);
521 }
522 if turn_tick_fut.as_mut().poll(cx).is_ready() {
523 return Poll::Ready(GatherArm::TurnRefreshTick);
524 }
525 if core::pin::Pin::new(&mut turn_refresh_future)
526 .poll(cx)
527 .is_ready()
528 {
529 return Poll::Ready(GatherArm::TurnRefreshDone);
530 }
531 if upnp_tick_fut.as_mut().poll(cx).is_ready() {
532 return Poll::Ready(GatherArm::UpnpTick);
533 }
534 if core::pin::Pin::new(&mut upnp_refresh_future)
535 .poll(cx)
536 .is_ready()
537 {
538 return Poll::Ready(GatherArm::UpnpDone);
539 }
540 if let Poll::Ready(Some(_)) = read_next_fut.as_mut().poll(cx) {
541 return Poll::Ready(GatherArm::ReadLoopDone);
542 }
543 if core::pin::Pin::new(&mut gathering_future)
544 .poll(cx)
545 .is_ready()
546 {
547 return Poll::Ready(GatherArm::GatheringDone);
548 }
549 return Poll::Pending;
550 }
551 })
552 .await;
553 match arm {
554 GatherArm::State(res) => {
555 if res.is_err() {
556 break;
557 }
558 if matches!(
559 *self.state_rx.borrow(),
560 IceTransportState::Closed | IceTransportState::Failed
561 ) {
562 break;
563 }
564 }
565 GatherArm::Socket(socket) => {
566 match socket {
567 IceSocketWrapper::Udp(s) => {
568 #[cfg(feature = "std")]
571 {
572 read_futures
573 .push(Box::pin(Self::run_udp_read_loop(s, self.inner.clone())));
574 }
575 #[cfg(not(feature = "std"))]
576 {
577 let _ = s;
578 }
579 }
580 IceSocketWrapper::SharedUdp(handle) => {
581 read_futures.push(Box::pin(Self::run_shared_udp_read_loop(
582 handle,
583 self.inner.clone(),
584 )));
585 }
586 #[cfg(feature = "std")]
587 IceSocketWrapper::TcpListener(l) => {
588 read_futures
589 .push(Box::pin(Self::run_tcp_listen_loop(l, self.inner.clone())));
590 }
591 #[cfg(feature = "std")]
592 IceSocketWrapper::TcpStream(read, write, peer) => {
593 read_futures.push(Box::pin(Self::run_tcp_read_loop(
594 read,
595 write,
596 peer,
597 self.inner.clone(),
598 )));
599 }
600 IceSocketWrapper::Platform(s) => {
601 read_futures.push(Box::pin(Self::run_platform_read_loop(
602 s,
603 self.inner.clone(),
604 )));
605 }
606 IceSocketWrapper::Turn(c, addr) => {
607 read_futures.push(Box::pin(Self::run_turn_read_loop(
608 c,
609 addr,
610 self.inner.clone(),
611 )));
612 }
613 }
614 }
615 GatherArm::Candidate(res) => match res { Ok(_) => {
616 let inner = self.inner.clone();
617 read_futures.push(Box::pin(async move {
618 perform_connectivity_checks_async(inner).await;
619 }));
620 }
621 Err(broadcast::RecvError::Closed) => break,
622 Err(broadcast::RecvError::Lagged(_)) => continue,
623 }
624 GatherArm::Cmd(cmd) => {
625
626
627 trace!("Runner received command: {:?}", cmd);
628 match cmd {
629 IceCommand::StartGathering => {
630 let inner = self.inner.clone();
631 gathering_future = Box::pin(async move {
632 if let Err(e) = inner.gatherer.gather().await {
633 debug!("Gathering failed: {}", e);
634 }
635 {
636 let mut buffer = inner.local_candidates.lock().await;
637 *buffer = inner.gatherer.local_candidates();
638 }
639 *inner.gather_state.lock() = IceGathererState::Complete;
640 let _ = inner.gathering_state.send(IceGathererState::Complete);
641 });
642 }
643 IceCommand::RunChecks => {
644 let inner = self.inner.clone();
645 let rt_handle = inner.config.runtime_handle.clone();
651 crate::spawn_rtc(
652 rt_handle.as_ref(),
653 tracing::Span::current(),
654 async move {
655 perform_connectivity_checks_async(inner).await;
656 },
657 );
658 }
659 }
660 }
661 GatherArm::Keepalive => {
662 if let Some(f) = Self::run_keepalive_tick(&self.inner).await {
663 read_futures.push(f);
664 }
665 }
666 GatherArm::TurnRefreshTick => {
667 if !self
674 .inner
675 .turn_refresh_in_progress
676 .load(core::sync::atomic::Ordering::SeqCst)
677 {
678 let inner = self.inner.clone();
679 turn_refresh_future = Box::pin(async move {
680 Self::run_turn_refresh(&inner).await;
681 });
682 }
683 }
684 GatherArm::TurnRefreshDone => {
685 turn_refresh_future = Box::pin(futures::future::pending());
686 }
687 GatherArm::UpnpTick => {
688 if !self
693 .inner
694 .upnp_refresh_in_progress
695 .swap(true, core::sync::atomic::Ordering::SeqCst)
696 {
697 let inner = self.inner.clone();
698 upnp_refresh_future = Box::pin(async move {
699 #[cfg(feature = "std")]
700 inner.gatherer.renew_upnp_mappings().await;
701 #[cfg(not(feature = "std"))]
702 {
703 let _ = &inner;
704 }
705 inner
706 .upnp_refresh_in_progress
707 .store(false, core::sync::atomic::Ordering::SeqCst);
708 });
709 }
710 }
711 GatherArm::UpnpDone => {
712 upnp_refresh_future = Box::pin(futures::future::pending());
713 }
714 GatherArm::ReadLoopDone => {
715 }
717 GatherArm::GatheringDone => {
718 gathering_future = Box::pin(futures::future::pending());
719 }
720 }
721 }
722 }
723
724 #[cfg(feature = "std")]
725 async fn run_udp_read_loop(socket: Arc<UdpSocket>, inner: Arc<IceTransportInner>) {
726 let mut buf = [0u8; 1500];
727 let mut marshal_buf = Vec::with_capacity(1500);
728 let mut state_rx = inner.state.subscribe();
729 let sender = IceSocketWrapper::Udp(socket.clone());
730 trace!("Read loop started for {:?}", socket.local_addr());
731 loop {
732 let which = {
733 let mut readable_fut = core::pin::pin!(socket.readable());
734 let mut state_fut = core::pin::pin!(state_rx.changed());
735 crate::platform::select::select2(&mut readable_fut, &mut state_fut).await
736 };
737 match which {
738 crate::platform::select::Either::A(res) => {
739 if let Err(e) = res {
740 debug!("Socket readable wait error: {}", e);
741 break;
742 }
743
744 loop {
745 let (len, addr) = match socket.try_recv_from(&mut buf) {
746 Ok(v) => v,
747 Err(e) if e.kind() == ErrorKind::WouldBlock => {
748 break;
749 }
750 Err(e) if e.kind() == ErrorKind::ConnectionReset => {
751 debug!("Socket recv error (connection reset, continuing): {}", e);
759 break;
760 }
761 Err(e) => {
762 debug!("Socket recv error: {}", e);
763 return;
764 }
765 };
766
767 let packet = &buf[..len];
768 if len > 0 {
769 handle_packet(
770 packet,
771 addr,
772 inner.clone(),
773 sender.clone(),
774 &mut marshal_buf,
775 )
776 .await;
777 }
778 }
779 }
780 crate::platform::select::Either::B(res) => {
781 if res.is_err()
782 || matches!(
783 *state_rx.borrow(),
784 IceTransportState::Closed | IceTransportState::Failed
785 )
786 {
787 trace!("Read loop stopping (IceTransport Closed or Failed)");
789 break;
790 }
791 }
792 }
793 }
794 }
795
796 async fn run_platform_read_loop(
797 socket: Arc<dyn crate::platform::net::UdpSocket>,
798 inner: Arc<IceTransportInner>,
799 ) {
800 let mut buf = vec![0u8; 1500];
801 let mut marshal_buf = Vec::with_capacity(1500);
802 let sender = IceSocketWrapper::Platform(socket.clone());
803 loop {
804 let result = crate::platform::time::with_timeout(
805 core::time::Duration::from_secs(1),
806 socket.recv_from(&mut buf),
807 )
808 .await;
809 let (len, addr) = match result {
810 Err(_) => continue,
811 Ok(Err(_)) => break,
812 Ok(Ok(v)) => v,
813 };
814 let packet = &buf[..len];
815 if len > 0 {
816 handle_packet(
817 packet,
818 addr,
819 inner.clone(),
820 sender.clone(),
821 &mut marshal_buf,
822 )
823 .await;
824 }
825 }
826 }
827
828 async fn run_shared_udp_read_loop(
832 handle: Arc<shared_udp::SharedUdpHandle>,
833 inner: Arc<IceTransportInner>,
834 ) {
835 let mut state_rx = inner.state.subscribe();
836 let mut marshal_buf = Vec::with_capacity(1500);
837 let sender = IceSocketWrapper::SharedUdp(handle.clone());
838 trace!("Shared UDP read loop started");
839 loop {
840 let which = {
844 let mut state_fut = core::pin::pin!(state_rx.changed());
845 let mut recv_fut = core::pin::pin!(handle.recv());
846 crate::platform::select::select2(&mut state_fut, &mut recv_fut).await
847 };
848 let packet_opt = match which {
849 crate::platform::select::Either::A(res) => {
850 if res.is_err()
851 || matches!(
852 *state_rx.borrow(),
853 IceTransportState::Closed | IceTransportState::Failed
854 )
855 {
856 debug!("Shared UDP read loop stopping (IceTransport Closed or Failed)");
857 break;
858 }
859 continue;
860 }
861 crate::platform::select::Either::B(pkt) => pkt,
862 };
863 match packet_opt {
864 Some((packet, addr)) => {
865 handle_packet(
866 &packet,
867 addr,
868 inner.clone(),
869 sender.clone(),
870 &mut marshal_buf,
871 )
872 .await;
873 }
874 None => break,
875 }
876 }
877 }
878
879 async fn run_turn_read_loop(
880 client: Arc<TurnClient>,
881 relayed_addr: SocketAddr,
882 inner: Arc<IceTransportInner>,
883 ) {
884 let mut buf = [0u8; 1500];
885 let mut marshal_buf = Vec::with_capacity(1500);
886 let mut state_rx = inner.state.subscribe();
887 trace!("Read loop started for TURN client {}", relayed_addr);
888 loop {
889 let which = {
890 let mut recv_fut = core::pin::pin!(async { client.recv(&mut buf).await });
891 let mut state_fut = core::pin::pin!(state_rx.changed());
892 crate::platform::select::select2(&mut recv_fut, &mut state_fut).await
893 };
894 match which {
895 crate::platform::select::Either::A(result) => match result {
896 Ok(len) => {
897 if len > 0 {
898 IceTransport::handle_turn_packet(
899 &buf[..len],
900 &inner,
901 &client,
902 relayed_addr,
903 &mut marshal_buf,
904 )
905 .await;
906 }
907 }
908 Err(e) => {
909 if e.to_string().contains("deadline has elapsed") {
910 continue;
911 }
912 debug!("TURN client recv error: {}", e);
913 break;
914 }
915 },
916 crate::platform::select::Either::B(res) => {
917 if res.is_err()
918 || matches!(
919 *state_rx.borrow(),
920 IceTransportState::Closed | IceTransportState::Failed
921 )
922 {
923 trace!("TURN Read loop stopping (IceTransport Closed or Failed)");
924 break;
925 }
926 }
927 }
928 }
929 }
930
931 #[cfg(feature = "std")]
932 async fn run_tcp_listen_loop(listener: Arc<TcpListener>, inner: Arc<IceTransportInner>) {
933 let mut state_rx = inner.state.subscribe();
934 let local_addr = match listener.local_addr() {
935 Ok(a) => a,
936 Err(e) => {
937 debug!("TCP listener local_addr error: {}", e);
938 return;
939 }
940 };
941 trace!("TCP listen loop started for {:?}", local_addr);
942 loop {
943 let which = {
944 let mut accept_fut = core::pin::pin!(listener.accept());
945 let mut state_fut = core::pin::pin!(state_rx.changed());
946 crate::platform::select::select2(&mut accept_fut, &mut state_fut).await
947 };
948 match which {
949 crate::platform::select::Either::A(accept_res) => match accept_res {
950 Ok((stream, peer_addr)) => {
951 trace!("TCP accepted connection from {}", peer_addr);
952 let wrapper = split_tcp_stream(stream, peer_addr);
953 inner.gatherer.store_tcp_stream(local_addr, wrapper.clone());
954 let _ = inner.gatherer.socket_tx.send(wrapper);
955 }
956 Err(e) => {
957 debug!("TCP accept error: {}", e);
958 break;
959 }
960 },
961 crate::platform::select::Either::B(res) => {
962 if res.is_err()
963 || matches!(
964 *state_rx.borrow(),
965 IceTransportState::Closed | IceTransportState::Failed
966 )
967 {
968 debug!("TCP listen loop stopping (IceTransport Closed or Failed)");
969 break;
970 }
971 }
972 }
973 }
974 }
975
976 #[cfg(feature = "std")]
977 async fn run_tcp_read_loop(
978 read: Arc<Mutex<TcpReadHalf>>,
979 write: Arc<Mutex<TcpWriteHalf>>,
980 peer_addr: SocketAddr,
981 inner: Arc<IceTransportInner>,
982 ) {
983 let mut buf = [0u8; 65_535];
984 let mut marshal_buf = Vec::with_capacity(1500);
985 let mut state_rx = inner.state.subscribe();
986 #[cfg(feature = "std")]
987 let sender = IceSocketWrapper::TcpStream(read, write, peer_addr);
988 trace!("TCP read loop started for peer {}", peer_addr);
989 loop {
990 let which = {
991 let mut recv_fut = core::pin::pin!(sender.recv_from(&mut buf));
992 let mut state_fut = core::pin::pin!(state_rx.changed());
993 crate::platform::select::select2(&mut recv_fut, &mut state_fut).await
994 };
995 match which {
996 crate::platform::select::Either::A(result) => match result {
997 Ok((len, addr)) => {
998 if len > 0 {
999 handle_packet(
1000 &buf[..len],
1001 addr,
1002 inner.clone(),
1003 sender.clone(),
1004 &mut marshal_buf,
1005 )
1006 .await;
1007 }
1008 }
1009 Err(e) => {
1010 debug!("TCP recv error from {}: {}", peer_addr, e);
1011 break;
1012 }
1013 },
1014 crate::platform::select::Either::B(res) => {
1015 if res.is_err()
1016 || matches!(
1017 *state_rx.borrow(),
1018 IceTransportState::Closed | IceTransportState::Failed
1019 )
1020 {
1021 debug!("TCP read loop stopping (IceTransport Closed or Failed)");
1022 break;
1023 }
1024 }
1025 }
1026 }
1027 }
1028
1029 async fn run_keepalive_tick(inner: &Arc<IceTransportInner>) -> Option<BoxFuture<'static, ()>> {
1033 let state = *inner.state.borrow();
1034 if state == IceTransportState::Connected || state == IceTransportState::Disconnected {
1035 if inner.config.transport_mode == crate::TransportMode::WebRtc {
1036 let last_nanos = inner.last_received_nanos.load(Ordering::Relaxed);
1037 let now_nanos = inner.created_at.elapsed().as_nanos() as u64;
1038 let elapsed = Duration::from_nanos(now_nanos.saturating_sub(last_nanos));
1039 let ice_conn_timeout = inner.config.ice_connection_timeout;
1040 let tcp_selected = inner
1041 .selected_pair
1042 .lock()
1043 .as_ref()
1044 .map(|pair| pair.local.transport == "tcp")
1045 .unwrap_or(false);
1046 let disconnect_threshold = if tcp_selected {
1049 ice_conn_timeout.saturating_sub(Duration::from_secs(1))
1050 } else {
1051 inner.config.ice_disconnect_threshold
1052 };
1053 if elapsed > ice_conn_timeout {
1054 let _ = inner.set_state(IceTransportState::Failed);
1055 } else if elapsed > disconnect_threshold {
1056 if state != IceTransportState::Disconnected {
1057 let _ = inner.set_state(IceTransportState::Disconnected);
1058 }
1059 } else if state == IceTransportState::Disconnected {
1060 let _ = inner.set_state(IceTransportState::Connected);
1061 }
1062 }
1063
1064 let pair_opt = inner.selected_pair.lock().clone();
1066 if let Some(pair) = pair_opt {
1067 let socket = inner
1068 ._socket_rx_keeper
1069 .borrow()
1070 .clone()
1071 .or_else(|| resolve_socket(inner, &pair));
1072 if let Some(socket) = socket {
1073 let tx_id = random_bytes::<12>();
1074 let mut msg = StunMessage::binding_request(tx_id, Some("rustrtc"));
1075
1076 let remote_params = inner.remote_parameters.lock().clone();
1077 if let Some(params) = remote_params {
1078 let username = format!(
1079 "{}:{}",
1080 params.username_fragment,
1081 inner.local_parameters.lock().username_fragment
1082 );
1083 msg.attributes.push(StunAttribute::Username(username));
1084 msg.attributes
1085 .push(StunAttribute::Priority(pair.local.priority));
1086
1087 if let Ok(bytes) = msg.encode(Some(params.password.as_bytes()), true) {
1088 let (tx, rx) = oneshot::channel();
1090 {
1091 let mut map = inner.pending_transactions.lock();
1092 map.insert(tx_id, tx);
1093 }
1094
1095 let inner_weak = Arc::downgrade(inner);
1096 let cleanup: BoxFuture<'static, ()> = Box::pin(async move {
1097 let _ = with_timeout(Duration::from_secs(5), rx).await;
1098 if let Some(inner) = inner_weak.upgrade() {
1099 let mut map = inner.pending_transactions.lock();
1100 map.remove(&tx_id);
1101 }
1102 });
1103
1104 let _ = socket.send_to(&bytes, pair.remote.address).await;
1105 return Some(cleanup);
1106 }
1107 } else if inner.config.transport_mode != crate::TransportMode::WebRtc
1108 && let Ok(bytes) = msg.encode(None, false)
1109 {
1110 let _ = socket.send_to(&bytes, pair.remote.address).await;
1111 }
1112 }
1113 }
1114 }
1115 None
1116 }
1117
1118 async fn run_turn_refresh(inner: &Arc<IceTransportInner>) {
1134 if inner
1138 .turn_refresh_in_progress
1139 .swap(true, core::sync::atomic::Ordering::SeqCst)
1140 {
1141 return;
1142 }
1143 struct RefreshGuard<'a>(&'a core::sync::atomic::AtomicBool);
1146 impl Drop for RefreshGuard<'_> {
1147 fn drop(&mut self) {
1148 self.0.store(false, core::sync::atomic::Ordering::SeqCst);
1149 }
1150 }
1151 let _guard = RefreshGuard(&inner.turn_refresh_in_progress);
1152
1153 let state = *inner.state.borrow();
1154 if state != IceTransportState::Connected && state != IceTransportState::Disconnected {
1155 return;
1156 }
1157
1158 let all_clients: Vec<(SocketAddr, Arc<TurnClient>)> = {
1159 let clients = inner.gatherer.turn_clients.lock();
1160 clients.iter().map(|(k, v)| (*k, v.clone())).collect()
1161 };
1162
1163 if all_clients.is_empty() {
1164 return;
1165 }
1166
1167 let pair_opt = inner.selected_pair.lock().clone();
1168
1169 let remote_addr_for_perm = pair_opt.as_ref().map(|p| p.remote.address);
1170
1171 for (relay_local_addr, client) in all_clients {
1172 Self::refresh_one_turn_client(inner, relay_local_addr, &client, remote_addr_for_perm)
1173 .await;
1174 }
1175 }
1176
1177 async fn refresh_one_turn_client(
1178 inner: &Arc<IceTransportInner>,
1179 _relay_local_addr: SocketAddr,
1180 client: &Arc<TurnClient>,
1181 remote_addr_opt: Option<SocketAddr>,
1182 ) {
1183 async fn send_and_await_inner(
1184 client: &Arc<TurnClient>,
1185 inner: &Arc<IceTransportInner>,
1186 bytes: Vec<u8>,
1187 tx_id: [u8; 12],
1188 ) -> Option<StunDecoded> {
1189 let (tx, rx) = oneshot::channel();
1190 inner.pending_transactions.lock().insert(tx_id, tx);
1191 if let Err(e) = client.send(&bytes).await {
1192 debug!("TURN refresh send failed: {}", e);
1193 inner.pending_transactions.lock().remove(&tx_id);
1194 return None;
1195 }
1196 match with_timeout(Duration::from_secs(5), rx).await {
1197 Ok(Ok(msg)) => Some(msg),
1198 _ => {
1199 inner.pending_transactions.lock().remove(&tx_id);
1200 None
1201 }
1202 }
1203 }
1204
1205 'alloc: for attempt in 0..2u8 {
1208 match client.create_refresh_packet().await {
1209 Ok((bytes, tx_id)) => {
1210 match send_and_await_inner(client, inner, bytes, tx_id).await {
1211 Some(msg) if msg.class == StunClass::SuccessResponse => {
1212 trace!("TURN allocation refreshed successfully");
1213 break 'alloc;
1214 }
1215 Some(msg)
1216 if matches!(msg.error_code, Some(401) | Some(438)) && attempt == 0 =>
1217 {
1218 if let (Some(realm), Some(nonce)) = (msg.realm, msg.nonce) {
1220 debug!(
1221 "TURN Refresh got {}: updating nonce, retrying",
1222 msg.error_code.unwrap_or(0)
1223 );
1224 client.update_nonce(realm, nonce).await;
1225 }
1226 continue 'alloc;
1227 }
1228 Some(msg) => {
1229 debug!("TURN Refresh failed: error={:?}", msg.error_code);
1230 }
1231 None => {
1232 debug!("TURN Refresh timeout or send error");
1233 }
1234 }
1235 }
1236 Err(e) => debug!("TURN Refresh packet creation failed: {}", e),
1237 }
1238 break;
1239 }
1240
1241 if let Some(remote_addr) = remote_addr_opt {
1245 'perm: for attempt in 0..2u8 {
1246 match client.create_permission_packet(remote_addr).await {
1247 Ok((bytes, tx_id)) => {
1248 match send_and_await_inner(client, inner, bytes, tx_id).await {
1249 Some(msg) if msg.class == StunClass::SuccessResponse => {
1250 trace!("TURN permission refreshed for {}", remote_addr);
1251 break 'perm;
1252 }
1253 Some(msg)
1254 if matches!(msg.error_code, Some(401) | Some(438))
1255 && attempt == 0 =>
1256 {
1257 if let (Some(realm), Some(nonce)) = (msg.realm, msg.nonce) {
1258 debug!(
1259 "TURN CreatePermission got {}: updating nonce, retrying",
1260 msg.error_code.unwrap_or(0)
1261 );
1262 client.update_nonce(realm, nonce).await;
1263 }
1264 continue 'perm;
1265 }
1266 Some(msg) => {
1267 debug!(
1268 "TURN CreatePermission refresh failed: error={:?}",
1269 msg.error_code
1270 );
1271 }
1272 None => {
1273 debug!("TURN CreatePermission refresh timeout or send error");
1274 }
1275 }
1276 }
1277 Err(e) => debug!("TURN CreatePermission packet creation failed: {}", e),
1278 }
1279 break;
1280 }
1281 }
1282
1283 let bound_peers = client.bound_peers().await;
1286 let num_bindings = bound_peers.len();
1287 for peer in bound_peers {
1288 if let Some(channel) = client.get_channel(peer).await {
1289 'chan: for attempt in 0..2u8 {
1290 match client.create_channel_rebind_packet(peer, channel).await {
1291 Ok((bytes, tx_id)) => {
1292 match send_and_await_inner(client, inner, bytes, tx_id).await {
1293 Some(msg) if msg.class == StunClass::SuccessResponse => {
1294 trace!(
1295 "TURN ChannelBind refreshed: {} -> ch {}",
1296 peer, channel
1297 );
1298 break 'chan;
1299 }
1300 Some(msg)
1301 if matches!(msg.error_code, Some(401) | Some(438))
1302 && attempt == 0 =>
1303 {
1304 if let (Some(realm), Some(nonce)) = (msg.realm, msg.nonce) {
1305 debug!(
1306 "TURN ChannelBind got {}: updating nonce, retrying ch {}",
1307 msg.error_code.unwrap_or(0),
1308 channel
1309 );
1310 client.update_nonce(realm, nonce).await;
1311 }
1312 continue 'chan;
1313 }
1314 Some(msg) => {
1315 debug!(
1316 "TURN ChannelBind refresh failed: ch={} error={:?}",
1317 channel, msg.error_code
1318 );
1319 }
1320 None => {
1321 debug!(
1322 "TURN ChannelBind refresh timeout or send error: ch={}",
1323 channel
1324 );
1325 }
1326 }
1327 }
1328 Err(e) => {
1329 debug!("TURN ChannelBind refresh packet creation failed: {}", e);
1330 }
1331 }
1332 break;
1333 }
1334 }
1335 }
1336
1337 debug!(
1338 "TURN refresh done: allocation + {} permission + {} channel bindings",
1339 if remote_addr_opt.is_some() { 1 } else { 0 },
1340 num_bindings
1341 );
1342 }
1343}
1344
1345impl IceTransport {
1346 pub fn new(config: RtcConfiguration) -> (Self, impl core::future::Future<Output = ()> + Send) {
1347 let (candidate_tx, _) = broadcast::channel(100);
1348 let (socket_tx, socket_rx) = crate::platform::sync::mpsc::unbounded_channel();
1349 let gatherer = IceGatherer::new(config.clone(), candidate_tx.clone(), socket_tx);
1350 let (state_tx, state_rx) = watch::channel(IceTransportState::New);
1351 let runner_state_rx = state_tx.subscribe();
1352 let (gathering_state_tx, gathering_state_rx) = watch::channel(IceGathererState::New);
1353 let (selected_socket_tx, selected_socket_rx) = watch::channel(None);
1354 let (selected_rtcp_socket_tx, selected_rtcp_socket_rx) = watch::channel(None);
1355 let (selected_pair_tx, selected_pair_rx) = watch::channel(None);
1356 let (cmd_tx, cmd_rx) = mpsc::unbounded_channel();
1357 let (nomination_complete_tx, nomination_complete_rx) = watch::channel(None);
1358
1359 let inner = IceTransportInner {
1360 state: state_tx,
1361 _state_rx_keeper: state_rx,
1362 gathering_state: gathering_state_tx,
1363 _gathering_state_rx_keeper: gathering_state_rx,
1364 role: crate::platform::sync::Mutex::new(IceRole::Controlled),
1365 selected_pair: crate::platform::sync::Mutex::new(None),
1366 local_candidates: Mutex::new(Vec::new()),
1367 remote_candidates: crate::platform::sync::Mutex::new(Vec::new()),
1368 gather_state: crate::platform::sync::Mutex::new(IceGathererState::New),
1369 config: config.clone(),
1370 gatherer,
1371 local_parameters: crate::platform::sync::Mutex::new(IceParameters::generate()),
1372 remote_parameters: crate::platform::sync::Mutex::new(None),
1373 pending_transactions: crate::platform::sync::Mutex::new(BTreeMap::new()),
1374 data_receiver: crate::platform::sync::Mutex::new(None),
1375 buffered_packets: crate::platform::sync::Mutex::new(VecDeque::new()),
1376 selected_socket: selected_socket_tx,
1377 _socket_rx_keeper: selected_socket_rx,
1378 selected_rtcp_socket: selected_rtcp_socket_tx,
1379 _rtcp_socket_rx_keeper: selected_rtcp_socket_rx,
1380 selected_pair_notifier: selected_pair_tx,
1381 _selected_pair_rx_keeper: selected_pair_rx,
1382 created_at: Instant::now(),
1383 last_received_nanos: AtomicU64::new(0),
1384 candidate_tx: candidate_tx.clone(),
1385 cmd_tx,
1386 checking_pairs: Mutex::new(alloc::collections::BTreeSet::new()),
1387 nomination_complete: nomination_complete_tx,
1388 _nomination_complete_rx: nomination_complete_rx,
1389 restart_requested: core::sync::atomic::AtomicBool::new(false),
1390 nomination_generation: crate::platform::atomic64::AtomicU64::new(0),
1391 mdns_hostname: {
1392 #[cfg(feature = "std")]
1393 {
1394 config
1395 .enable_mdns
1396 .then(crate::transports::ice::mdns::MdnsResponder::generate_hostname)
1397 }
1398 #[cfg(not(feature = "std"))]
1399 {
1400 None
1401 }
1402 },
1403 turn_refresh_in_progress: core::sync::atomic::AtomicBool::new(false),
1404 upnp_refresh_in_progress: core::sync::atomic::AtomicBool::new(false),
1405 buffer_stats: Arc::new(BufferStats::default()),
1406 };
1407 let inner = Arc::new(inner);
1408 inner.gatherer.set_transport(Arc::downgrade(&inner));
1409
1410 let runner = IceTransportRunner {
1411 inner: inner.clone(),
1412 socket_rx,
1413 candidate_rx: candidate_tx.subscribe(),
1414 cmd_rx,
1415 state_rx: runner_state_rx,
1416 };
1417
1418 (Self { inner }, runner.run())
1419 }
1420
1421 pub fn state(&self) -> IceTransportState {
1422 *self.inner.state.borrow()
1423 }
1424
1425 pub fn subscribe_state(&self) -> watch::Receiver<IceTransportState> {
1426 self.inner.state.subscribe()
1427 }
1428
1429 pub fn subscribe_gathering_state(&self) -> watch::Receiver<IceGathererState> {
1430 self.inner.gathering_state.subscribe()
1431 }
1432
1433 pub fn subscribe_candidates(&self) -> broadcast::Receiver<IceCandidate> {
1434 self.inner.candidate_tx.subscribe()
1435 }
1436
1437 pub fn subscribe_selected_socket(&self) -> watch::Receiver<Option<IceSocketWrapper>> {
1438 self.inner.selected_socket.subscribe()
1439 }
1440
1441 pub(crate) fn subscribe_selected_rtcp_socket(
1442 &self,
1443 ) -> watch::Receiver<Option<IceSocketWrapper>> {
1444 self.inner.selected_rtcp_socket.subscribe()
1445 }
1446
1447 pub fn subscribe_selected_pair(&self) -> watch::Receiver<Option<IceCandidatePair>> {
1448 self.inner.selected_pair_notifier.subscribe()
1449 }
1450
1451 pub fn subscribe_nomination_complete(&self) -> watch::Receiver<Option<bool>> {
1455 self.inner.nomination_complete.subscribe()
1456 }
1457
1458 pub fn nudge_passive_tcp_nomination(&self) {
1461 if *self.inner.role.lock() != IceRole::Controlled {
1462 return;
1463 }
1464 if self.inner.nomination_complete.borrow().is_some() {
1465 return;
1466 }
1467 let inner = self.inner.clone();
1468 debug!("ICE: nudging passive TCP nomination (controlled, awaiting inbound TCP)");
1469 let rt_handle = inner.config.runtime_handle.clone();
1470 crate::spawn_rtc(rt_handle.as_ref(), tracing::Span::current(), async move {
1471 let streams: Vec<_> = inner
1472 .gatherer
1473 .tcp_streams
1474 .lock()
1475 .values()
1476 .cloned()
1477 .collect();
1478 for wrapper in streams {
1479 #[cfg(feature = "std")]
1480 if let IceSocketWrapper::TcpStream(_, _, peer) = wrapper {
1481 #[cfg(feature = "std")]
1482 complete_controlled_inbound_tcp_nomination(&wrapper, peer, inner).await;
1483 #[cfg(not(feature = "std"))]
1484 {
1485 let _ = (&wrapper, &peer, &inner);
1486 }
1487 return;
1488 }
1489 }
1490 });
1491 }
1492
1493 pub fn gather_state(&self) -> IceGathererState {
1494 self.inner.gatherer.state()
1495 }
1496
1497 pub fn role(&self) -> IceRole {
1498 *self.inner.role.lock()
1499 }
1500
1501 pub fn local_candidates(&self) -> Vec<IceCandidate> {
1502 self.inner.gatherer.local_candidates()
1503 }
1504
1505 pub(crate) fn local_rtcp_addr(&self) -> Option<SocketAddr> {
1506 self.inner
1507 .gatherer
1508 .local_candidates()
1509 .into_iter()
1510 .find(|candidate| candidate.component == 2)
1511 .map(|candidate| candidate.address)
1512 }
1513
1514 pub fn remote_candidates(&self) -> Vec<IceCandidate> {
1515 self.inner.remote_candidates.lock().clone()
1516 }
1517
1518 pub fn local_parameters(&self) -> IceParameters {
1519 self.inner.local_parameters.lock().clone()
1520 }
1521
1522 pub fn set_remote_parameters(&self, params: IceParameters) {
1523 *self.inner.remote_parameters.lock() = Some(params);
1524 }
1525
1526 pub async fn restart(&self) -> RtcResult<()> {
1541 self.inner
1548 .restart_requested
1549 .store(true, core::sync::atomic::Ordering::SeqCst);
1550 self.restart_internal().await
1551 }
1552
1553 async fn restart_internal(&self) -> RtcResult<()> {
1557 *self.inner.local_parameters.lock() = IceParameters::generate();
1560
1561 self.inner.checking_pairs.lock().await.clear();
1565 self.inner.pending_transactions.lock().clear();
1566 *self.inner.selected_pair.lock() = None;
1567 let _ = self.inner.selected_pair_notifier.send(None);
1568 self.inner
1571 .nomination_generation
1572 .fetch_add(1, core::sync::atomic::Ordering::SeqCst);
1573 let _ = self.inner.nomination_complete.send(None);
1574 let _ = self.inner.set_state(IceTransportState::Checking);
1575
1576 self.rebind_shared_udp_mux().await?;
1580
1581 debug!(
1582 label = self.inner.config.label.as_deref().unwrap_or("-"),
1583 "ICE restart: new ufrag={}, pwd=<redacted>",
1584 self.inner.local_parameters.lock().username_fragment
1585 );
1586 Ok(())
1587 }
1588
1589 async fn rebind_shared_udp_mux(&self) -> RtcResult<()> {
1592 let gatherer = &self.inner.gatherer;
1593 let listen_key = {
1594 let regs = gatherer.shared_udp_regs.lock();
1595 let Some(reg) = regs.first() else {
1596 return Ok(()); };
1598 reg.listen_key()
1599 };
1600
1601 gatherer.shared_udp_regs.lock().clear();
1604
1605 let ufrag = self.inner.local_parameters.lock().username_fragment.clone();
1606 let (_local_addr, handle, registration) =
1607 shared_udp::acquire(listen_key, ufrag).await.map_err(|e| {
1608 RtcError::Internal(format!("shared UDP mux rebind failed: {e:#}"))
1611 })?;
1612 gatherer.shared_udp_regs.lock().push(registration);
1613
1614 let wrapper = IceSocketWrapper::SharedUdp(Arc::new(handle));
1615 *gatherer.shared_udp_socket.lock() = Some(wrapper.clone());
1616 gatherer.socket_tx.send(wrapper).ok();
1618 Ok(())
1619 }
1620
1621 fn start_keepalive(&self) {
1622 }
1624
1625 pub fn start_gathering(&self) -> RtcResult<()> {
1626 {
1627 let mut state = self.inner.gather_state.lock();
1628 if *state == IceGathererState::Complete || *state == IceGathererState::Gathering {
1629 return Ok(());
1630 }
1631 *state = IceGathererState::Gathering;
1632 let _ = self.inner.gathering_state.send(IceGathererState::Gathering);
1633 }
1634
1635 let _ = self.inner.cmd_tx.send(IceCommand::StartGathering);
1636 Ok(())
1637 }
1638
1639 pub async fn start(&self, remote: IceParameters) -> RtcResult<()> {
1640 let previous_remote = self.inner.remote_parameters.lock().clone();
1648 if let Some(prev) = previous_remote
1649 && (prev.username_fragment != remote.username_fragment
1650 || prev.password != remote.password)
1651 {
1652 if self
1653 .inner
1654 .restart_requested
1655 .swap(false, core::sync::atomic::Ordering::SeqCst)
1656 {
1657 debug!(
1658 label = self.inner.config.label.as_deref().unwrap_or("-"),
1659 "ICE restart completing: peer re-signalled credentials"
1660 );
1661 } else {
1662 debug!(
1663 label = self.inner.config.label.as_deref().unwrap_or("-"),
1664 "remote ICE restart detected (ufrag/pwd changed): restarting locally"
1665 );
1666 self.restart_internal().await?;
1667 }
1668 } else {
1669 self.inner
1670 .restart_requested
1671 .store(false, core::sync::atomic::Ordering::SeqCst);
1672 }
1673
1674 self.start_gathering()?;
1675 self.start_keepalive();
1676 {
1677 let mut params = self.inner.remote_parameters.lock();
1678 *params = Some(remote);
1679 }
1680 self.inner.set_state(IceTransportState::Checking);
1681 self.try_connectivity_checks();
1682 Ok(())
1683 }
1684
1685 pub async fn start_direct(&self, remote_addr: SocketAddr) -> RtcResult<()> {
1686 self.start_gathering()?;
1687 self.start_keepalive();
1688
1689 let mut rx = self.subscribe_candidates();
1692 let start = Instant::now();
1693 let timeout_dur = Duration::from_secs(2);
1694
1695 let is_suitable = |c: &IceCandidate| -> bool {
1696 if !remote_addr.ip().is_loopback() && c.address.ip().is_loopback() {
1697 return false;
1698 }
1699 true
1700 };
1701
1702 let mut best_local: Option<IceCandidate> = None;
1703
1704 {
1706 let candidates = self.inner.gatherer.local_candidates();
1707 for c in candidates {
1708 if is_suitable(&c) {
1709 best_local = Some(c);
1710 break;
1711 }
1712 }
1713 }
1714
1715 if best_local.is_none() {
1717 loop {
1718 let remaining = timeout_dur
1719 .checked_sub(start.elapsed())
1720 .unwrap_or(Duration::ZERO);
1721 if remaining.is_zero() {
1722 break;
1723 }
1724
1725 match with_timeout(remaining, rx.recv()).await {
1726 Ok(Ok(c)) => {
1727 if is_suitable(&c) {
1728 best_local = Some(c);
1729 break;
1730 }
1731 }
1732 _ => break,
1733 }
1734 }
1735 }
1736
1737 let local = if let Some(best) = best_local {
1739 best
1740 } else if let Some(first) = self.inner.gatherer.local_candidates().first() {
1741 first.clone()
1742 } else {
1743 return Err(RtcError::Internal(format!(
1744 "No local candidates gathered for direct connection"
1745 )));
1746 };
1747
1748 let remote = IceCandidate::host(remote_addr, 1);
1749 let pair = IceCandidatePair::new(local, remote);
1750
1751 *self.inner.selected_pair.lock() = Some(pair.clone());
1752 let _ = self.inner.selected_pair_notifier.send(Some(pair.clone()));
1753 if let Some(socket) = resolve_socket(&self.inner, &pair) {
1754 let _ = self.inner.selected_socket.send(Some(socket.clone()));
1755 publish_selected_rtcp_socket(&self.inner, Some(socket));
1756 }
1757 let _ = self.inner.set_state(IceTransportState::Connected);
1758 Ok(())
1759 }
1760
1761 pub async fn setup_direct_rtp(&self, remote_addr: SocketAddr) -> RtcResult<SocketAddr> {
1765 self.setup_direct_rtp_with_rtcp(remote_addr, false).await
1766 }
1767
1768 pub(crate) async fn setup_direct_rtp_with_rtcp(
1769 &self,
1770 remote_addr: SocketAddr,
1771 bind_rtcp: bool,
1772 ) -> RtcResult<SocketAddr> {
1773 let bind_ip = if let Some(bind_ip_str) = &self.inner.config.bind_ip {
1774 bind_ip_str.parse::<IpAddr>().unwrap_or_else(|_| {
1775 get_local_ip().unwrap_or(IpAddr::V4(core::net::Ipv4Addr::UNSPECIFIED))
1776 })
1777 } else if let Ok(ip) = get_local_ip() {
1778 ip
1779 } else {
1780 IpAddr::V4(core::net::Ipv4Addr::UNSPECIFIED)
1781 };
1782
1783 let socket = self.inner.gatherer.bind_socket(bind_ip).await?;
1784 let local_addr = socket.local_addr()?;
1785
1786 self.inner.gatherer.register_bound(&socket);
1789
1790 let mut cand_addr = local_addr;
1792 let mut upnp_external_addr: Option<SocketAddr> = None;
1793
1794 #[cfg(feature = "std")]
1797 if self.inner.config.enable_upnp && !local_addr.ip().is_loopback() && !local_addr.is_ipv6()
1798 {
1799 let mut mapper = UpnpPortMapper::with_lease_duration(
1800 local_addr,
1801 self.inner.config.upnp_lease_duration,
1802 );
1803 if let Err(e) = mapper.discover().await {
1804 trace!("UPnP discovery failed for RTP mode: {}", e);
1805 } else if let Ok(ext_addr) = mapper.add_mapping(0).await {
1806 debug!(
1807 "UPnP mapping created for RTP mode: {} -> {}",
1808 local_addr, ext_addr
1809 );
1810 cand_addr.set_ip(ext_addr.ip());
1811 cand_addr.set_port(ext_addr.port());
1812 upnp_external_addr = Some(ext_addr);
1813 self.inner.gatherer.upnp_mappers.lock().push(mapper);
1814 } else {
1815 debug!("UPnP mapping failed for RTP mode, using local address");
1816 }
1817 }
1818
1819 if upnp_external_addr.is_none() {
1821 if let Some(ext_ip) = &self.inner.config.external_ip {
1822 if let Ok(parsed_ip) = ext_ip.parse::<IpAddr>()
1823 && !bind_ip.is_loopback()
1824 {
1825 cand_addr.set_ip(parsed_ip);
1826 }
1827 } else if bind_ip.is_unspecified()
1828 && let Ok(local_ip) = get_local_ip()
1829 {
1830 cand_addr.set_ip(local_ip);
1831 }
1832 }
1833
1834 if upnp_external_addr.is_none()
1836 && let Some(ext_port) = self.inner.config.external_port
1837 && !bind_ip.is_loopback()
1838 {
1839 cand_addr.set_port(ext_port);
1840 }
1841
1842 let mut local_candidate = IceCandidate::host(cand_addr, 1);
1843 if cand_addr != local_addr {
1844 local_candidate.related_address = Some(local_addr);
1845 }
1846 let mut rtcp_socket = None;
1847 let mut rtcp_candidate = None;
1848 if bind_rtcp {
1849 let (rtcp, candidate) =
1850 bind_direct_rtcp_socket(&self.inner, local_addr, cand_addr.ip()).await?;
1851 rtcp_socket = Some(rtcp);
1852 rtcp_candidate = Some(candidate);
1853 }
1854 self.inner.gatherer.push_candidate(local_candidate.clone());
1855 if let Some(candidate) = rtcp_candidate {
1856 self.inner.gatherer.push_candidate(candidate);
1857 }
1858
1859 *self.inner.gatherer.state.lock() = IceGathererState::Complete;
1861 let _ = self.inner.gathering_state.send(IceGathererState::Complete);
1862
1863 let remote_candidate = IceCandidate::host(remote_addr, 1);
1865 let pair = IceCandidatePair::new(local_candidate, remote_candidate);
1866 *self.inner.selected_pair.lock() = Some(pair.clone());
1867 let _ = self.inner.selected_pair_notifier.send(Some(pair));
1868 let _ = self
1869 .inner
1870 .selected_socket
1871 .send(Some(socket.clone()));
1872 let rtcp_socket = rtcp_socket.unwrap_or_else(|| socket.clone());
1873 let _ = self
1874 .inner
1875 .selected_rtcp_socket
1876 .send(Some(rtcp_socket));
1877 let _ = self.inner.set_state(IceTransportState::Connected);
1878
1879 Ok(cand_addr)
1880 }
1881
1882 pub async fn setup_direct_rtp_offer(&self) -> RtcResult<SocketAddr> {
1886 self.setup_direct_rtp_offer_with_rtcp(false).await
1887 }
1888
1889 pub(crate) async fn setup_direct_rtp_offer_with_rtcp(
1890 &self,
1891 bind_rtcp: bool,
1892 ) -> RtcResult<SocketAddr> {
1893 let bind_ip = if let Some(bind_ip_str) = &self.inner.config.bind_ip {
1894 bind_ip_str.parse::<IpAddr>().unwrap_or_else(|_| {
1895 get_local_ip().unwrap_or(IpAddr::V4(core::net::Ipv4Addr::UNSPECIFIED))
1896 })
1897 } else if let Ok(ip) = get_local_ip() {
1898 ip
1899 } else {
1900 IpAddr::V4(core::net::Ipv4Addr::UNSPECIFIED)
1901 };
1902
1903 let socket = self.inner.gatherer.bind_socket(bind_ip).await?;
1904 let local_addr = socket.local_addr()?;
1905 self.inner.gatherer.register_bound(&socket);
1906
1907 let mut cand_addr = local_addr;
1908 let mut upnp_external_addr: Option<SocketAddr> = None;
1909
1910 #[cfg(feature = "std")]
1913 if self.inner.config.enable_upnp && !local_addr.ip().is_loopback() && !local_addr.is_ipv6()
1914 {
1915 let mut mapper = UpnpPortMapper::with_lease_duration(
1916 local_addr,
1917 self.inner.config.upnp_lease_duration,
1918 );
1919 if let Err(e) = mapper.discover().await {
1920 trace!("UPnP discovery failed for RTP offer mode: {}", e);
1921 } else if let Ok(ext_addr) = mapper.add_mapping(0).await {
1922 debug!(
1923 "UPnP mapping created for RTP offer mode: {} -> {}",
1924 local_addr, ext_addr
1925 );
1926 cand_addr.set_ip(ext_addr.ip());
1927 cand_addr.set_port(ext_addr.port());
1928 upnp_external_addr = Some(ext_addr);
1929 self.inner.gatherer.upnp_mappers.lock().push(mapper);
1930 } else {
1931 debug!("UPnP mapping failed for RTP offer mode, using local address");
1932 }
1933 }
1934
1935 if upnp_external_addr.is_none() {
1937 if let Some(ext_ip) = &self.inner.config.external_ip {
1938 if let Ok(parsed_ip) = ext_ip.parse::<IpAddr>()
1939 && !bind_ip.is_loopback()
1940 {
1941 cand_addr.set_ip(parsed_ip);
1942 }
1943 } else if bind_ip.is_unspecified()
1944 && let Ok(local_ip) = get_local_ip()
1945 {
1946 cand_addr.set_ip(local_ip);
1947 }
1948 }
1949
1950 if upnp_external_addr.is_none()
1952 && let Some(ext_port) = self.inner.config.external_port
1953 && !bind_ip.is_loopback()
1954 {
1955 cand_addr.set_port(ext_port);
1956 }
1957
1958 let mut local_candidate = IceCandidate::host(cand_addr, 1);
1959 if cand_addr != local_addr {
1960 local_candidate.related_address = Some(local_addr);
1961 }
1962 let mut rtcp_socket = None;
1963 let mut rtcp_candidate = None;
1964 if bind_rtcp {
1965 let (rtcp, candidate) =
1966 bind_direct_rtcp_socket(&self.inner, local_addr, cand_addr.ip()).await?;
1967 rtcp_socket = Some(rtcp);
1968 rtcp_candidate = Some(candidate);
1969 }
1970 self.inner.gatherer.push_candidate(local_candidate);
1971 if let Some(candidate) = rtcp_candidate {
1972 self.inner.gatherer.push_candidate(candidate);
1973 }
1974 if let Some(rtcp_socket) = rtcp_socket {
1975 let _ = self
1976 .inner
1977 .selected_rtcp_socket
1978 .send(Some(rtcp_socket));
1979 }
1980
1981 *self.inner.gatherer.state.lock() = IceGathererState::Complete;
1982 let _ = self.inner.gathering_state.send(IceGathererState::Complete);
1983
1984 Ok(cand_addr)
1985 }
1986
1987 pub fn complete_direct_rtp(&self, remote_addr: SocketAddr) {
1990 let remote_candidate = IceCandidate::host(remote_addr, 1);
1991 let local_candidate = self
1992 .inner
1993 .gatherer
1994 .local_candidates()
1995 .into_iter()
1996 .find(|candidate| candidate.component == 1)
1997 .unwrap_or_else(|| {
1998 IceCandidate::host(
1999 SocketAddr::new(IpAddr::V4(core::net::Ipv4Addr::LOCALHOST), 0),
2000 1,
2001 )
2002 });
2003 let pair = IceCandidatePair::new(local_candidate, remote_candidate);
2004 *self.inner.selected_pair.lock() = Some(pair.clone());
2005 let _ = self.inner.selected_pair_notifier.send(Some(pair.clone()));
2006 if let Some(socket) = resolve_socket(&self.inner, &pair) {
2007 let _ = self.inner.selected_socket.send(Some(socket.clone()));
2008 publish_selected_rtcp_socket(&self.inner, Some(socket));
2009 }
2010 let _ = self.inner.set_state(IceTransportState::Connected);
2011 }
2012
2013 fn destroy_turn_allocations_best_effort(&self) {
2020 let clients: Vec<Arc<TurnClient>> = {
2025 let map = self.inner.gatherer.turn_clients.lock();
2026 map.values().cloned().collect()
2027 };
2028 for client in &clients {
2029 if let Ok((bytes, _tx_id)) = client.create_destroy_packet_sync()
2030 && client.try_send_sync(&bytes)
2031 {
2032 trace!("TURN allocation destroy Refresh(LIFETIME=0) sent (best-effort)");
2033 }
2034 }
2035 }
2036
2037 pub fn stop(&self) {
2038 self.destroy_turn_allocations_best_effort();
2045
2046 #[cfg(feature = "std")]
2053 if let Ok(handle) = tokio::runtime::Handle::try_current() {
2054 let upnp_clone = self.inner.gatherer.clone();
2055 handle.spawn(async move {
2056 upnp_clone.cleanup_upnp_mappings().await;
2057 });
2058 }
2059
2060 let _ = self.inner.set_state(IceTransportState::Closed);
2061 let _ = self.inner.selected_socket.send(None);
2062 let _ = self.inner.selected_rtcp_socket.send(None);
2063 let _ = self.inner.selected_pair_notifier.send(None);
2064 *self.inner.selected_pair.lock() = None;
2065 self.inner.gatherer.sockets.lock().clear();
2066 self.inner.gatherer.tcp_listeners.lock().clear();
2067 self.inner.gatherer.tcp_streams.lock().clear();
2068 self.inner.gatherer.shared_tcp_regs.lock().clear();
2069 self.inner.gatherer.shared_udp_regs.lock().clear();
2070 self.inner.gatherer.turn_clients.lock().clear();
2071 *self.inner.gatherer.shared_udp_socket.lock() = None;
2074 }
2075
2076 #[cfg(test)]
2081 pub fn force_state_for_test(&self, state: IceTransportState) {
2082 let _ = self.inner.set_state(state);
2083 }
2084
2085 pub fn set_role(&self, role: IceRole) {
2086 *self.inner.role.lock() = role;
2087 }
2088
2089 pub fn add_remote_candidate(&self, candidate: IceCandidate) {
2090 let mut list = self.inner.remote_candidates.lock();
2091 list.push(candidate);
2092 drop(list);
2093 self.try_connectivity_checks();
2094 }
2095
2096 pub fn select_pair(&self, pair: IceCandidatePair) {
2097 *self.inner.selected_pair.lock() = Some(pair.clone());
2098 let _ = self.inner.selected_pair_notifier.send(Some(pair.clone()));
2099 if let Some(socket) = resolve_socket(&self.inner, &pair) {
2100 let _ = self.inner.selected_socket.send(Some(socket.clone()));
2101 publish_selected_rtcp_socket(&self.inner, Some(socket));
2102 }
2103 let _ = self.inner.set_state(IceTransportState::Connected);
2104 }
2105
2106 pub fn config(&self) -> &RtcConfiguration {
2107 &self.inner.config
2108 }
2109
2110 pub fn get_selected_socket(&self) -> Option<IceSocketWrapper> {
2111 if let Some(socket) = self.inner._socket_rx_keeper.borrow().clone() {
2112 return Some(socket);
2113 }
2114 let pair = self.inner.selected_pair.lock().clone()?;
2115 resolve_socket(&self.inner, &pair)
2116 }
2117
2118 pub fn get_selected_pair(&self) -> Option<IceCandidatePair> {
2119 self.inner.selected_pair.lock().clone()
2120 }
2121
2122 pub async fn set_data_receiver(&self, receiver: Arc<dyn PacketReceiver>) {
2123 {
2124 let mut rx_lock = self.inner.data_receiver.lock();
2125 *rx_lock = Some(receiver.clone());
2126 }
2127
2128 let packets: Vec<_> = {
2129 let mut buffer = self.inner.buffered_packets.lock();
2130 if buffer.is_empty() {
2131 return;
2132 }
2133 debug!(
2134 count = buffer.len(),
2135 "Flushing buffered RTP packets to newly registered data_receiver"
2136 );
2137 buffer.drain(..).collect()
2138 };
2139
2140 let mut marshal_buf = Vec::new();
2141 for (packet, addr) in packets {
2142 receiver
2143 .receive(Bytes::from(packet), addr, &mut marshal_buf)
2144 .await;
2145 }
2146 }
2147
2148 fn try_connectivity_checks(&self) {
2149 let _ = self.inner.cmd_tx.send(IceCommand::RunChecks);
2150 }
2151
2152 async fn handle_turn_packet(
2153 packet: &[u8],
2154 inner: &Arc<IceTransportInner>,
2155 client: &Arc<TurnClient>,
2156 relayed_addr: SocketAddr,
2157 marshal_buf: &mut Vec<u8>,
2158 ) {
2159 if packet.len() >= 4 {
2161 let channel_num = u16::from_be_bytes([packet[0], packet[1]]);
2162 if (0x4000..=0x7FFF).contains(&channel_num) {
2163 let len = u16::from_be_bytes([packet[2], packet[3]]) as usize;
2164 if packet.len() >= 4 + len {
2165 let data = &packet[4..4 + len];
2166 if let Some(peer_addr) = client.get_peer(channel_num).await {
2167 handle_packet(
2168 data,
2169 peer_addr,
2170 inner.clone(),
2171 IceSocketWrapper::Turn(client.clone(), relayed_addr),
2172 marshal_buf,
2173 )
2174 .await;
2175 }
2176 }
2177 return;
2178 }
2179 }
2180
2181 if let Ok(msg) = StunMessage::decode(packet) {
2182 if msg.class == StunClass::Indication && msg.method == StunMethod::Data {
2183 if let Some(data) = &msg.data
2184 && let Some(peer_addr) = msg.xor_peer_address
2185 {
2186 handle_packet(
2187 data,
2188 peer_addr,
2189 inner.clone(),
2190 IceSocketWrapper::Turn(client.clone(), relayed_addr),
2191 marshal_buf,
2192 )
2193 .await;
2194 }
2195 } else {
2196 handle_packet(
2198 packet,
2199 relayed_addr,
2200 inner.clone(),
2201 IceSocketWrapper::Turn(client.clone(), relayed_addr),
2202 marshal_buf,
2203 )
2204 .await;
2205 }
2206 }
2207 }
2208}
2209
2210async fn perform_connectivity_checks_async(inner: Arc<IceTransportInner>) {
2211 let state = *inner.state.borrow();
2212 if state != IceTransportState::Checking {
2213 return;
2214 }
2215
2216 if inner.selected_pair.lock().is_some() {
2218 return;
2219 }
2220
2221 let remotes = inner.remote_candidates.lock().clone();
2222 let role = *inner.role.lock();
2223
2224 if remotes.is_empty() {
2225 return;
2226 }
2227
2228 let mut locals = inner.gatherer.local_candidates();
2229
2230 if locals.is_empty() && role == IceRole::Controlling {
2234 use core::net::{IpAddr, Ipv4Addr};
2235 for remote in &remotes {
2236 if remote.transport == "tcp" && remote.tcp_type == Some(TcpType::Passive) {
2237 locals.push(IceCandidate::tcp(
2238 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
2239 remote.component,
2240 "active",
2241 ));
2242 }
2243 }
2244 }
2245
2246 if locals.is_empty() {
2247 return;
2248 }
2249
2250 let mut pairs = Vec::new();
2251
2252 for local in &locals {
2253 for remote in &remotes {
2254 if local.transport != remote.transport {
2255 continue;
2256 }
2257 if local.component != remote.component {
2258 continue;
2259 }
2260 if local.address.ip().is_loopback() && !remote.address.ip().is_loopback() {
2262 continue;
2263 }
2264 if local.address.is_ipv4() != remote.address.is_ipv4() {
2265 continue;
2266 }
2267 if role == IceRole::Controlled
2271 && local.transport == "tcp"
2272 && local.tcp_type == Some(TcpType::Passive)
2273 {
2274 continue;
2275 }
2276 pairs.push(IceCandidatePair::new(local.clone(), remote.clone()));
2277 }
2278 }
2279
2280 pairs.sort_by_key(|p| core::cmp::Reverse(p.priority(role)));
2282
2283 if inner.config.prefer_srflx_over_natted_host {
2290 let is_private_ip = |ip: core::net::IpAddr| -> bool {
2291 match ip {
2292 core::net::IpAddr::V4(v4) => v4.is_private(),
2293 core::net::IpAddr::V6(v6) => v6.is_unique_local(),
2294 }
2295 };
2296 let is_behind_nat = |pair: &IceCandidatePair| -> bool {
2297 pair.local.typ == IceCandidateType::Host
2298 && is_private_ip(pair.local.address.ip())
2299 && !(pair.remote.typ == IceCandidateType::Host
2300 && is_private_ip(pair.remote.address.ip()))
2301 };
2302 pairs.sort_by(|a, b| {
2303 let a_natted = is_behind_nat(a);
2304 let b_natted = is_behind_nat(b);
2305 if a_natted != b_natted {
2306 return a_natted.cmp(&b_natted);
2307 }
2308 b.priority(role).cmp(&a.priority(role))
2309 });
2310 }
2311
2312 let mut pairs_to_check = Vec::new();
2313 {
2314 let mut checking = inner.checking_pairs.lock().await;
2315 for pair in pairs {
2316 let key = (pair.local.address, pair.remote.address);
2317 if !checking.contains(&key) {
2318 checking.insert(key);
2319 pairs_to_check.push(pair);
2320 }
2321 }
2322 }
2323
2324 if pairs_to_check.is_empty() {
2325 return;
2326 }
2327 let mut checks = futures::stream::FuturesUnordered::new();
2328
2329 for pair in pairs_to_check {
2330 let inner = inner.clone();
2331 let local = pair.local.clone();
2332 let remote = pair.remote.clone();
2333
2334 checks.push(async move {
2335 let key = (local.address, remote.address);
2336 let res = perform_binding_check(&local, &remote, &inner, role, false).await;
2337
2338 {
2339 let mut checking = inner.checking_pairs.lock().await;
2340 checking.remove(&key);
2341 }
2342
2343 match res {
2344 Ok(_) => Some(IceCandidatePair::new(local, remote)),
2345 Err(e) => {
2346 trace!(
2351 label = inner.config.label.as_deref().unwrap_or("-"),
2352 "ICE connectivity check failed: {} -> {}: {}",
2353 local.address,
2354 remote.address,
2355 e
2356 );
2357 None
2358 }
2359 }
2360 });
2361 }
2362
2363 if checks.is_empty() {
2364 return;
2365 }
2366
2367 #[cfg(feature = "std")]
2368 use futures::stream::StreamExt;
2369 let mut successful_pairs: Vec<IceCandidatePair> = Vec::new();
2370
2371 const NOMINATION_GRACE: Duration = Duration::from_millis(200);
2378 loop {
2379 let next = if successful_pairs.is_empty() {
2380 checks.next().await
2381 } else {
2382 let mut checks_fut = core::pin::pin!(checks.next());
2384 let mut grace_fut = core::pin::pin!(crate::platform::task::sleep(NOMINATION_GRACE));
2385 match crate::platform::select::select2(&mut checks_fut, &mut grace_fut).await {
2386 crate::platform::select::Either::A(res) => res,
2387 crate::platform::select::Either::B(_) => break,
2388 }
2389 };
2390
2391 match next {
2392 Some(pair) => {
2393 if let Some(pair) = pair {
2394 let key = (pair.local.address, pair.remote.address);
2396 if !successful_pairs
2397 .iter()
2398 .any(|p| (p.local.address, p.remote.address) == key)
2399 {
2400 successful_pairs.push(pair);
2401 }
2402 }
2403 }
2404 None => break,
2405 }
2406 }
2407
2408 if successful_pairs.is_empty() {
2409 return;
2414 }
2415
2416 successful_pairs.sort_by_key(|p| core::cmp::Reverse(p.priority(role)));
2418
2419 for p in &successful_pairs {
2420 debug!(
2421 label = inner.config.label.as_deref().unwrap_or("-"),
2422 "ICE successful pair ({}): local {} {:?} -> remote {} {:?}",
2423 if role == IceRole::Controlling {
2424 "controlling"
2425 } else {
2426 "controlled"
2427 },
2428 p.local.address,
2429 p.local.typ,
2430 p.remote.address,
2431 p.remote.typ
2432 );
2433 }
2434
2435 if role == IceRole::Controlling {
2436 let _ = inner.set_state(IceTransportState::Connected);
2438
2439 if inner.nomination_complete.borrow().is_some() {
2445 debug!(
2446 label = inner.config.label.as_deref().unwrap_or("-"),
2447 "ICE checks complete (controlling): already nominated, keeping selected pair"
2448 );
2449 return;
2450 }
2451
2452 let nomination_start = crate::platform::time::Instant::now();
2469 let mut nominated_pair: Option<IceCandidatePair> = None;
2470 for (idx, pair) in successful_pairs.iter().enumerate() {
2471 if idx > 0
2473 && crate::platform::time::Instant::now().duration_since(nomination_start)
2474 >= inner.config.nomination_timeout
2475 {
2476 debug!("Nomination deadline reached before trying all candidate pairs");
2477 break;
2478 }
2479 debug!(
2480 label = inner.config.label.as_deref().unwrap_or("-"),
2481 "Controlling agent nominating pair: {} -> {}",
2482 pair.local.address,
2483 pair.remote.address
2484 );
2485 match perform_binding_check(&pair.local, &pair.remote, &inner, role, true).await {
2486 Ok(_) => {
2487 debug!(
2488 label = inner.config.label.as_deref().unwrap_or("-"),
2489 "Nomination succeeded: {} -> {}", pair.local.address, pair.remote.address
2490 );
2491 nominated_pair = Some(pair.clone());
2492 break;
2493 }
2494 Err(e) => {
2495 debug!(
2496 label = inner.config.label.as_deref().unwrap_or("-"),
2497 "Nomination failed for {} -> {}: {}",
2498 pair.local.address,
2499 pair.remote.address,
2500 e
2501 );
2502 }
2503 }
2504 }
2505
2506 let final_pair = nominated_pair
2509 .clone()
2510 .unwrap_or_else(|| successful_pairs[0].clone());
2511 let nominated = nominated_pair.is_some();
2512 *inner.selected_pair.lock() = Some(final_pair.clone());
2513 let _ = inner.selected_pair_notifier.send(Some(final_pair.clone()));
2514 if let Some(socket) = resolve_socket(&inner, &final_pair) {
2515 let _ = inner.selected_socket.send(Some(socket.clone()));
2516 publish_selected_rtcp_socket(&inner, Some(socket));
2517 }
2518 debug!(
2519 label = inner.config.label.as_deref().unwrap_or("-"),
2520 "ICE checks complete. Selected pair: {} -> {}",
2521 final_pair.local.address,
2522 final_pair.remote.address
2523 );
2524
2525 if nominated {
2526 let _ = inner.nomination_complete.send(Some(true));
2527 } else {
2528 let _ = inner.nomination_complete.send(Some(false));
2529 let _ = inner.set_state(IceTransportState::Failed);
2530 }
2531 } else {
2532 if inner.nomination_complete.borrow().is_some() {
2541 debug!(
2542 label = inner.config.label.as_deref().unwrap_or("-"),
2543 "ICE checks complete (controlled): keeping peer-nominated pair"
2544 );
2545 return;
2546 }
2547 let pair = &successful_pairs[0];
2548 *inner.selected_pair.lock() = Some(pair.clone());
2549 let _ = inner.selected_pair_notifier.send(Some(pair.clone()));
2550 if let Some(socket) = resolve_socket(&inner, pair) {
2551 let _ = inner.selected_socket.send(Some(socket.clone()));
2552 publish_selected_rtcp_socket(&inner, Some(socket));
2553 }
2554 let _ = inner.set_state(IceTransportState::Connected);
2555 if pair.local.transport == "tcp" {
2556 let _ = inner.nomination_complete.send(Some(true));
2557 }
2558 debug!(
2559 label = inner.config.label.as_deref().unwrap_or("-"),
2560 "ICE checks complete. Selected pair: {} -> {}", pair.local.address, pair.remote.address
2561 );
2562
2563 if pair.local.transport != "tcp"
2569 && inner.nomination_complete.borrow().is_none()
2570 {
2571 debug!(
2572 label = inner.config.label.as_deref().unwrap_or("-"),
2573 "Controlled checks complete without nomination — waiting for USE-CANDIDATE"
2574 );
2575 let deadline = Instant::now() + inner.config.nomination_timeout;
2576 while Instant::now() < deadline
2577 && inner.nomination_complete.borrow().is_none()
2578 && inner.state.borrow().clone() == IceTransportState::Connected
2579 {
2580 crate::platform::task::sleep(core::time::Duration::from_millis(20)).await;
2581 }
2582 if inner.nomination_complete.borrow().is_none() {
2583 debug!(
2584 label = inner.config.label.as_deref().unwrap_or("-"),
2585 "Nomination did not arrive in time; keeping best-effort selected pair"
2586 );
2587 let _ = inner.nomination_complete.send(Some(true));
2588 }
2589 }
2590 }
2591}
2592
2593fn resolve_socket(inner: &IceTransportInner, pair: &IceCandidatePair) -> Option<IceSocketWrapper> {
2594 if pair.local.typ == IceCandidateType::Relay {
2595 let clients = inner.gatherer.turn_clients.lock();
2596 clients
2597 .get(&pair.local.address)
2598 .map(|c| IceSocketWrapper::Turn(c.clone(), pair.local.address))
2599 } else if pair.local.transport == "tcp" {
2600 let streams = inner.gatherer.tcp_streams.lock();
2604 for wrapper in streams.values() {
2605 #[cfg(feature = "std")]
2606 if let IceSocketWrapper::TcpStream(_, _, peer) = wrapper
2607 && *peer == pair.remote.address
2608 {
2609 return Some(wrapper.clone());
2610 }
2611 }
2612 drop(streams);
2613 inner.gatherer.get_tcp_socket(pair.local.base_address())
2614 } else {
2615 if pair.local.typ == IceCandidateType::Host
2617 && let Some(shared) = inner.gatherer.shared_udp_socket.lock().clone()
2618 {
2619 return Some(shared);
2620 }
2621 if let Some(platform) = inner.gatherer.get_platform_socket(pair.local.base_address()) {
2623 return Some(IceSocketWrapper::Platform(platform));
2624 }
2625 let socket = inner.gatherer.get_socket(pair.local.base_address());
2626 if socket.is_none() {
2627 debug!(
2628 "resolve_socket: failed to find socket for {}",
2629 pair.local.base_address()
2630 );
2631 }
2632 socket.map(IceSocketWrapper::Udp)
2633 }
2634}
2635
2636fn publish_selected_socket(
2637 inner: &IceTransportInner,
2638 pair: &IceCandidatePair,
2639 inbound: Option<&IceSocketWrapper>,
2640) {
2641 let socket = match inbound {
2644 #[cfg(feature = "std")]
2645 Some(s @ IceSocketWrapper::TcpStream(_, _, _)) => Some(s.clone()),
2646 _ => resolve_socket(inner, pair),
2647 };
2648 if let Some(socket) = socket {
2649 #[cfg(feature = "std")]
2650 let inbound_tcp = matches!(inbound, Some(IceSocketWrapper::TcpStream(_, _, _)));
2651 #[cfg(not(feature = "std"))]
2652 let inbound_tcp = false;
2653 debug!(
2654 pair_local = %pair.local.address,
2655 pair_remote = %pair.remote.address,
2656 socket = %socket.diag(),
2657 inbound_tcp,
2658 "ICE: published selected socket"
2659 );
2660 let _ = inner.selected_socket.send(Some(socket.clone()));
2661 publish_selected_rtcp_socket(inner, Some(socket));
2662 }
2663}
2664
2665fn commit_verified_nomination(
2671 inner: &IceTransportInner,
2672 generation: u64,
2673 pair: &IceCandidatePair,
2674 sender: &IceSocketWrapper,
2675) -> bool {
2676 if inner
2677 .nomination_generation
2678 .load(core::sync::atomic::Ordering::SeqCst)
2679 != generation
2680 {
2681 return false;
2682 }
2683 *inner.selected_pair.lock() = Some(pair.clone());
2684 let _ = inner.selected_pair_notifier.send(Some(pair.clone()));
2685 publish_selected_socket(inner, pair, Some(sender));
2686 true
2687}
2688
2689#[cfg(feature = "std")]
2690async fn complete_controlled_inbound_tcp_nomination(
2691 sender: &IceSocketWrapper,
2692 addr: SocketAddr,
2693 inner: Arc<IceTransportInner>,
2694) {
2695 if *inner.role.lock() != IceRole::Controlled {
2696 return;
2697 }
2698 #[cfg(feature = "std")]
2699 let IceSocketWrapper::TcpStream(read, _, _) = sender else {
2700 return;
2701 };
2702 if inner.nomination_complete.borrow().is_some() {
2703 if let Some(pair) = inner.selected_pair.lock().clone() {
2704 publish_selected_socket(&inner, &pair, Some(sender));
2705 }
2706 return;
2707 }
2708
2709 let local_addr: SocketAddr = {
2710 let s = read.lock().await;
2711 s.local_addr()
2712 .unwrap_or_else(|_| "0.0.0.0:0".parse().unwrap())
2713 };
2714
2715 let locals = inner.gatherer.local_candidates();
2716 let local_cand = locals.iter().find(|c| {
2717 c.base_address() == local_addr
2718 || (c.transport == "tcp"
2719 && c.base_address().port() == local_addr.port()
2720 && (c.base_address().ip().is_unspecified() || local_addr.ip().is_unspecified()))
2721 });
2722
2723 let pair = {
2724 let remotes = inner.remote_candidates.lock();
2725 let remote_cand = remotes.iter().find(|c| c.address == addr);
2726 if let (Some(l), Some(r)) = (local_cand, remote_cand) {
2727 Some(IceCandidatePair::new(l.clone(), r.clone()))
2728 } else {
2729 None
2730 }
2731 };
2732
2733 if let Some(pair) = pair {
2734 trace!(
2735 "Controlled agent selected pair via inbound TCP nomination: {} -> {}",
2736 pair.local.address, pair.remote.address
2737 );
2738 inner
2740 .nomination_generation
2741 .fetch_add(1, core::sync::atomic::Ordering::SeqCst);
2742 *inner.selected_pair.lock() = Some(pair.clone());
2743 let _ = inner.selected_pair_notifier.send(Some(pair.clone()));
2744 publish_selected_socket(&inner, &pair, Some(sender));
2745 let _ = inner.set_state(IceTransportState::Connected);
2746 } else {
2747 debug!(
2748 "Inbound TCP nomination: synthesizing pair for {} -> {}",
2749 local_addr, addr
2750 );
2751 let local_cand = locals.iter().find(|c| {
2752 c.transport == "tcp"
2753 && c.tcp_type == Some(TcpType::Passive)
2754 && (c.base_address().port() == local_addr.port()
2755 || c.address.port() == local_addr.port())
2756 });
2757 let remote_cand = {
2758 let remotes = inner.remote_candidates.lock();
2759 remotes.iter().find(|c| c.address == addr).cloned()
2760 };
2761 if let (Some(l), Some(r)) = (local_cand, remote_cand) {
2762 let pair = IceCandidatePair::new(l.clone(), r.clone());
2763 *inner.selected_pair.lock() = Some(pair.clone());
2764 let _ = inner.selected_pair_notifier.send(Some(pair.clone()));
2765 publish_selected_socket(&inner, &pair, Some(sender));
2766 let _ = inner.set_state(IceTransportState::Connected);
2767 } else {
2768 let _ = inner.selected_socket.send(Some(sender.clone()));
2769 publish_selected_rtcp_socket(&inner, Some(sender.clone()));
2770 }
2771 }
2772 let _ = inner.nomination_complete.send(Some(true));
2773 let pair_summary = inner
2774 .selected_pair
2775 .lock()
2776 .as_ref()
2777 .map(|p| format!("{} -> {}", p.local.address, p.remote.address))
2778 .unwrap_or_else(|| format!("(no pair) peer={addr}"));
2779 debug!(
2780 peer = %addr,
2781 local_bind = %local_addr,
2782 pair = %pair_summary,
2783 socket = %sender.diag(),
2784 "ICE: passive TCP nomination complete"
2785 );
2786}
2787
2788fn resolve_rtcp_socket(inner: &IceTransportInner) -> Option<IceSocketWrapper> {
2789 let candidate = inner
2790 .gatherer
2791 .local_candidates()
2792 .into_iter()
2793 .find(|candidate| candidate.component == 2)?;
2794
2795 if candidate.typ == IceCandidateType::Relay {
2796 let clients = inner.gatherer.turn_clients.lock();
2797 clients
2798 .get(&candidate.address)
2799 .map(|client| IceSocketWrapper::Turn(client.clone(), candidate.address))
2800 } else if candidate.transport == "tcp" {
2801 inner.gatherer.get_tcp_socket(candidate.base_address())
2802 } else {
2803 if let Some(platform) = inner.gatherer.get_platform_socket(candidate.base_address()) {
2805 return Some(IceSocketWrapper::Platform(platform));
2806 }
2807 let socket = inner.gatherer.get_socket(candidate.base_address());
2808 if socket.is_none() {
2809 debug!(
2810 "resolve_rtcp_socket: failed to find socket for {}",
2811 candidate.base_address()
2812 );
2813 }
2814 socket.map(IceSocketWrapper::Udp)
2815 }
2816}
2817
2818fn publish_selected_rtcp_socket(inner: &IceTransportInner, fallback: Option<IceSocketWrapper>) {
2819 if let Some(socket) = resolve_rtcp_socket(inner).or(fallback) {
2820 let _ = inner.selected_rtcp_socket.send(Some(socket));
2821 }
2822}
2823
2824async fn bind_direct_rtcp_socket(
2825 inner: &IceTransportInner,
2826 rtp_base: SocketAddr,
2827 advertised_ip: IpAddr,
2828) -> RtcResult<(IceSocketWrapper, IceCandidate)> {
2829 let rtcp_bind_addr = rtp_base
2830 .port()
2831 .checked_add(1)
2832 .map(|port| SocketAddr::new(rtp_base.ip(), port));
2833 let rtcp = if let Some(addr) = rtcp_bind_addr {
2834 match inner.gatherer.bind_one(addr).await {
2835 Ok(socket) => socket,
2836 Err(err) => {
2837 debug!(
2838 "Failed to bind RTCP socket on {}, falling back to ephemeral port: {}",
2839 addr, err
2840 );
2841 inner
2842 .gatherer
2843 .bind_one(SocketAddr::new(rtp_base.ip(), 0))
2844 .await?
2845 }
2846 }
2847 } else {
2848 inner
2849 .gatherer
2850 .bind_one(SocketAddr::new(rtp_base.ip(), 0))
2851 .await?
2852 };
2853 let local_rtcp_addr = rtcp.local_addr()?;
2854 inner.gatherer.register_bound(&rtcp);
2855
2856 let mut rtcp_cand_addr = local_rtcp_addr;
2857 rtcp_cand_addr.set_ip(advertised_ip);
2858 let mut candidate = IceCandidate::host(rtcp_cand_addr, 2);
2859 if rtcp_cand_addr != local_rtcp_addr {
2860 candidate.related_address = Some(local_rtcp_addr);
2861 }
2862 Ok((rtcp, candidate))
2863}
2864
2865
2866async fn handle_packet(
2867 packet: &[u8],
2868 addr: SocketAddr,
2869 inner: Arc<IceTransportInner>,
2870 sender: IceSocketWrapper,
2871 marshal_buf: &mut Vec<u8>,
2872) { if should_drop_packet() {
2873 return;
2874 }
2875 inner.last_received_nanos.store(
2876 inner.created_at.elapsed().as_nanos() as u64,
2877 Ordering::Relaxed,
2878 );
2879 let b = packet[0];
2880 if b < 2 {
2881 match StunMessage::decode(packet) {
2883 Ok(msg) => {
2884 if msg.class == StunClass::Request {
2885 handle_stun_request(&sender, &msg, addr, inner).await;
2895 } else if msg.class == StunClass::SuccessResponse {
2896 let mut map = inner.pending_transactions.lock();
2897 if let Some(tx) = map.remove(&msg.transaction_id) {
2898 let _ = tx.send(msg);
2899 } else {
2900 trace!(
2901 "Unmatched transaction {:?} Pending transactions: {:?}",
2902 msg.transaction_id,
2903 map.keys()
2904 );
2905 }
2906 } else if msg.class == StunClass::ErrorResponse {
2907 trace!("Received STUN Error Response from {}", addr);
2908 debug!(
2909 "Received STUN Error Response from {}: {:?}",
2910 addr, msg.error_code
2911 );
2912 if let Some(code) = msg.error_code {
2913 if code == 401 {
2914 let remote_params = inner.remote_parameters.lock().clone();
2915 debug!(
2916 "STUN 401 received. Current remote params: {:?}",
2917 remote_params
2918 );
2919 }
2920 trace!("Error code: {}", code);
2921 }
2922 let mut map = inner.pending_transactions.lock();
2926 if let Some(tx) = map.remove(&msg.transaction_id) {
2927 let _ = tx.send(msg);
2928 }
2929 }
2930 }
2931 Err(e) => {
2932 debug!("Failed to decode STUN packet from {}: {}", addr, e);
2933 }
2934 }
2935 } else {
2936 let receiver = inner.data_receiver.lock().clone();
2938 if let Some(rx) = receiver {
2939 rx.receive(Bytes::copy_from_slice(packet), addr, marshal_buf)
2940 .await;
2941 } else {
2942 let mut buffer = inner.buffered_packets.lock();
2943 let stats = inner.buffer_stats.clone();
2944 let capacity = inner.config.rtp_buffer_capacity;
2945
2946 stats.packets_received.fetch_add(1, Ordering::Relaxed);
2947
2948 if buffer.len() >= capacity {
2949 match inner.config.buffer_drop_strategy {
2950 BufferDropStrategy::DropOldest => {
2951 buffer.pop_front();
2952 buffer.push_back((packet.to_vec(), addr));
2953 }
2954 BufferDropStrategy::DropNew => {
2955 let dropped = stats.packets_dropped.load(Ordering::Relaxed);
2959 if dropped == 0 || dropped.is_multiple_of(1000) {
2960 tracing::warn!(src = %addr, capacity, "RTP buffer full — dropping inbound packet (DropNew strategy)");
2961 }
2962 }
2963 }
2964 stats.packets_dropped.fetch_add(1, Ordering::Relaxed);
2965 } else {
2966 buffer.push_back((packet.to_vec(), addr));
2967 }
2968
2969 let current_size = buffer.len() as u32;
2971 stats.current_size.store(current_size, Ordering::Relaxed);
2972
2973 let mut peak = stats.peak_size.load(Ordering::Relaxed);
2975 while current_size > peak {
2976 match stats.peak_size.compare_exchange_weak(
2977 peak,
2978 current_size,
2979 Ordering::Relaxed,
2980 Ordering::Relaxed,
2981 ) {
2982 Ok(_) => break,
2983 Err(current) => peak = current,
2984 }
2985 }
2986
2987 let mut last_log = stats.last_log_time.lock();
2989 if last_log.elapsed() >= inner.config.buffer_stats_log_interval {
2990 let received = stats.packets_received.load(Ordering::Relaxed);
2991 let dropped = stats.packets_dropped.load(Ordering::Relaxed);
2992 let peak_size = stats.peak_size.load(Ordering::Relaxed);
2993 trace!(
2994 "Buffer stats: received={}, dropped={}, current={}, peak={}, capacity={}",
2995 received, dropped, current_size, peak_size, capacity
2996 );
2997 *last_log = Instant::now();
2998 }
2999 }
3000 }
3001}
3002
3003async fn verify_nominated_path(
3011 sender: &IceSocketWrapper,
3012 addr: SocketAddr,
3013 inner: Arc<IceTransportInner>,
3014) -> bool {
3015 let remote_params = inner.remote_parameters.lock().clone();
3016 let Some(rp) = remote_params else {
3017 return false;
3018 };
3019 let local_params = inner.local_parameters.lock().clone();
3020
3021 let tx_id = random_bytes::<12>();
3022 let mut msg = StunMessage::binding_request(tx_id, Some("rustrtc"));
3023 msg.attributes.push(StunAttribute::Username(format!(
3024 "{}:{}",
3025 rp.username_fragment, local_params.username_fragment
3026 )));
3027 let bytes = match msg.encode(Some(rp.password.as_bytes()), true) {
3028 Ok(b) => b,
3029 Err(_) => return false,
3030 };
3031
3032 let (tx, rx) = oneshot::channel();
3033 {
3034 let mut map = inner.pending_transactions.lock();
3035 map.insert(tx_id, tx);
3036 }
3037
3038 if let Err(e) = sender.send_to(&bytes, addr).await {
3039 inner.pending_transactions.lock().remove(&tx_id);
3040 debug!("Path verification send to {} failed: {}", addr, e);
3041 return false;
3042 }
3043
3044 let verified = with_timeout(inner.config.stun_timeout, rx)
3045 .await
3046 .map(|res| res.is_ok())
3047 .unwrap_or(false);
3048 if !verified {
3049 let mut map = inner.pending_transactions.lock();
3050 map.remove(&tx_id);
3051 }
3052 verified
3053}
3054
3055async fn handle_stun_request(
3056 sender: &IceSocketWrapper,
3057 msg: &StunDecoded,
3058 addr: SocketAddr,
3059 inner: Arc<IceTransportInner>,
3060) {
3061 let response = StunMessage::binding_success_response(msg.transaction_id, addr);
3062
3063 #[cfg(any(test, feature = "simulator"))]
3064 simulate_stun_respond_delay(sender).await;
3065
3066 let password = inner.local_parameters.lock().password.clone();
3067 if let Ok(bytes) = response.encode(Some(password.as_bytes()), true) {
3068 match sender.send_to(&bytes, addr).await {
3069 Ok(_) => trace!("Sent STUN Response to {}", addr),
3070 Err(e) => {
3071 debug!("Failed to send STUN Response to {}: {}", addr, e);
3074 }
3075 }
3076 } else {
3077 debug!("Failed to encode STUN Response");
3078 }
3079
3080 let mut known = false;
3082 {
3083 let remotes = inner.remote_candidates.lock();
3084 for cand in remotes.iter() {
3085 if cand.address == addr {
3086 known = true;
3087 break;
3088 }
3089 }
3090 }
3091
3092 if !known {
3093 debug!("Discovered peer reflexive candidate: {}", addr);
3094 let transport = match sender {
3095 IceSocketWrapper::Platform(_)
3096 | IceSocketWrapper::Udp(_)
3097 | IceSocketWrapper::SharedUdp(_) => "udp",
3098 #[cfg(feature = "std")]
3099 IceSocketWrapper::TcpListener(_) | IceSocketWrapper::TcpStream(_, _, _) => "tcp",
3100 IceSocketWrapper::Turn(_, _) => "udp",
3101 };
3102 let mut candidate = IceCandidate::host(addr, 1); candidate.typ = IceCandidateType::PeerReflexive;
3104 candidate.transport = transport.to_string();
3105 candidate.foundation = IceCandidate::compute_foundation(
3106 IceCandidateType::PeerReflexive,
3107 candidate.base_address(),
3108 transport,
3109 );
3110 candidate.priority = if transport == "tcp" {
3111 IceCandidate::priority_for_tcp(IceCandidateType::PeerReflexive, 1, TcpType::Passive)
3112 } else {
3113 IceCandidate::priority_for(IceCandidateType::PeerReflexive, 1)
3114 };
3115
3116 let mut list = inner.remote_candidates.lock();
3117 list.push(candidate);
3118 drop(list);
3119
3120 let _ = inner.cmd_tx.send(IceCommand::RunChecks);
3121 }
3122 if inner.config.enable_latching && inner.config.transport_mode != crate::TransportMode::WebRtc {
3130 let current_pair = inner.selected_pair.lock().clone();
3131 if let Some(pair) = current_pair
3132 && pair.remote.address.port() == addr.port()
3133 && pair.remote.address.ip() != addr.ip()
3134 {
3135 debug!(
3136 "RTP latching: updating remote address from {} to {}",
3137 pair.remote.address, addr
3138 );
3139 let mut new_remote = pair.remote.clone();
3140 new_remote.address = addr;
3141 let new_pair = IceCandidatePair::new(pair.local.clone(), new_remote);
3142 *inner.selected_pair.lock() = Some(new_pair.clone());
3143 let _ = inner.selected_pair_notifier.send(Some(new_pair.clone()));
3144 publish_selected_socket(&inner, &new_pair, Some(sender));
3145 }
3146 }
3147
3148 #[cfg(feature = "std")]
3149 complete_controlled_inbound_tcp_nomination(sender, addr, inner.clone()).await;
3150 #[cfg(not(feature = "std"))]
3151 {
3152 let _ = (sender, &addr, &inner);
3153 }
3154
3155 if msg.use_candidate {
3156 let role = *inner.role.lock();
3157 if role == IceRole::Controlled {
3158 #[cfg(feature = "std")]
3160 if matches!(sender, IceSocketWrapper::TcpStream(_, _, _)) {
3161 #[allow(unused_mut, unused_variables)]
3162 let sender = &sender;
3163 return;
3164 }
3165 let use_candidate_generation = inner
3170 .nomination_generation
3171 .fetch_add(1, core::sync::atomic::Ordering::SeqCst)
3172 + 1;
3173 let local_addr: SocketAddr = match sender {
3195 IceSocketWrapper::Platform(s) => s
3196 .local_addr()
3197 .unwrap_or_else(|_| "0.0.0.0:0".parse().unwrap()),
3198 IceSocketWrapper::Udp(s) => s
3199 .local_addr()
3200 .unwrap_or_else(|_| "0.0.0.0:0".parse().unwrap()),
3201 IceSocketWrapper::SharedUdp(h) => h
3202 .local_addr()
3203 .unwrap_or_else(|_| "0.0.0.0:0".parse().unwrap()),
3204 #[cfg(feature = "std")]
3205 IceSocketWrapper::TcpListener(l) => l
3206 .local_addr()
3207 .unwrap_or_else(|_| "0.0.0.0:0".parse().unwrap()),
3208 #[cfg(feature = "std")]
3209 IceSocketWrapper::TcpStream(read, _, _) => {
3210 let s = read.lock().await;
3211 s.local_addr()
3212 .unwrap_or_else(|_| "0.0.0.0:0".parse().unwrap())
3213 }
3214 IceSocketWrapper::Turn(_, addr) => *addr,
3215 };
3216
3217 let locals = inner.gatherer.local_candidates();
3218 let local_cand = locals.iter().find(|c| c.base_address() == local_addr);
3219
3220 let pair = {
3221 let remotes = inner.remote_candidates.lock();
3222 let remote_cand = remotes.iter().find(|c| c.address == addr);
3223 if let (Some(l), Some(r)) = (local_cand, remote_cand) {
3224 Some(IceCandidatePair::new(l.clone(), r.clone()))
3225 } else {
3226 None
3227 }
3228 };
3229
3230 if let Some(pair) = pair {
3231 let same_pair = {
3232 let selected = inner.selected_pair.lock();
3233 selected
3234 .as_ref()
3235 .map(|cur| {
3236 cur.local.address == pair.local.address
3237 && cur.remote.address == pair.remote.address
3238 })
3239 .unwrap_or(false)
3240 };
3241 let has_selected = inner.selected_pair.lock().is_some();
3242
3243 if same_pair {
3244 trace!(
3245 "Controlled agent keeping current pair (UseCandidate {} -> {})",
3246 pair.local.address, pair.remote.address
3247 );
3248 } else if !has_selected {
3249 debug!(
3252 label = inner.config.label.as_deref().unwrap_or("-"),
3253 "Controlled agent following UseCandidate (first nomination): {} -> {}",
3254 pair.local.address,
3255 pair.remote.address
3256 );
3257 *inner.selected_pair.lock() = Some(pair.clone());
3258 let _ = inner.selected_pair_notifier.send(Some(pair.clone()));
3259 publish_selected_socket(&inner, &pair, Some(sender));
3260 } else {
3261 debug!(
3270 label = inner.config.label.as_deref().unwrap_or("-"),
3271 "Controlled agent deferring switch to newly nominated path {} -> {} until verified",
3272 pair.local.address,
3273 pair.remote.address
3274 );
3275 let inner2 = inner.clone();
3276 let sender2 = sender.clone();
3277 let pair2 = pair.clone();
3278 crate::platform::task::spawn(async move {
3279 let verified = verify_nominated_path(&sender2, addr, inner2.clone()).await;
3280 if !verified {
3281 debug!(
3282 label = inner2.config.label.as_deref().unwrap_or("-"),
3283 "New nominated path {} -> {} failed verification; keeping current pair",
3284 pair2.local.address,
3285 pair2.remote.address
3286 );
3287 } else if commit_verified_nomination(
3288 &inner2,
3289 use_candidate_generation,
3290 &pair2,
3291 &sender2,
3292 ) {
3293 debug!(
3294 label = inner2.config.label.as_deref().unwrap_or("-"),
3295 "New nominated path verified, switching: {} -> {}",
3296 pair2.local.address,
3297 pair2.remote.address
3298 );
3299 } else {
3300 debug!(
3301 label = inner2.config.label.as_deref().unwrap_or("-"),
3302 "New nominated path {} -> {} verified but superseded by a newer nomination; keeping current pair",
3303 pair2.local.address,
3304 pair2.remote.address
3305 );
3306 }
3307 });
3308 }
3309 let _ = inner.set_state(IceTransportState::Connected);
3310 let _ = inner.nomination_complete.send(Some(true));
3311 } else {
3312 debug!(
3313 "Received UseCandidate but could not find UDP pair for {} -> {}",
3314 local_addr, addr
3315 );
3316 let _ = inner.nomination_complete.send(Some(true));
3317 }
3318 }
3319 }
3320}
3321
3322struct TransactionGuard<'a> {
3323 map: &'a crate::platform::sync::Mutex<BTreeMap<[u8; 12], oneshot::Sender<StunDecoded>>>,
3324 tx_id: [u8; 12],
3325}
3326
3327impl<'a> Drop for TransactionGuard<'a> {
3328 fn drop(&mut self) {
3329 let mut map = self.map.lock();
3331 map.remove(&self.tx_id);
3332 }
3333}
3334
3335async fn perform_binding_check(
3336 local: &IceCandidate,
3337 remote: &IceCandidate,
3338 inner: &Arc<IceTransportInner>,
3339 role: IceRole,
3340 nominated: bool,
3341) -> RtcResult<()> {
3342 #[cfg(feature = "std")]
3344 if local.transport == "tcp" && remote.transport == "tcp" {
3345 return perform_tcp_binding_check(local, remote, inner, role, nominated).await;
3346 }
3347 #[cfg(not(feature = "std"))]
3348 if local.transport == "tcp" && remote.transport == "tcp" {
3349 return Err(RtcError::Internal(
3350 "ICE-TCP is excluded from the embedded target".into(),
3351 ));
3352 }
3353
3354 if role == IceRole::Controlled && local.transport == "tcp" {
3356 return Ok(());
3357 }
3358
3359 if remote.transport != "udp" {
3361 return Err(RtcError::Internal(format!(
3362 "only UDP connectivity checks are supported"
3363 )));
3364 }
3365
3366 let local_params = inner.local_parameters.lock().clone();
3367 let remote_params = match inner.remote_parameters.lock().clone() {
3368 Some(p) => p,
3369 None => return Err(RtcError::Internal(format!("no remote params"))),
3370 };
3371
3372 let tx_id = random_bytes::<12>();
3373 let mut msg = StunMessage::binding_request(tx_id, Some("rustrtc"));
3376 let username = format!(
3377 "{}:{}",
3378 remote_params.username_fragment, local_params.username_fragment
3379 );
3380 msg.attributes.push(StunAttribute::Username(username));
3381 msg.attributes.push(StunAttribute::Priority(local.priority));
3382 match role {
3383 IceRole::Controlling => {
3384 msg.attributes
3385 .push(StunAttribute::IceControlling(local_params.tie_breaker));
3386 if nominated {
3387 msg.attributes.push(StunAttribute::UseCandidate);
3388 }
3389 }
3390 IceRole::Controlled => msg
3391 .attributes
3392 .push(StunAttribute::IceControlled(local_params.tie_breaker)),
3393 }
3394 let bytes = msg.encode(Some(remote_params.password.as_bytes()), true)?;
3395
3396 let (tx, mut rx) = oneshot::channel();
3397 {
3398 let mut map = inner.pending_transactions.lock();
3399 map.insert(tx_id, tx);
3400 }
3401
3402 let _guard = TransactionGuard {
3404 map: &inner.pending_transactions,
3405 tx_id,
3406 };
3407
3408 let (socket, platform_socket, turn_client) = if local.typ == IceCandidateType::Relay {
3409 let gatherer = &inner.gatherer;
3410 let clients = gatherer.turn_clients.lock();
3411 let client = clients.get(&local.address).cloned();
3412 (None, None, client)
3413 } else {
3414 let socket = inner.gatherer.get_socket(local.base_address());
3415 let platform_socket = inner.gatherer.get_platform_socket(local.base_address());
3416 (socket, platform_socket, None)
3417 };
3418
3419 if local.typ == IceCandidateType::Relay {
3420 let client = turn_client.as_ref().ok_or_else(|| {
3421 RtcError::Internal(format!("TURN client not found for relay candidate"))
3422 })?;
3423
3424 let (perm_bytes, perm_tx_id) = client.create_permission_packet(remote.address).await?;
3425
3426 let (perm_tx, perm_rx) = oneshot::channel();
3427 {
3428 let mut map = inner.pending_transactions.lock();
3429 map.insert(perm_tx_id, perm_tx);
3430 }
3431
3432 trace!("Sending CreatePermission to TURN server");
3433 if let Err(e) = client.send(&perm_bytes).await {
3434 debug!("CreatePermission send failed: {}", e);
3435 return Err(e);
3436 }
3437
3438 match with_timeout(inner.config.stun_timeout, perm_rx).await {
3439 Ok(Ok(msg)) => {
3440 if msg.class == StunClass::ErrorResponse {
3441 return Err(RtcError::Internal(format!(
3442 "CreatePermission failed: {:?}",
3443 msg.error_code
3444 )));
3445 }
3446
3447 if client.get_channel(remote.address).await.is_none()
3449 && let Ok((bind_bytes, bind_tx_id, channel_num)) =
3450 client.create_channel_bind_packet(remote.address).await
3451 {
3452 let (bind_tx, bind_rx) = oneshot::channel();
3453 {
3454 let mut map = inner.pending_transactions.lock();
3455 map.insert(bind_tx_id, bind_tx);
3456 }
3457
3458 if client.send(&bind_bytes).await.is_ok() {
3459 let client_clone = client.clone();
3460 let remote_addr = remote.address;
3461 let inner_weak = Arc::downgrade(inner);
3462 let timeout_dur = inner.config.stun_timeout;
3463
3464 match with_timeout(timeout_dur, bind_rx).await {
3465 Ok(Ok(msg)) => {
3466 if msg.class == StunClass::SuccessResponse {
3467 client_clone.add_channel(remote_addr, channel_num).await;
3468 }
3469 }
3470 _ => {
3471 if let Some(inner) = inner_weak.upgrade() {
3473 let mut map = inner.pending_transactions.lock();
3474 map.remove(&bind_tx_id);
3475 }
3476 }
3477 }
3478 }
3479 }
3480 }
3481 _ => {
3482 let mut map = inner.pending_transactions.lock();
3483 map.remove(&perm_tx_id);
3484 return Err(RtcError::Internal(format!("CreatePermission timeout")));
3485 }
3486 }
3487 } else if socket.is_none() && platform_socket.is_none() {
3488 return Err(RtcError::Internal(format!(
3489 "no socket found for local candidate"
3490 )));
3491 }
3492
3493 let start = Instant::now();
3494 let mut rto = Duration::from_millis(500);
3495 let max_timeout = if nominated {
3496 inner.config.nomination_timeout
3497 } else {
3498 inner.config.stun_timeout
3499 };
3500
3501 loop {
3502 if let Some(client) = &turn_client {
3503 let sent = if let Some(channel) = client.get_channel(remote.address).await {
3504 client.send_channel_data(channel, &bytes).await
3505 } else {
3506 client.send_indication(remote.address, &bytes).await
3507 };
3508
3509 if let Err(e) = sent {
3510 debug!("TURN send failed: {}", e);
3511 return Err(e);
3512 }
3513 } else if local.transport == "tcp" {
3514 let tcp_stream = match TcpStream::connect(remote.address).await {
3516 Ok(stream) => {
3517 stream.set_nodelay(true).ok();
3518 stream
3519 }
3520 Err(e) => {
3521 debug!("TCP connect to {} failed: {}", remote.address, e);
3522 return Err(e.into());
3523 }
3524 };
3525 #[cfg(feature = "std")]
3526 use tokio::io::{AsyncReadExt, AsyncWriteExt};
3527 let mut tcp_stream = tcp_stream;
3528 let mut framed = Vec::with_capacity(2 + bytes.len());
3529 let flen = bytes.len() as u16;
3530 framed.extend_from_slice(&flen.to_be_bytes());
3531 framed.extend_from_slice(&bytes);
3532 tcp_stream.write_all(&framed).await?;
3533 match with_timeout(inner.config.stun_timeout, async {
3535 let mut len_buf = [0u8; 2];
3536 tcp_stream.read_exact(&mut len_buf).await?;
3537 let resp_len = u16::from_be_bytes(len_buf) as usize;
3538 let mut resp_buf = vec![0u8; resp_len];
3539 tcp_stream.read_exact(&mut resp_buf).await?;
3540 StunMessage::decode(&resp_buf)
3541 .map_err(|e| RtcError::Internal(format!("stun decode: {e}")))
3542 })
3543 .await
3544 {
3545 Ok(Ok(parsed)) => {
3546 if parsed.class == StunClass::SuccessResponse {
3547 return Ok(());
3548 }
3549 return Err(RtcError::Internal(format!(
3550 "TCP binding check failed: unexpected response"
3551 )));
3552 }
3553 Ok(Err(e)) => return Err(e),
3554 Err(_) => return Err(RtcError::Internal(format!("TCP binding check timeout"))),
3555 }
3556 } else if let Some(platform_socket) = &platform_socket {
3557 if let Err(e) = platform_socket.send_to(&bytes, remote.address).await {
3561 debug!(
3562 "platform socket send_to {} failed (transient): {}",
3563 remote.address, e
3564 );
3565 }
3566 } else if let Some(socket) = &socket
3567 && let Err(e) = socket.send_to(&bytes, remote.address).await
3568 {
3569 let is_fatal = {
3572 #[cfg(feature = "std")]
3573 {
3574 matches!(
3575 e.kind(),
3576 std::io::ErrorKind::BrokenPipe
3577 | std::io::ErrorKind::ConnectionReset
3578 | std::io::ErrorKind::NotConnected
3579 )
3580 }
3581 #[cfg(not(feature = "std"))]
3582 {
3583 false
3584 }
3585 };
3586 if is_fatal {
3587 debug!(
3588 "socket.send_to {} fatal error, aborting nomination: {}",
3589 remote.address, e
3590 );
3591 return Err(e.into());
3592 }
3593 }
3596
3597 let timeout_fut = crate::platform::task::sleep(max_timeout.saturating_sub(start.elapsed()));
3598 let rto_fut = crate::platform::task::sleep(rto);
3599
3600 let mut timeout_fut = core::pin::pin!(timeout_fut);
3601 let mut rto_fut = core::pin::pin!(rto_fut);
3602 match crate::platform::select::select3(&mut rx, &mut timeout_fut, &mut rto_fut).await {
3603 crate::platform::select::Which3::A(res) => {
3604 let parsed = match res {
3605 Ok(msg) => msg,
3606 Err(_) => return Err(RtcError::Internal(format!("channel closed"))),
3607 };
3608
3609 if parsed.transaction_id != tx_id {
3610 return Err(RtcError::Internal(format!(
3611 "binding response transaction mismatch"
3612 )));
3613 }
3614 if parsed.method != StunMethod::Binding {
3615 return Err(RtcError::Internal(format!(
3616 "unexpected STUN method in binding response"
3617 )));
3618 }
3619 if parsed.class != StunClass::SuccessResponse {
3620 return Err(RtcError::Internal(format!("binding request failed")));
3621 }
3622 return Ok(());
3623 }
3624 crate::platform::select::Which3::B(_) => {
3625 return Err(RtcError::Internal(format!("timeout")));
3626 }
3627 crate::platform::select::Which3::C(_) => {
3628 if start.elapsed() >= max_timeout {
3629 continue;
3630 }
3631 trace!(
3632 "Retransmitting STUN Request to {} tx={:?}",
3633 remote.address, tx_id
3634 );
3635 rto = core::cmp::min(rto * 2, Duration::from_millis(1600));
3636 }
3637 }
3638 }
3639}
3640
3641#[cfg(feature = "std")]
3651fn frame_stun_for_tcp(data: &[u8]) -> Vec<u8> {
3652 let len = data.len() as u16;
3653 let mut framed = Vec::with_capacity(2 + data.len());
3654 framed.extend_from_slice(&len.to_be_bytes());
3655 framed.extend_from_slice(data);
3656 framed
3657}
3658
3659#[cfg(feature = "std")]
3660type TcpReadHalf = tokio::net::tcp::OwnedReadHalf;
3661#[cfg(feature = "std")]
3662type TcpWriteHalf = tokio::net::tcp::OwnedWriteHalf;
3663
3664#[cfg(feature = "std")]
3665fn split_tcp_stream(stream: TcpStream, peer: SocketAddr) -> IceSocketWrapper {
3666 if let Err(e) = stream.set_nodelay(true) {
3667 debug!("TCP set_nodelay failed: {}", e);
3668 }
3669 let (read, write) = stream.into_split();
3670 #[cfg(feature = "std")]
3671 IceSocketWrapper::TcpStream(
3672 Arc::new(Mutex::new(read)),
3673 Arc::new(Mutex::new(write)),
3674 peer,
3675 )
3676}
3677
3678#[cfg(feature = "std")]
3679pub(crate) async fn attach_demuxed_tcp_stream(
3680 inner: Arc<IceTransportInner>,
3681 stream: TcpStream,
3682 peer_addr: SocketAddr,
3683 listen_addr: SocketAddr,
3684 first_packet: Vec<u8>,
3685) {
3686 let wrapper = split_tcp_stream(stream, peer_addr);
3687 inner
3688 .gatherer
3689 .store_tcp_stream(listen_addr, wrapper.clone());
3690 let _ = inner.gatherer.socket_tx.send(wrapper.clone());
3691 let mut marshal_buf = Vec::new();
3692 handle_packet(&first_packet, peer_addr, inner, wrapper, &mut marshal_buf).await;
3693}
3694
3695#[cfg(feature = "std")]
3696pub(crate) async fn tcp_write_all(write: &Arc<Mutex<TcpWriteHalf>>, data: &[u8]) -> RtcResult<()> {
3697 let mut offset = 0;
3698 while offset < data.len() {
3699 let guard = write.lock().await;
3700 loop {
3701 match guard.try_write(&data[offset..]) {
3702 Ok(0) => guard.writable().await?,
3703 Ok(n) => {
3704 offset += n;
3705 break;
3706 }
3707 Err(e) if e.kind() == ErrorKind::WouldBlock => guard.writable().await?,
3708 Err(e) => return Err(RtcError::Internal(format!("TCP write failed: {}", e))),
3709 }
3710 }
3711 }
3712 Ok(())
3713}
3714
3715#[cfg(feature = "std")]
3716async fn perform_tcp_binding_check(
3717 local: &IceCandidate,
3718 remote: &IceCandidate,
3719 inner: &Arc<IceTransportInner>,
3720 role: IceRole,
3721 nominated: bool,
3722) -> RtcResult<()> {
3723 debug!(
3724 "perform_tcp_binding_check: {} -> {}",
3725 local.address, remote.address
3726 );
3727 let local_params = inner.local_parameters.lock().clone();
3728 let remote_params = match inner.remote_parameters.lock().clone() {
3729 Some(p) => p,
3730 None => return Err(RtcError::Internal(format!("no remote params"))),
3731 };
3732
3733 let tx_id = random_bytes::<12>();
3734 let mut msg = StunMessage::binding_request(tx_id, Some("rustrtc"));
3735 let username = format!(
3736 "{}:{}",
3737 remote_params.username_fragment, local_params.username_fragment
3738 );
3739 msg.attributes.push(StunAttribute::Username(username));
3740 msg.attributes.push(StunAttribute::Priority(local.priority));
3741 match role {
3742 IceRole::Controlling => {
3743 msg.attributes
3744 .push(StunAttribute::IceControlling(local_params.tie_breaker));
3745 if nominated {
3746 msg.attributes.push(StunAttribute::UseCandidate);
3747 }
3748 }
3749 IceRole::Controlled => msg
3750 .attributes
3751 .push(StunAttribute::IceControlled(local_params.tie_breaker)),
3752 }
3753 let bytes = msg.encode(Some(remote_params.password.as_bytes()), true)?;
3754
3755 let connect_timeout = inner.config.stun_timeout;
3757 let stream = with_timeout(connect_timeout, TcpStream::connect(remote.address))
3758 .await
3759 .map_err(|_| RtcError::Internal(format!("TCP connect timeout to {}", remote.address)))?
3760 .map_err(|e| {
3761 RtcError::Internal(format!("TCP connect to {} failed: {}", remote.address, e))
3762 })?;
3763
3764 let local_addr = stream.local_addr()?;
3765 let wrapper = split_tcp_stream(stream, remote.address);
3766 let write = match &wrapper {
3767 #[cfg(feature = "std")]
3768 IceSocketWrapper::TcpStream(_, write, _) => write.clone(),
3769 _ => return Err(RtcError::Internal(format!("split_tcp_stream invariant"))),
3770 };
3771
3772 inner.gatherer.store_tcp_stream(local_addr, wrapper.clone());
3774 let _ = inner.gatherer.socket_tx.send(wrapper);
3775
3776 let (tx, mut rx) = oneshot::channel();
3778 {
3779 let mut map = inner.pending_transactions.lock();
3780 map.insert(tx_id, tx);
3781 }
3782 let _guard = TransactionGuard {
3783 map: &inner.pending_transactions,
3784 tx_id,
3785 };
3786
3787 {
3789 let framed = frame_stun_for_tcp(&bytes);
3790 #[cfg(feature = "std")]
3791 tcp_write_all(&write, &framed).await?;
3792 }
3793
3794 let start = Instant::now();
3796 let mut rto = Duration::from_millis(500);
3797 let max_timeout = if nominated {
3798 inner.config.nomination_timeout
3799 } else {
3800 inner.config.stun_timeout
3801 };
3802
3803 loop {
3804 let timeout_fut = crate::platform::task::sleep(max_timeout.saturating_sub(start.elapsed()));
3805 let rto_fut = crate::platform::task::sleep(rto);
3806
3807 let mut timeout_fut = core::pin::pin!(timeout_fut);
3808 let mut rto_fut = core::pin::pin!(rto_fut);
3809 match crate::platform::select::select3(&mut rx, &mut timeout_fut, &mut rto_fut).await {
3810 crate::platform::select::Which3::A(res) => {
3811 let parsed = match res {
3812 Ok(msg) => msg,
3813 Err(_) => return Err(RtcError::Internal(format!("channel closed"))),
3814 };
3815 if parsed.transaction_id != tx_id {
3816 return Err(RtcError::Internal(format!(
3817 "binding response transaction mismatch"
3818 )));
3819 }
3820 if parsed.method != StunMethod::Binding {
3821 return Err(RtcError::Internal(format!(
3822 "unexpected STUN method in binding response"
3823 )));
3824 }
3825 if parsed.class != StunClass::SuccessResponse {
3826 return Err(RtcError::Internal(format!("binding request failed")));
3827 }
3828 return Ok(());
3829 }
3830 crate::platform::select::Which3::B(_) => {
3831 return Err(RtcError::Internal(format!("timeout")));
3832 }
3833 crate::platform::select::Which3::C(_) => {
3834 if start.elapsed() >= max_timeout {
3835 continue;
3836 }
3837 trace!(
3838 "TCP Retransmitting STUN Request to {} tx={:?}",
3839 remote.address, tx_id
3840 );
3841 rto = core::cmp::min(rto * 2, Duration::from_millis(1600));
3842 let framed = frame_stun_for_tcp(&bytes);
3843 #[cfg(feature = "std")]
3844 let _ = tcp_write_all(&write, &framed).await;
3845 }
3846 }
3847 }
3848}
3849
3850fn store_ice_state(state: &watch::Sender<IceTransportState>, new: IceTransportState) {
3858 if *state.borrow() != new {
3859 let _ = state.send(new);
3860 }
3861}
3862
3863impl IceTransportInner {
3864 fn set_state(&self, new: IceTransportState) {
3865 store_ice_state(&self.state, new);
3866 }
3867}
3868
3869#[cfg(all(test, feature = "std"))]
3870mod state_tests {
3871 use super::{IceTransportState, store_ice_state};
3872 use tokio::sync::watch;
3873
3874 #[test]
3876 fn store_ice_state_dedupes_equal_values() {
3877 let (tx, mut rx) = watch::channel(IceTransportState::Checking);
3878 store_ice_state(&tx, IceTransportState::Connected);
3879 assert!(rx.has_changed().unwrap());
3880 let _ = rx.borrow_and_update();
3881 store_ice_state(&tx, IceTransportState::Connected);
3882 assert!(
3883 !rx.has_changed().unwrap(),
3884 "re-sending an equal state must not notify (ICE recovered spam)"
3885 );
3886 store_ice_state(&tx, IceTransportState::Disconnected);
3887 assert!(rx.has_changed().unwrap());
3888 }
3889}
3890
3891#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3892pub enum IceTransportState {
3893 New,
3894 Checking,
3895 Connected,
3896 Completed,
3897 Failed,
3898 Disconnected,
3899 Closed,
3900}
3901
3902#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3903pub enum IceGathererState {
3904 New,
3905 Gathering,
3906 Complete,
3907}
3908
3909#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3910pub enum IceRole {
3911 Controlling,
3912 Controlled,
3913}
3914
3915#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3917pub enum TcpType {
3918 Active,
3919 Passive,
3920 So,
3921}
3922
3923impl TcpType {
3924 fn as_str(&self) -> &'static str {
3925 match self {
3926 TcpType::Active => "active",
3927 TcpType::Passive => "passive",
3928 TcpType::So => "so",
3929 }
3930 }
3931
3932 fn from_str(s: &str) -> Option<Self> {
3933 match s {
3934 "active" => Some(TcpType::Active),
3935 "passive" => Some(TcpType::Passive),
3936 "so" => Some(TcpType::So),
3937 _ => None,
3938 }
3939 }
3940}
3941
3942#[derive(Debug, Clone, PartialEq, Eq)]
3943pub struct IceCandidate {
3944 pub foundation: String,
3945 pub priority: u32,
3946 pub address: SocketAddr,
3947 pub typ: IceCandidateType,
3948 pub transport: String,
3949 pub tcp_type: Option<TcpType>,
3950 pub related_address: Option<SocketAddr>,
3951 pub component: u16,
3952 pub hostname: Option<String>,
3957}
3958
3959impl IceCandidate {
3960 fn compute_foundation(typ: IceCandidateType, base_addr: SocketAddr, transport: &str) -> String {
3961 fn fnv1a(parts: &[&[u8]]) -> u64 {
3965 let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
3966 for part in parts {
3967 for b in *part {
3968 hash ^= u64::from(*b);
3969 hash = hash.wrapping_mul(0x0000_0100_0000_01B3);
3970 }
3971 hash ^= 0xff; hash = hash.wrapping_mul(0x0000_0100_0000_01B3);
3973 }
3974 hash
3975 }
3976 let typ_label = alloc::format!("{typ:?}");
3977 let ip_label = base_addr.ip().to_string();
3978 format!(
3979 "{:x}",
3980 fnv1a(&[
3981 typ_label.as_bytes(),
3982 ip_label.as_bytes(),
3983 transport.as_bytes(),
3984 ])
3985 )
3986 }
3987
3988 pub fn with_tcp_type(mut self, tcp_type: TcpType) -> Self {
3990 self.tcp_type = Some(tcp_type);
3991 self.transport = "tcp".into();
3992 self
3993 }
3994
3995 pub fn host(address: SocketAddr, component: u16) -> Self {
3996 Self {
3997 foundation: Self::compute_foundation(IceCandidateType::Host, address, "udp"),
3998 priority: IceCandidate::priority_for(IceCandidateType::Host, component),
3999 address,
4000 typ: IceCandidateType::Host,
4001 transport: "udp".into(),
4002 tcp_type: None,
4003 related_address: None,
4004 component,
4005 hostname: None,
4006 }
4007 }
4008
4009 pub fn host_tcp(address: SocketAddr, component: u16, tcp_type: TcpType) -> Self {
4010 Self {
4011 foundation: Self::compute_foundation(IceCandidateType::Host, address, "tcp"),
4012 priority: IceCandidate::priority_for_tcp(IceCandidateType::Host, component, tcp_type),
4013 address,
4014 typ: IceCandidateType::Host,
4015 transport: "tcp".into(),
4016 tcp_type: Some(tcp_type),
4017 related_address: None,
4018 component,
4019 hostname: None,
4020 }
4021 }
4022
4023 pub fn tcp(address: SocketAddr, component: u16, tcptype_str: &str) -> Self {
4024 let transport = "tcp";
4025 let tcp_type = TcpType::from_str(tcptype_str).unwrap_or(TcpType::Passive);
4026 Self {
4027 foundation: Self::compute_foundation(IceCandidateType::Host, address, transport),
4028 priority: IceCandidate::priority_for_tcp(IceCandidateType::Host, component, tcp_type),
4029 address,
4030 typ: IceCandidateType::Host,
4031 transport: transport.into(),
4032 tcp_type: Some(tcp_type),
4033 related_address: None,
4034 component,
4035 hostname: None,
4036 }
4037 }
4038
4039 pub fn with_hostname(mut self, hostname: impl Into<String>) -> Self {
4042 self.hostname = Some(hostname.into());
4043 self
4044 }
4045
4046 pub fn base_address(&self) -> SocketAddr {
4047 if self.typ == IceCandidateType::ServerReflexive || self.typ == IceCandidateType::Host {
4048 self.related_address.unwrap_or(self.address)
4049 } else {
4050 self.address
4051 }
4052 }
4053
4054 fn server_reflexive(base: SocketAddr, mapped: SocketAddr, component: u16) -> Self {
4055 Self {
4056 foundation: Self::compute_foundation(IceCandidateType::ServerReflexive, base, "udp"),
4057 priority: IceCandidate::priority_for(IceCandidateType::ServerReflexive, component),
4058 address: mapped,
4059 typ: IceCandidateType::ServerReflexive,
4060 transport: "udp".into(),
4061 tcp_type: None,
4062 related_address: Some(base),
4063 component,
4064 hostname: None,
4065 }
4066 }
4067
4068 fn relay(mapped: SocketAddr, component: u16, transport: &str) -> Self {
4069 Self {
4070 foundation: Self::compute_foundation(IceCandidateType::Relay, mapped, transport),
4071 priority: IceCandidate::priority_for(IceCandidateType::Relay, component),
4072 address: mapped,
4073 typ: IceCandidateType::Relay,
4074 transport: transport.into(),
4075 tcp_type: None,
4076 related_address: None,
4077 component,
4078 hostname: None,
4079 }
4080 }
4081
4082 fn priority_for(typ: IceCandidateType, component: u16) -> u32 {
4083 let type_pref = match typ {
4084 IceCandidateType::Host => 126u32,
4085 IceCandidateType::PeerReflexive => 110u32,
4086 IceCandidateType::ServerReflexive => 100u32,
4087 IceCandidateType::Relay => 0u32,
4088 };
4089 let local_pref = 65_535u32;
4090 let component = component.min(256) as u32;
4091 (type_pref << 24) | (local_pref << 8) | (256 - component)
4092 }
4093
4094 fn priority_for_tcp(typ: IceCandidateType, component: u16, tcp_type: TcpType) -> u32 {
4099 let type_pref = match typ {
4100 IceCandidateType::Host => 126u32,
4101 IceCandidateType::PeerReflexive => 110u32,
4102 IceCandidateType::ServerReflexive => 100u32,
4103 IceCandidateType::Relay => 0u32,
4104 };
4105 let local_pref = match tcp_type {
4107 TcpType::Passive => 65535u32,
4108 TcpType::Active => 65534u32,
4109 TcpType::So => 65533u32,
4110 };
4111 let component = component.min(256) as u32;
4112 (type_pref << 24) | (local_pref << 8) | (256 - component)
4113 }
4114
4115 pub fn to_sdp(&self) -> String {
4116 let advertised_ip = match &self.hostname {
4117 Some(h) => h.clone(),
4118 None => self.address.ip().to_string(),
4119 };
4120 let mut parts = vec![
4121 self.foundation.clone(),
4122 self.component.to_string(),
4123 self.transport.to_ascii_lowercase(),
4124 self.priority.to_string(),
4125 advertised_ip,
4126 self.address.port().to_string(),
4127 "typ".into(),
4128 self.typ.as_str().into(),
4129 ];
4130 if let Some(tcp_type) = self.tcp_type {
4131 parts.push("tcptype".into());
4132 parts.push(tcp_type.as_str().into());
4133 }
4134 if let Some(addr) = self.related_address
4135 && self.typ != IceCandidateType::Host
4136 {
4137 parts.push("raddr".into());
4138 parts.push(addr.ip().to_string());
4139 parts.push("rport".into());
4140 parts.push(addr.port().to_string());
4141 }
4142 parts.join(" ")
4143 }
4144
4145 pub fn from_sdp(sdp: &str) -> RtcResult<Self> {
4146 let parts: Vec<&str> = sdp.split_whitespace().collect();
4147 if parts.len() < 8 {
4148 return Err(RtcError::Internal(format!("invalid candidate")));
4149 }
4150 let start_idx = 0;
4152
4153 let foundation = parts[start_idx]
4154 .trim_start_matches("candidate:")
4155 .to_string();
4156 let component = parts[start_idx + 1].parse::<u16>()?;
4157 let transport = parts[start_idx + 2].to_ascii_lowercase();
4158 let priority = parts[start_idx + 3].parse::<u32>()?;
4159 let ip_str = parts[start_idx + 4];
4160 let port = parts[start_idx + 5].parse::<u16>()?;
4161 let typ_str = parts[start_idx + 7];
4162
4163 let address = if ip_str.contains(':') {
4165 format!("[{}]:{}", ip_str, port).parse()?
4166 } else {
4167 format!("{}:{}", ip_str, port).parse()?
4168 };
4169
4170 let typ = match typ_str {
4171 "host" => IceCandidateType::Host,
4172 "srflx" => IceCandidateType::ServerReflexive,
4173 "prflx" => IceCandidateType::PeerReflexive,
4174 "relay" => IceCandidateType::Relay,
4175 _ => return Err(RtcError::Internal(format!("unknown type"))),
4176 };
4177
4178 let tcp_type = if transport == "tcp" {
4180 let mut i = 8;
4182 loop {
4183 if i + 1 >= parts.len() {
4184 break None;
4185 }
4186 match parts[i] {
4187 "tcptype" => {
4188 break TcpType::from_str(parts[i + 1]);
4189 }
4190 _ => {
4191 i += 2;
4192 }
4193 }
4194 }
4195 } else {
4196 None
4197 };
4198
4199 Ok(Self {
4200 foundation,
4201 priority,
4202 address,
4203 typ,
4204 transport,
4205 tcp_type,
4206 related_address: None,
4207 component,
4208 hostname: None,
4209 })
4210 }
4211}
4212
4213#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4214pub enum IceCandidateType {
4215 Host,
4216 ServerReflexive,
4217 PeerReflexive,
4218 Relay,
4219}
4220
4221impl IceCandidateType {
4222 fn as_str(&self) -> &'static str {
4223 match self {
4224 IceCandidateType::Host => "host",
4225 IceCandidateType::ServerReflexive => "srflx",
4226 IceCandidateType::PeerReflexive => "prflx",
4227 IceCandidateType::Relay => "relay",
4228 }
4229 }
4230}
4231
4232#[derive(Debug, Clone, PartialEq, Eq)]
4233pub struct IceCandidatePair {
4234 pub local: IceCandidate,
4235 pub remote: IceCandidate,
4236 pub nominated: bool,
4237}
4238
4239impl IceCandidatePair {
4240 pub fn new(local: IceCandidate, remote: IceCandidate) -> Self {
4241 Self {
4242 local,
4243 remote,
4244 nominated: false,
4245 }
4246 }
4247
4248 pub fn priority(&self, role: IceRole) -> u64 {
4249 let g = self.local.priority as u64;
4250 let d = self.remote.priority as u64;
4251 let (g, d) = match role {
4252 IceRole::Controlling => (g, d),
4253 IceRole::Controlled => (d, g),
4254 };
4255 (1u64 << 32) * core::cmp::min(g, d) + 2 * core::cmp::max(g, d) + if g > d { 1 } else { 0 }
4256 }
4257}
4258
4259#[derive(Debug, Clone)]
4260pub struct IceParameters {
4261 pub username_fragment: String,
4262 pub password: String,
4263 pub ice_lite: bool,
4264 pub tie_breaker: u64,
4265}
4266
4267impl IceParameters {
4268 pub fn new(username_fragment: impl Into<String>, password: impl Into<String>) -> Self {
4269 Self {
4270 username_fragment: username_fragment.into(),
4271 password: password.into(),
4272 ice_lite: false,
4273 tie_breaker: random_u64(),
4274 }
4275 }
4276
4277 fn generate() -> Self {
4278 let ufrag = hex_encode(&random_bytes::<8>());
4279 let pwd = hex_encode(&random_bytes::<16>());
4280 Self {
4281 username_fragment: ufrag,
4282 password: pwd,
4283 ice_lite: false,
4284 tie_breaker: random_u64(),
4285 }
4286 }
4287}
4288
4289#[derive(Debug, Clone)]
4290pub struct IceTransportBuilder {
4291 config: RtcConfiguration,
4292 role: IceRole,
4293 servers: Vec<IceServer>,
4294}
4295
4296impl IceTransportBuilder {
4297 pub fn new(config: RtcConfiguration) -> Self {
4298 Self {
4299 config,
4300 role: IceRole::Controlled,
4301 servers: Vec::new(),
4302 }
4303 }
4304
4305 pub fn role(mut self, role: IceRole) -> Self {
4306 self.role = role;
4307 self
4308 }
4309
4310 pub fn server(mut self, server: IceServer) -> Self {
4311 self.servers.push(server);
4312 self
4313 }
4314
4315 pub fn build(self) -> (IceTransport, impl core::future::Future<Output = ()> + Send) {
4316 let mut config = self.config.clone();
4317 config.ice_servers.extend(self.servers);
4318 let (transport, runner) = IceTransport::new(config);
4319 transport.set_role(self.role);
4320 if let Err(err) = transport.start_gathering() {
4321 debug!("ICE gather failed: {}", err);
4322 }
4323 (transport, runner)
4324 }
4325}
4326
4327#[derive(Debug, Clone)]
4328struct IceGatherer {
4329 state: Arc<crate::platform::sync::Mutex<IceGathererState>>,
4330 local_candidates: Arc<crate::platform::sync::Mutex<Vec<IceCandidate>>>,
4331 sockets: Arc<crate::platform::sync::Mutex<Vec<Arc<UdpSocket>>>>,
4332 platform_sockets: Arc<
4337 crate::platform::sync::Mutex<Vec<Arc<dyn crate::platform::net::UdpSocket>>>,
4338 >,
4339 #[cfg_attr(not(feature = "std"), allow(dead_code))]
4340 tcp_listeners: Arc<crate::platform::sync::Mutex<Vec<Arc<TcpListener>>>>,
4341 tcp_streams: Arc<crate::platform::sync::Mutex<BTreeMap<SocketAddr, IceSocketWrapper>>>,
4342 #[cfg(feature = "std")]
4343 shared_tcp_regs: Arc<crate::platform::sync::Mutex<Vec<shared_tcp::SharedTcpRegistration>>>,
4344 #[cfg(not(feature = "std"))]
4345 shared_tcp_regs: Arc<crate::platform::sync::Mutex<Vec<SharedTcpRegistration>>>,
4346 shared_udp_regs: Arc<crate::platform::sync::Mutex<Vec<shared_udp::SharedUdpRegistration>>>,
4347 shared_udp_socket: Arc<crate::platform::sync::Mutex<Option<IceSocketWrapper>>>,
4350 transport_inner:
4351 Arc<crate::platform::sync::Mutex<Option<alloc::sync::Weak<IceTransportInner>>>>,
4352 turn_clients: Arc<crate::platform::sync::Mutex<BTreeMap<SocketAddr, Arc<TurnClient>>>>,
4353 upnp_mappers: Arc<crate::platform::sync::Mutex<Vec<UpnpPortMapper>>>,
4354 config: RtcConfiguration,
4355 candidate_tx: broadcast::Sender<IceCandidate>,
4356 socket_tx: crate::platform::sync::mpsc::UnboundedSender<IceSocketWrapper>,
4357}
4358
4359impl IceGatherer {
4360 fn new(
4361 config: RtcConfiguration,
4362 candidate_tx: broadcast::Sender<IceCandidate>,
4363 socket_tx: crate::platform::sync::mpsc::UnboundedSender<IceSocketWrapper>,
4364 ) -> Self {
4365 Self {
4366 state: Arc::new(crate::platform::sync::Mutex::new(IceGathererState::New)),
4367 local_candidates: Arc::new(crate::platform::sync::Mutex::new(Vec::new())),
4368 sockets: Arc::new(crate::platform::sync::Mutex::new(Vec::new())),
4369 platform_sockets: Arc::new(crate::platform::sync::Mutex::new(Vec::new())),
4370 tcp_listeners: Arc::new(crate::platform::sync::Mutex::new(Vec::new())),
4371 tcp_streams: Arc::new(crate::platform::sync::Mutex::new(BTreeMap::new())),
4372 shared_tcp_regs: Arc::new(crate::platform::sync::Mutex::new(Vec::new())),
4373 shared_udp_regs: Arc::new(crate::platform::sync::Mutex::new(Vec::new())),
4374 shared_udp_socket: Arc::new(crate::platform::sync::Mutex::new(None)),
4375 transport_inner: Arc::new(crate::platform::sync::Mutex::new(None)),
4376 turn_clients: Arc::new(crate::platform::sync::Mutex::new(BTreeMap::new())),
4377 upnp_mappers: Arc::new(crate::platform::sync::Mutex::new(Vec::new())),
4378 config,
4379 candidate_tx,
4380 socket_tx,
4381 }
4382 }
4383
4384 fn set_transport(&self, inner: alloc::sync::Weak<IceTransportInner>) {
4385 *self.transport_inner.lock() = Some(inner);
4386 }
4387
4388 fn external_srflx_ip(&self, bind_ip: IpAddr) -> Option<IpAddr> {
4391 if self.config.external_ip_candidate_type
4392 != crate::config::ExternalIpCandidateType::ServerReflexive
4393 || self.config.transport_mode != crate::config::TransportMode::WebRtc
4394 || self.config.ice_transport_policy != IceTransportPolicy::All
4395 || bind_ip.is_loopback()
4396 {
4397 return None;
4398 }
4399 self.config.external_ip.as_ref()?.parse().ok()
4400 }
4401
4402 fn push_host_with_external_srflx(
4406 &self,
4407 local_addr: SocketAddr,
4408 bind_ip: IpAddr,
4409 tcp_type: Option<TcpType>,
4410 ) -> bool {
4411 let Some(external) = self.external_srflx_ip(bind_ip) else {
4412 return false;
4413 };
4414 let mut host_addr = local_addr;
4415 if bind_ip.is_unspecified()
4416 && let Ok(local_ip) = get_local_ip()
4417 {
4418 host_addr.set_ip(local_ip);
4419 }
4420 let mut host = match tcp_type {
4421 Some(tcp_type) => IceCandidate::host_tcp(host_addr, 1, tcp_type),
4422 None => IceCandidate::host(host_addr, 1),
4423 };
4424 if host_addr != local_addr {
4425 host.related_address = Some(local_addr);
4426 }
4427 let mut srflx = IceCandidate::server_reflexive(
4429 local_addr,
4430 SocketAddr::new(external, local_addr.port()),
4431 1,
4432 );
4433 if let Some(tcp_type) = tcp_type {
4434 srflx = srflx.with_tcp_type(tcp_type);
4435 srflx.foundation = IceCandidate::compute_foundation(
4436 IceCandidateType::ServerReflexive,
4437 local_addr,
4438 "tcp",
4439 );
4440 srflx.priority =
4441 IceCandidate::priority_for_tcp(IceCandidateType::ServerReflexive, 1, tcp_type);
4442 }
4443 self.push_candidate(host);
4444 if external.is_ipv4() == local_addr.is_ipv4() {
4445 self.push_candidate(srflx);
4446 }
4447 true
4448 }
4449
4450 fn push_tcp_passive_candidate(&self, local_addr: SocketAddr, bind_ip: IpAddr) {
4451 if self.push_host_with_external_srflx(local_addr, bind_ip, Some(TcpType::Passive)) {
4452 return;
4453 }
4454 if let Some(ext_ip) = &self.config.external_ip
4455 && let Ok(parsed_ip) = ext_ip.parse::<IpAddr>()
4456 {
4457 if !bind_ip.is_loopback() {
4458 let mut ext_addr = local_addr;
4459 ext_addr.set_ip(parsed_ip);
4460 let mut cand = IceCandidate::tcp(ext_addr, 1, "passive");
4461 cand.related_address = Some(local_addr);
4462 self.push_candidate(cand);
4463 } else {
4464 self.push_candidate(IceCandidate::tcp(local_addr, 1, "passive"));
4465 }
4466 } else if bind_ip.is_unspecified() {
4467 let mut cand_addr = local_addr;
4468 if let Ok(local_ip) = get_local_ip() {
4469 cand_addr.set_ip(local_ip);
4470 }
4471 let mut cand = IceCandidate::tcp(cand_addr, 1, "passive");
4472 cand.related_address = Some(local_addr);
4473 self.push_candidate(cand);
4474 } else {
4475 self.push_candidate(IceCandidate::tcp(local_addr, 1, "passive"));
4476 }
4477 }
4478
4479 #[allow(dead_code)]
4481 #[cfg(feature = "std")]
4482 pub fn upnp_mappers(&self) -> Arc<crate::platform::sync::Mutex<Vec<UpnpPortMapper>>> {
4483 self.upnp_mappers.clone()
4484 }
4485
4486 #[allow(dead_code)]
4488 pub async fn cleanup_upnp_mappings(&self) {
4489 let mappers = self.upnp_mappers.lock().clone();
4490 for mapper in mappers {
4491 if let Err(e) = mapper.cleanup().await {
4492 trace!("Failed to clean up UPnP mappings: {}", e);
4493 }
4494 }
4495 self.upnp_mappers.lock().clear();
4496 }
4497
4498 #[cfg(feature = "std")]
4504 pub async fn renew_upnp_mappings(&self) {
4505 let mappers = self.upnp_mappers.lock().clone();
4506 for mapper in mappers {
4507 if let Err(e) = mapper.renew_all_stale().await {
4508 warn!("Failed to refresh UPnP mappings: {}", e);
4509 }
4510 }
4511 }
4512
4513 fn state(&self) -> IceGathererState {
4514 *self.state.lock()
4515 }
4516
4517 fn local_candidates(&self) -> Vec<IceCandidate> {
4518 self.local_candidates.lock().clone()
4519 }
4520
4521 async fn bind_socket(&self, ip: IpAddr) -> RtcResult<IceSocketWrapper> {
4522 if let (Some(start), Some(end)) = (self.config.rtp_start_port, self.config.rtp_end_port) {
4523 let start = start.saturating_add(start % 2);
4524 let end = end - (end % 2);
4525
4526 if start > end {
4527 return Err(RtcError::Internal(format!(
4528 "No usable even RTP ports in range {}..={}",
4529 start, end
4530 )));
4531 }
4532
4533 let port_count = (((end - start) / 2) + 1) as u64;
4534 let start_index = (random_u64() % port_count) as u16;
4535 let mut port = start + (start_index * 2);
4536
4537 for _ in 0..port_count {
4538 match self.bind_one(SocketAddr::new(ip, port)).await {
4539 Ok(socket) => return Ok(socket),
4540 Err(e) => {
4541 if !e.is_addr_in_use() {
4549 error!(
4550 label = self.config.label.as_deref().unwrap_or("-"),
4551 "binding RTP port {} on {} failed: {}", port, ip, e
4552 );
4553 return Err(e);
4554 }
4555 port = port.saturating_add(2);
4556 if port > end {
4557 port = start;
4558 }
4559 }
4560 }
4561 }
4562 return Err(RtcError::Internal(format!(
4563 "No available even RTP ports in range {}..={} (label={label})",
4564 start,
4565 end,
4566 label = self.config.label.as_deref().unwrap_or("-")
4567 )));
4568 } else {
4569 self.bind_one(SocketAddr::new(ip, 0)).await
4570 }
4571 }
4572
4573 async fn bind_one(&self, addr: SocketAddr) -> RtcResult<IceSocketWrapper> {
4579 if let Some(result) = crate::platform::net::udp_bind_via_factory(addr) {
4580 let socket = result?;
4581 let wrapper = IceSocketWrapper::Platform(socket.clone());
4582 self.platform_sockets.lock().push(socket);
4583 return Ok(wrapper);
4584 }
4585
4586 #[cfg(feature = "std")]
4587 {
4588 let socket = UdpSocket::bind(addr).await?;
4589 let socket = Arc::new(socket);
4590 self.sockets.lock().push(socket.clone());
4591 Ok(IceSocketWrapper::Udp(socket))
4592 }
4593 #[cfg(not(feature = "std"))]
4594 {
4595 let _ = addr;
4596 Err(RtcError::Internal(alloc::string::String::from(
4597 "no UDP bind backend: install one via platform::net::set_udp_bind_fn (rtcembed)",
4598 )))
4599 }
4600 }
4601
4602 pub(crate) fn get_platform_socket(
4605 &self,
4606 addr: SocketAddr,
4607 ) -> Option<Arc<dyn crate::platform::net::UdpSocket>> {
4608 let sockets = self.platform_sockets.lock();
4609 sockets.iter().find_map(|socket| {
4610 let local = socket.local_addr().ok()?;
4611 let matches =
4612 local == addr || (local.ip().is_unspecified() && local.port() == addr.port());
4613 matches.then(|| socket.clone())
4614 })
4615 }
4616
4617 pub(crate) fn register_bound(&self, wrapper: &IceSocketWrapper) {
4621 if let IceSocketWrapper::Udp(s) = wrapper {
4622 self.sockets.lock().push(s.clone());
4623 }
4624 let _ = self.socket_tx.send(wrapper.clone());
4625 }
4626
4627 fn get_socket(&self, addr: SocketAddr) -> Option<Arc<UdpSocket>> {
4628 let found = {
4629 let sockets = self.sockets.lock();
4630 sockets.iter().find_map(|socket| {
4631 let local = socket.local_addr().ok()?;
4632 let matches =
4633 local == addr || (local.ip().is_unspecified() && local.port() == addr.port());
4634 matches.then(|| socket.clone())
4635 })
4636 };
4637 if let Some(s) = found {
4638 return Some(s);
4639 }
4640 if let Some(IceSocketWrapper::SharedUdp(handle)) = self.shared_udp_socket.lock().clone()
4644 && let Ok(local) = handle.local_addr()
4645 && (local == addr || (local.ip().is_unspecified() && local.port() == addr.port()))
4646 {
4647 return None; }
4649 let available: Vec<String> = self
4651 .sockets
4652 .lock()
4653 .iter()
4654 .map(|s| {
4655 s.local_addr()
4656 .map(|a| a.to_string())
4657 .unwrap_or_else(|_| "error".to_string())
4658 })
4659 .collect();
4660 trace!(
4661 "get_socket: no socket found for {}, available: {:?}",
4662 addr, available
4663 );
4664 None
4665 }
4666
4667 fn get_tcp_socket(&self, addr: SocketAddr) -> Option<IceSocketWrapper> {
4668 let streams = self.tcp_streams.lock();
4669 for (local_addr, wrapper) in streams.iter() {
4670 if *local_addr == addr {
4671 return Some(wrapper.clone());
4672 }
4673 if local_addr.ip().is_unspecified() && local_addr.port() == addr.port() {
4675 return Some(wrapper.clone());
4676 }
4677 }
4678 trace!(
4679 "get_tcp_socket: no TCP stream found for {}, available: {:?}",
4680 addr,
4681 streams.keys().collect::<Vec<_>>()
4682 );
4683 None
4684 }
4685
4686 fn store_tcp_stream(&self, local_addr: SocketAddr, wrapper: IceSocketWrapper) {
4687 self.tcp_streams.lock().insert(local_addr, wrapper);
4688 }
4689
4690 #[instrument(skip(self))]
4691 async fn gather(&self) -> RtcResult<()> {
4692 {
4693 let mut state = self.state.lock();
4694 if *state == IceGathererState::Complete {
4695 return Ok(());
4696 }
4697 *state = IceGathererState::Gathering;
4698 }
4699
4700 let host_fut = async {
4702 if self.config.ice_transport_policy == IceTransportPolicy::All {
4703 if self.config.ice_gather_udp_hosts {
4704 if let Err(e) = self.gather_host_candidates().await {
4705 debug!("Host gathering failed: {}", e);
4706 }
4707 } else if self.config.ice_tcp_policy == crate::config::IceTcpPolicy::Enabled {
4708 let has_tcp_listen_range = match (
4712 self.config.tcp_port_range_start,
4713 self.config.tcp_port_range_end,
4714 ) {
4715 (Some(s), Some(e)) => s > 0 && e > 0 && s <= e,
4716 _ => false,
4717 };
4718 if !has_tcp_listen_range
4719 && let Err(e) = self.gather_tcp_active_candidates().await
4720 {
4721 debug!("TCP active gathering failed: {}", e);
4722 }
4723 }
4724 }
4725 };
4726
4727 host_fut.await;
4728
4729 if (self.config.tcp_port_range_start.is_some() || self.config.tcp_port_range_end.is_some())
4731 && let Err(e) = {
4732 #[cfg(feature = "std")]
4733 {
4734 self.gather_tcp_host_candidates().await
4735 }
4736 #[cfg(not(feature = "std"))]
4737 {
4738 Ok::<(), RtcError>(())
4739 }
4740 }
4741 {
4742 debug!("TCP host gathering failed: {}", e);
4743 }
4744
4745 let stun_public_ip = if self.config.enable_upnp {
4751 with_timeout(
4752 Duration::from_secs(5),
4753 self.gather_servers_and_get_public_ip(),
4754 )
4755 .await
4756 .unwrap_or_else(|_| {
4757 debug!(
4758 "STUN/TURN gathering timed out after 5s, skipping UPnP double-NAT detection"
4759 );
4760 None
4761 })
4762 } else {
4763 if let Err(e) = self.gather_servers().await {
4764 debug!("Server gathering failed: {}", e);
4765 }
4766 None
4767 };
4768
4769 if self.config.enable_upnp
4771 && self.config.ice_transport_policy == IceTransportPolicy::All
4772 && let Err(e) = self.gather_upnp_candidates(stun_public_ip).await
4773 {
4774 debug!("UPnP gathering failed: {}", e);
4775 }
4776
4777 *self.state.lock() = IceGathererState::Complete;
4778 Ok(())
4779 }
4780
4781 async fn gather_shared_udp_host_candidate(&self) -> RtcResult<()> {
4786 let port = self.config.ice_udp_mux_port.ok_or_else(|| {
4787 RtcError::Internal(format!(
4788 "ice_udp_mux is enabled but ice_udp_mux_port is not set"
4789 ))
4790 })?;
4791
4792 let bind_ip = if let Some(bind_ip_str) = &self.config.bind_ip {
4793 bind_ip_str
4794 .parse::<IpAddr>()
4795 .map_err(|e| RtcError::Internal(format!("invalid bind_ip {bind_ip_str}: {e}")))?
4796 } else {
4797 IpAddr::V4(core::net::Ipv4Addr::UNSPECIFIED)
4800 };
4801
4802 if self.config.disable_ipv6 && bind_ip.is_ipv6() {
4803 return Err(RtcError::Internal(format!(
4804 "disable_ipv6 is set but bind_ip is IPv6"
4805 )));
4806 }
4807
4808 let bind_addr = SocketAddr::new(bind_ip, port);
4809
4810 let inner = self
4811 .transport_inner
4812 .lock()
4813 .as_ref()
4814 .and_then(|weak| weak.upgrade())
4815 .ok_or_else(|| {
4816 RtcError::Internal("ICE transport unavailable during shared UDP gather".into())
4817 })?;
4818 let ufrag = inner.local_parameters.lock().username_fragment.clone();
4819
4820 let (local_addr, handle, registration) = shared_udp::acquire(bind_addr, ufrag)
4821 .await
4822 .map_err(|e| RtcError::Internal(format!("shared udp acquire: {e}")))?;
4823
4824 self.shared_udp_regs.lock().push(registration);
4825
4826 let wrapper = IceSocketWrapper::SharedUdp(Arc::new(handle));
4827 *self.shared_udp_socket.lock() = Some(wrapper.clone());
4828 let _ = self.socket_tx.send(wrapper);
4829
4830 if self.push_host_with_external_srflx(local_addr, bind_ip, None) {
4831 return Ok(());
4832 }
4833 let mut cand_addr = local_addr;
4835 if let Some(ext_ip) = &self.config.external_ip
4836 && let Ok(parsed_ip) = ext_ip.parse::<IpAddr>()
4837 {
4838 if !bind_ip.is_loopback() {
4839 cand_addr.set_ip(parsed_ip);
4840 }
4841 } else if bind_ip.is_unspecified()
4842 && let Ok(local_ip) = get_local_ip()
4843 {
4844 cand_addr.set_ip(local_ip);
4845 }
4846
4847 let mut cand = IceCandidate::host(cand_addr, 1);
4848 if cand_addr != local_addr {
4849 cand.related_address = Some(local_addr);
4850 }
4851 self.push_candidate(cand);
4852 Ok(())
4853 }
4854
4855 async fn gather_host_candidates(&self) -> RtcResult<()> {
4856 let mut bind_ips = Vec::new();
4857
4858 if let Some(bind_ip_str) = &self.config.bind_ip {
4859 if let Ok(ip) = bind_ip_str.parse::<IpAddr>() {
4860 bind_ips.push(ip);
4861 }
4862 } else if self.config.transport_mode != crate::TransportMode::WebRtc {
4863 if let Ok(ip) = get_local_ip() {
4867 bind_ips.push(ip);
4868 } else {
4869 bind_ips.push(IpAddr::V4(core::net::Ipv4Addr::UNSPECIFIED));
4870 }
4871 } else {
4872 if self.config.ice_include_loopback_candidates {
4876 bind_ips.push(IpAddr::V4(core::net::Ipv4Addr::LOCALHOST));
4877 }
4878
4879 #[cfg(feature = "std")]
4880 use local_ip_address::list_afinet_netifas;
4881 #[cfg(feature = "std")]
4882 if let Ok(interfaces) = list_afinet_netifas() {
4883 for (name, addr) in interfaces {
4884 if let IpAddr::V4(ip) = addr
4885 && !ip.is_loopback()
4886 && !bind_ips.contains(&IpAddr::V4(ip))
4887 {
4888 if name.starts_with("utun")
4890 || name.starts_with("gif")
4891 || name.starts_with("stf")
4892 || name.starts_with("awdl")
4893 || name.starts_with("llw")
4894 {
4895 continue;
4896 }
4897 bind_ips.push(IpAddr::V4(ip));
4898 }
4899 }
4900 }
4901
4902 #[cfg(not(feature = "std"))]
4907 if let Ok(ip) = get_local_ip() {
4908 bind_ips.push(ip);
4909 }
4910 }
4911
4912 if self.config.ice_udp_mux
4913 && let Err(e) = self.gather_shared_udp_host_candidate().await
4914 {
4915 debug!("Shared UDP mux host candidate failed: {}", e);
4916 }
4917
4918 for ip in &bind_ips {
4919 let ip = *ip;
4920 if self.config.ice_udp_mux {
4923 continue;
4924 }
4925 match self.bind_socket(ip).await {
4926 Ok(socket) => {
4927 if let Ok(addr) = socket.local_addr() {
4928 self.register_bound(&socket);
4929
4930 if self.push_host_with_external_srflx(addr, ip, None) {
4931 } else if let Some(ext_ip) = &self.config.external_ip
4933 && let Ok(parsed_ip) = ext_ip.parse::<IpAddr>()
4934 {
4935 if !ip.is_loopback() {
4936 let mut ext_addr = addr;
4937 ext_addr.set_ip(parsed_ip);
4938 let mut cand = IceCandidate::host(ext_addr, 1);
4939 cand.related_address = Some(addr);
4940 self.push_candidate(cand);
4941 } else {
4942 self.push_candidate(IceCandidate::host(addr, 1));
4943 }
4944 } else if ip.is_unspecified() {
4945 let mut cand_addr = addr;
4947 if let Ok(local_ip) = get_local_ip() {
4948 cand_addr.set_ip(local_ip);
4949 }
4950 let mut cand = IceCandidate::host(cand_addr, 1);
4951 cand.related_address = Some(addr);
4952 self.push_candidate(cand);
4953 } else {
4954 self.push_candidate(IceCandidate::host(addr, 1));
4955 }
4956 }
4957 }
4958 Err(e) => {
4959 if self.config.bind_ip.is_some() {
4960 debug!(
4961 label = self.config.label.as_deref().unwrap_or("-"),
4962 "Failed to bind to requested bind_ip {}: {}", ip, e
4963 );
4964 } else if !ip.is_loopback() && !ip.is_unspecified() {
4965 debug!(
4966 label = self.config.label.as_deref().unwrap_or("-"),
4967 "Failed to bind socket on {}: {}", ip, e
4968 );
4969 }
4970 }
4971 }
4972 }
4973
4974 #[cfg(feature = "std")]
4977 if self.config.ice_tcp_policy != crate::config::IceTcpPolicy::Disabled {
4978 for ip in &bind_ips {
4979 let ip = *ip;
4980 match TcpListener::bind(SocketAddr::new(ip, 0)).await {
4981 Ok(listener) => {
4982 if let Ok(addr) = listener.local_addr() {
4983 let listener = Arc::new(listener);
4984 self.tcp_listeners.lock().push(listener.clone());
4985 #[cfg(feature = "std")]
4986 let _ = self.socket_tx.send(IceSocketWrapper::TcpListener(listener));
4987
4988 let tcp_type = TcpType::Passive;
4989 if self.push_host_with_external_srflx(addr, ip, Some(tcp_type)) {
4990 continue;
4991 }
4992 let mut cand = IceCandidate::host_tcp(addr, 1, tcp_type);
4993 if ip.is_unspecified()
4994 && let Ok(local_ip) = get_local_ip()
4995 {
4996 let mut cand_addr = addr;
4997 cand_addr.set_ip(local_ip);
4998 let mut ext_cand = IceCandidate::host_tcp(cand_addr, 1, tcp_type);
4999 ext_cand.related_address = Some(addr);
5000 cand = ext_cand;
5001 }
5002 self.push_candidate(cand);
5003 }
5004 }
5005 Err(e) => {
5006 debug!("Failed to bind TCP listener on {}: {}", ip, e);
5007 }
5008 }
5009 }
5010 }
5011
5012 Ok(())
5013 }
5014
5015 async fn gather_tcp_active_candidates(&self) -> RtcResult<()> {
5019 use core::net::{IpAddr, Ipv4Addr};
5020
5021 const ACTIVE_PLACEHOLDER_PORT: u16 = 9;
5022
5023 let mut bind_ips = Vec::new();
5024 if self.config.ice_include_loopback_candidates {
5025 bind_ips.push(IpAddr::V4(Ipv4Addr::LOCALHOST));
5026 }
5027 if let Ok(local_ip) = get_local_ip()
5028 && !bind_ips.contains(&local_ip)
5029 {
5030 bind_ips.push(local_ip);
5031 }
5032
5033 for ip in bind_ips {
5034 self.push_candidate(IceCandidate::tcp(
5035 SocketAddr::new(ip, ACTIVE_PLACEHOLDER_PORT),
5036 1,
5037 "active",
5038 ));
5039 }
5040 self.push_candidate(IceCandidate::tcp(
5041 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), ACTIVE_PLACEHOLDER_PORT),
5042 1,
5043 "active",
5044 ));
5045 Ok(())
5046 }
5047
5048 #[cfg(feature = "std")]
5049 async fn gather_tcp_host_candidates(&self) -> RtcResult<()> {
5050 let start = self.config.tcp_port_range_start.unwrap_or(0);
5051 let end = self.config.tcp_port_range_end.unwrap_or(0);
5052
5053 if start == 0 || end == 0 || start > end {
5054 return Ok(());
5055 }
5056
5057 let bind_ips = if let Some(bind_ip_str) = &self.config.bind_ip {
5058 if let Ok(ip) = bind_ip_str.parse::<IpAddr>() {
5059 vec![ip]
5060 } else {
5061 return Ok(());
5062 }
5063 } else {
5064 let mut ips = Vec::new();
5065 if self.config.ice_include_loopback_candidates {
5066 ips.push(IpAddr::V4(core::net::Ipv4Addr::LOCALHOST));
5067 }
5068 #[cfg(feature = "std")]
5069 use local_ip_address::list_afinet_netifas;
5070 #[cfg(feature = "std")]
5071 if let Ok(interfaces) = list_afinet_netifas() {
5072 for (name, addr) in interfaces {
5073 if let IpAddr::V4(ip) = addr
5074 && !ip.is_loopback()
5075 && !ips.contains(&IpAddr::V4(ip))
5076 {
5077 if name.starts_with("utun")
5078 || name.starts_with("gif")
5079 || name.starts_with("stf")
5080 || name.starts_with("awdl")
5081 || name.starts_with("llw")
5082 {
5083 continue;
5084 }
5085 ips.push(IpAddr::V4(ip));
5086 }
5087 }
5088 }
5089 ips
5090 };
5091
5092 let use_shared_listener = start == end;
5096
5097 for ip in bind_ips {
5098 if use_shared_listener {
5099 let addr = SocketAddr::new(ip, start);
5100 let inner = self
5101 .transport_inner
5102 .lock()
5103 .as_ref()
5104 .and_then(|weak| weak.upgrade())
5105 .ok_or_else(|| {
5106 RtcError::Internal("ICE transport unavailable during TCP gather".into())
5107 })?;
5108 let ufrag = inner.local_parameters.lock().username_fragment.clone();
5109 match shared_tcp::acquire(addr, ufrag, Arc::downgrade(&inner)).await {
5110 Ok((local_addr, registration)) => {
5111 self.shared_tcp_regs.lock().push(registration);
5112 self.push_tcp_passive_candidate(local_addr, ip);
5113 break;
5114 }
5115 Err(e) => {
5116 debug!("shared TCP listener acquire on {} failed: {}", addr, e);
5117 }
5118 }
5119 continue;
5120 }
5121
5122 for port in start..=end {
5123 let addr = SocketAddr::new(ip, port);
5124 match TcpListener::bind(addr).await {
5125 Ok(listener) => {
5126 let local_addr = match listener.local_addr() {
5127 Ok(a) => a,
5128 Err(_) => continue,
5129 };
5130 let listener = Arc::new(listener);
5131 self.tcp_listeners.lock().push(listener.clone());
5132 #[cfg(feature = "std")]
5133 let _ = self.socket_tx.send(IceSocketWrapper::TcpListener(listener));
5134
5135 self.push_tcp_passive_candidate(local_addr, ip);
5136 break;
5137 }
5138 Err(_) => continue,
5139 }
5140 }
5141 }
5142
5143 Ok(())
5144 }
5145
5146 async fn gather_upnp_candidates(&self, stun_public_ip: Option<IpAddr>) -> RtcResult<()> {
5147 let sockets = self.sockets.lock().clone();
5148 let timeout = self.config.upnp_discovery_timeout;
5149 let mut tasks = FuturesUnordered::new();
5150
5151 for socket in sockets {
5152 let local_addr = match socket.local_addr() {
5153 Ok(addr) => addr,
5154 Err(_) => continue,
5155 };
5156
5157 if local_addr.ip().is_loopback() {
5159 continue;
5160 }
5161
5162 if local_addr.is_ipv6() {
5164 continue;
5165 }
5166
5167 let this = self.clone();
5168 let stun_ip = stun_public_ip;
5169 tasks.push(async move {
5170 let mut mapper = UpnpPortMapper::with_lease_duration(
5172 local_addr,
5173 this.config.upnp_lease_duration,
5174 );
5175
5176 if let Err(e) = mapper.discover_with_timeout(timeout).await {
5178 trace!("UPnP discovery failed for {}: {}", local_addr, e);
5179 return;
5180 }
5181
5182 match mapper.add_mapping(0).await {
5184 Ok(external_addr) => {
5185 let is_private = is_private_ip(&external_addr.ip());
5187
5188 let candidate_addr = if is_private {
5190 if let Some(public_ip) = stun_ip {
5191 let mut addr = external_addr;
5192 addr.set_ip(public_ip);
5193 debug!(
5194 "UPnP double-NAT detected: {} is private, using STUN public IP {} -> {}",
5195 external_addr.ip(),
5196 public_ip,
5197 addr
5198 );
5199 addr
5200 } else {
5201 debug!(
5202 "UPnP returned private IP {} but no STUN public IP available",
5203 external_addr.ip()
5204 );
5205 external_addr
5206 }
5207 } else {
5208 external_addr
5209 };
5210
5211 let candidate =
5213 IceCandidate::server_reflexive(local_addr, candidate_addr, 1);
5214 this.push_candidate(candidate);
5215
5216 this.upnp_mappers.lock().push(mapper);
5218
5219 debug!(
5220 "UPnP candidate gathered: {} -> {}",
5221 local_addr, candidate_addr
5222 );
5223 }
5224 Err(e) => {
5225 debug!("UPnP mapping failed for {}: {}", local_addr, e);
5226 }
5227 }
5228 });
5229 }
5230
5231 while tasks.next().await.is_some() {}
5232
5233 Ok(())
5234 }
5235
5236 async fn gather_servers(&self) -> RtcResult<()> {
5237 let mut tasks = FuturesUnordered::new();
5238
5239 for server in &self.config.ice_servers {
5240 for url in &server.urls {
5241 let server = server.clone();
5242 let url = url.clone();
5243 let this = self.clone();
5244
5245 tasks.push(async move {
5246 let uri = match IceServerUri::parse(&url) {
5247 Ok(uri) => uri,
5248 Err(err) => {
5249 debug!("invalid ICE server URI {}: {}", url, err);
5250 return;
5251 }
5252 };
5253
5254 match uri.kind {
5255 IceUriKind::Stun => {
5256 if this.config.ice_transport_policy == IceTransportPolicy::All {
5257 match this.probe_stun(&uri).await {
5258 Ok(Some(candidate)) => this.push_candidate(candidate),
5259 Ok(None) => {}
5260 Err(e) => debug!(
5261 label = this.config.label.as_deref().unwrap_or("-"),
5262 "STUN probe failed for {}: {}", url, e
5263 ),
5264 }
5265 }
5266 }
5267 IceUriKind::Turn => match this.probe_turn(&uri, &server).await {
5268 Ok(Some(candidate)) => this.push_candidate(candidate),
5269 Ok(None) => {}
5270 Err(e) => debug!(
5271 label = this.config.label.as_deref().unwrap_or("-"),
5272 "TURN probe failed for {}: {}", url, e
5273 ),
5274 },
5275 }
5276 });
5277 }
5278 }
5279
5280 while tasks.next().await.is_some() {}
5281 Ok(())
5282 }
5283
5284 async fn gather_servers_and_get_public_ip(&self) -> Option<IpAddr> {
5287 let mut tasks = FuturesUnordered::new();
5288 let public_ip: Arc<crate::platform::sync::Mutex<Option<IpAddr>>> =
5289 Arc::new(crate::platform::sync::Mutex::new(None));
5290
5291 for server in &self.config.ice_servers {
5292 for url in &server.urls {
5293 let server = server.clone();
5294 let url = url.clone();
5295 let this = self.clone();
5296 let public_ip_clone = public_ip.clone();
5297
5298 tasks.push(async move {
5299 let uri = match IceServerUri::parse(&url) {
5300 Ok(uri) => uri,
5301 Err(err) => {
5302 debug!("invalid ICE server URI {}: {}", url, err);
5303 return;
5304 }
5305 };
5306
5307 match uri.kind {
5308 IceUriKind::Stun => {
5309 if this.config.ice_transport_policy == IceTransportPolicy::All {
5310 match this.probe_stun(&uri).await {
5311 Ok(Some(candidate)) => {
5312 if !is_private_ip(&candidate.address.ip()) {
5314 let mut ip = public_ip_clone.lock();
5315 if ip.is_none() {
5316 *ip = Some(candidate.address.ip());
5317 }
5318 }
5319 this.push_candidate(candidate);
5320 }
5321 Ok(None) => {}
5322 Err(e) => debug!(
5323 label = this.config.label.as_deref().unwrap_or("-"),
5324 "STUN probe failed for {}: {}", url, e
5325 ),
5326 }
5327 }
5328 }
5329 IceUriKind::Turn => match this.probe_turn(&uri, &server).await {
5330 Ok(Some(candidate)) => this.push_candidate(candidate),
5331 Ok(None) => {}
5332 Err(e) => debug!(
5333 label = this.config.label.as_deref().unwrap_or("-"),
5334 "TURN probe failed for {}: {}", url, e
5335 ),
5336 },
5337 }
5338 });
5339 }
5340 }
5341
5342 while tasks.next().await.is_some() {}
5343 let ip = *public_ip.lock();
5344 if let Some(ip) = &ip {
5345 debug!("STUN public IP for UPnP double-NAT detection: {}", ip);
5346 } else {
5347 debug!("No STUN public IP available for UPnP double-NAT detection");
5348 }
5349 ip
5350 }
5351
5352 async fn probe_stun(&self, uri: &IceServerUri) -> RtcResult<Option<IceCandidate>> {
5353 let addr = uri.resolve(self.config.disable_ipv6).await?;
5354
5355 let pick_bind_ip = |c: &IceCandidate| -> Option<IpAddr> {
5362 let base = c.related_address.unwrap_or(c.address);
5363 match base.ip() {
5364 IpAddr::V4(ip) if !addr.is_ipv6() && !ip.is_loopback() && !ip.is_unspecified() => {
5365 Some(IpAddr::V4(ip))
5366 }
5367 IpAddr::V6(ip) if addr.is_ipv6() && !ip.is_loopback() && !ip.is_unspecified() => {
5368 Some(IpAddr::V6(ip))
5369 }
5370 _ => None,
5371 }
5372 };
5373 let fallback = if addr.is_ipv6() {
5374 IpAddr::V6(core::net::Ipv6Addr::UNSPECIFIED)
5375 } else {
5376 IpAddr::V4(core::net::Ipv4Addr::new(0, 0, 0, 0))
5377 };
5378 let bind_ip = self
5379 .local_candidates
5380 .lock()
5381 .iter()
5382 .filter(|c| c.typ == IceCandidateType::Host)
5383 .filter_map(pick_bind_ip)
5384 .next()
5385 .unwrap_or(fallback);
5386
5387 let socket = match uri.transport {
5388 IceTransportProtocol::Udp => self.bind_socket(bind_ip).await?,
5389 IceTransportProtocol::Tcp => self.bind_socket(bind_ip).await?,
5390 };
5391 let local_addr = socket.local_addr()?;
5392 let tx_id = random_bytes::<12>();
5393 let message = StunMessage::binding_request(tx_id, Some("rustrtc"));
5394 let bytes = message.encode(None, true)?;
5395 socket.send_to(&bytes, addr).await?;
5396 let mut buf = [0u8; MAX_STUN_MESSAGE];
5397 let (len, from) = with_timeout(self.config.stun_timeout, socket.recv_from(&mut buf))
5398 .await
5399 .map_err(|_| RtcError::Internal("stun recv timeout".into()))??;
5400 if from.ip() != addr.ip() {
5401 return Ok(None);
5402 }
5403 let parsed = StunMessage::decode(&buf[..len])?;
5404 if let Some(mapped) = parsed.xor_mapped_address {
5405 self.register_bound(&socket);
5406 return Ok(Some(IceCandidate::server_reflexive(local_addr, mapped, 1)));
5407 }
5408 Ok(None)
5409 }
5410
5411 async fn probe_turn(
5412 &self,
5413 uri: &IceServerUri,
5414 server: &IceServer,
5415 ) -> RtcResult<Option<IceCandidate>> {
5416 let credentials = TurnCredentials::from_server(server)?;
5417 let client = TurnClient::connect(uri, self.config.disable_ipv6).await?;
5418 let allocation = client.allocate(credentials).await?;
5419 let relayed_addr = allocation.relayed_address;
5420 debug!(
5421 "TURN allocation granted: relayed={}, lifetime={}s",
5422 relayed_addr, allocation.lifetime_secs
5423 );
5424
5425 let client = Arc::new(client);
5426 self.turn_clients
5427 .lock()
5428 .insert(relayed_addr, client.clone());
5429 let _ = self
5430 .socket_tx
5431 .send(IceSocketWrapper::Turn(client, relayed_addr));
5432
5433 Ok(Some(IceCandidate::relay(
5434 relayed_addr,
5435 1,
5436 allocation.transport.as_str(),
5437 )))
5438 }
5439
5440 fn push_candidate(&self, mut candidate: IceCandidate) {
5441 if self.config.disable_ipv6 && candidate.address.is_ipv6() {
5442 return;
5443 }
5444 if candidate.typ == IceCandidateType::Host
5448 && let Some(hostname) = self
5449 .transport_inner
5450 .lock()
5451 .as_ref()
5452 .and_then(|weak| weak.upgrade())
5453 .and_then(|inner| inner.mdns_hostname.clone())
5454 {
5455 candidate = candidate.with_hostname(hostname);
5456 }
5457 let mut candidates = self.local_candidates.lock();
5458 if candidates.iter().any(|c| c.address == candidate.address) {
5459 return;
5460 }
5461 tracing::debug!(
5462 "Gathered local candidate: {} type={:?}",
5463 candidate.address,
5464 candidate.typ
5465 );
5466 candidates.push(candidate.clone());
5467 drop(candidates);
5468 let _ = self.candidate_tx.send(candidate);
5469 }
5470}
5471
5472#[derive(Debug, Clone, PartialEq, Eq)]
5473pub(crate) struct IceServerUri {
5474 kind: IceUriKind,
5475 host: String,
5476 port: u16,
5477 transport: IceTransportProtocol,
5478}
5479
5480impl IceServerUri {
5481 fn parse(input: &str) -> RtcResult<Self> {
5482 let (scheme, rest) = input
5483 .split_once(':')
5484 .ok_or_else(|| RtcError::Internal(format!("missing scheme")))?;
5485 let (host_part, query) = match rest.split_once('?') {
5486 Some(parts) => parts,
5487 None => (rest, ""),
5488 };
5489 let (host, port) = if let Some((h, p)) = host_part.rsplit_once(':') {
5490 let port = p
5491 .parse::<u16>()
5492 .map_err(|e| RtcError::Internal(format!("invalid port: {e}")))?;
5493 (h.to_string(), port)
5494 } else {
5495 (host_part.to_string(), default_port_for_scheme(scheme)?)
5496 };
5497 let mut transport = default_transport_for_scheme(scheme)?;
5498 if !query.is_empty() {
5499 for pair in query.split('&') {
5500 if let Some((k, v)) = pair.split_once('=')
5501 && k == "transport"
5502 {
5503 transport = match v.to_ascii_lowercase().as_str() {
5504 "udp" => IceTransportProtocol::Udp,
5505 "tcp" => IceTransportProtocol::Tcp,
5506 other => {
5507 return Err(RtcError::Internal(format!(
5508 "unsupported transport {}",
5509 other
5510 )));
5511 }
5512 };
5513 }
5514 }
5515 }
5516 if scheme.starts_with("stun") && query.contains("transport") {
5517 return Err(RtcError::Internal(format!(
5518 "stun URI must not include transport parameter"
5519 )));
5520 }
5521 let kind = match scheme {
5522 "stun" | "stuns" => IceUriKind::Stun,
5523 "turn" | "turns" => IceUriKind::Turn,
5524 other => return Err(RtcError::Internal(format!("unsupported scheme {}", other))),
5525 };
5526 Ok(Self {
5527 kind,
5528 host,
5529 port,
5530 transport,
5531 })
5532 }
5533
5534 async fn resolve(&self, disable_ipv6: bool) -> RtcResult<SocketAddr> {
5535 let target = format!("{}:{}", self.host, self.port);
5536 let addrs = with_timeout(
5537 Duration::from_secs(5),
5538 crate::platform::dns::lookup_host(&target),
5539 )
5540 .await
5541 .map_err(|_| RtcError::Internal(format!("DNS lookup timed out for {}", target)))??;
5542
5543 for addr in addrs {
5544 if disable_ipv6 && addr.is_ipv6() {
5545 continue;
5546 }
5547 return Ok(addr);
5548 }
5549 Err(RtcError::Internal(format!(
5550 "{} unresolved (disable_ipv6={})",
5551 self.host, disable_ipv6
5552 )))
5553 }
5554}
5555
5556#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5557enum IceUriKind {
5558 Stun,
5559 Turn,
5560}
5561
5562#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5563pub(crate) enum IceTransportProtocol {
5564 Udp,
5565 Tcp,
5566}
5567
5568impl IceTransportProtocol {
5569 fn as_str(&self) -> &'static str {
5570 match self {
5571 IceTransportProtocol::Udp => "udp",
5572 IceTransportProtocol::Tcp => "tcp",
5573 }
5574 }
5575}
5576
5577fn default_port_for_scheme(scheme: &str) -> RtcResult<u16> {
5578 Ok(match scheme {
5579 "stun" | "turn" => 3478,
5580 "stuns" | "turns" => 5349,
5581 other => return Err(RtcError::Internal(format!("unsupported scheme {}", other))),
5582 })
5583}
5584
5585fn default_transport_for_scheme(scheme: &str) -> RtcResult<IceTransportProtocol> {
5586 Ok(match scheme {
5587 "stun" | "turn" => IceTransportProtocol::Udp,
5588 "stuns" | "turns" => IceTransportProtocol::Tcp,
5589 other => return Err(RtcError::Internal(format!("unsupported scheme {}", other))),
5590 })
5591}
5592
5593fn is_private_ip(ip: &IpAddr) -> bool {
5595 match ip {
5596 IpAddr::V4(ipv4) => {
5597 let octets = ipv4.octets();
5598 octets[0] == 10
5600 || (octets[0] == 172 && (16..=31).contains(&octets[1]))
5602 || (octets[0] == 192 && octets[1] == 168)
5604 || (octets[0] == 169 && octets[1] == 254)
5606 || octets[0] == 127
5608 }
5609 IpAddr::V6(ipv6) => {
5610 ipv6.segments()[0] & 0xfe00 == 0xfc00
5612 || ipv6.segments()[0] & 0xffc0 == 0xfe80
5614 || *ipv6 == core::net::Ipv6Addr::LOCALHOST
5616 }
5617 }
5618}
5619
5620fn hex_encode(bytes: &[u8]) -> String {
5621 const TABLE: &[u8; 16] = b"0123456789abcdef";
5622 let mut out = String::with_capacity(bytes.len() * 2);
5623 for byte in bytes {
5624 out.push(TABLE[(byte >> 4) as usize] as char);
5625 out.push(TABLE[(byte & 0x0f) as usize] as char);
5626 }
5627 out
5628}
5629
5630#[derive(Clone)]
5631pub enum IceSocketWrapper {
5632 Platform(Arc<dyn crate::platform::net::UdpSocket>),
5633 Udp(Arc<UdpSocket>),
5636 SharedUdp(Arc<shared_udp::SharedUdpHandle>),
5640 #[cfg(feature = "std")]
5641 TcpListener(Arc<TcpListener>),
5642 #[cfg(feature = "std")]
5643 TcpStream(
5644 Arc<Mutex<TcpReadHalf>>,
5645 Arc<Mutex<TcpWriteHalf>>,
5646 SocketAddr,
5647 ),
5648 Turn(Arc<TurnClient>, SocketAddr),
5649}
5650
5651impl core::fmt::Debug for IceSocketWrapper {
5652 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
5653 f.write_str(&self.diag())
5654 }
5655}
5656
5657impl IceSocketWrapper {
5658 pub fn local_addr(&self) -> RtcResult<SocketAddr> {
5661 match self {
5662 IceSocketWrapper::Platform(s) => s.local_addr().map_err(RtcError::from),
5663 IceSocketWrapper::Udp(s) => s.local_addr().map_err(RtcError::from),
5664 IceSocketWrapper::SharedUdp(h) => h.local_addr(),
5665 #[cfg(feature = "std")]
5666 IceSocketWrapper::TcpListener(l) => l.local_addr().map_err(RtcError::from),
5667 #[cfg(feature = "std")]
5668 IceSocketWrapper::TcpStream(_, _, peer) => Ok(*peer),
5669 IceSocketWrapper::Turn(_, addr) => Ok(*addr),
5670 }
5671 }
5672
5673 pub fn diag(&self) -> String {
5675 match self {
5676 IceSocketWrapper::Platform(s) => format!(
5677 "platform-udp:{}",
5678 s.local_addr()
5679 .map(|a| a.to_string())
5680 .unwrap_or_else(|_| "?".into())
5681 ),
5682 IceSocketWrapper::Udp(s) => format!(
5683 "udp:{}",
5684 s.local_addr()
5685 .map(|a| a.to_string())
5686 .unwrap_or_else(|_| "?".into())
5687 ),
5688 IceSocketWrapper::SharedUdp(h) => format!(
5689 "udp-mux:{}",
5690 h.local_addr()
5691 .map(|a| a.to_string())
5692 .unwrap_or_else(|_| "?".into())
5693 ),
5694 #[cfg(feature = "std")]
5695 IceSocketWrapper::TcpListener(l) => format!(
5696 "tcp-listen:{}",
5697 l.local_addr()
5698 .map(|a| a.to_string())
5699 .unwrap_or_else(|_| "?".into())
5700 ),
5701 #[cfg(feature = "std")]
5702 IceSocketWrapper::TcpStream(_, _, peer) => format!("tcp-stream:peer={peer}"),
5703 IceSocketWrapper::Turn(_, addr) => format!("turn:{addr}"),
5704 }
5705 }
5706
5707 pub fn try_send_to(&self, data: &[u8], addr: SocketAddr) -> RtcResult<usize> {
5711 match self {
5712 IceSocketWrapper::Platform(s) => {
5713 match <dyn crate::platform::net::UdpSocket>::try_send_to(
5714 s.as_ref(),
5715 data,
5716 addr,
5717 ) {
5718 Ok(len) => Ok(len),
5719 Err(e) => Err(RtcError::Internal(alloc::format!(
5720 "platform try_send_to: {e}"
5721 ))),
5722 }
5723 }
5724 IceSocketWrapper::Udp(s) => match s.try_send_to(data, addr) {
5725 Ok(len) => Ok(len),
5726 Err(e) => {
5727 let reason = match s.local_addr() {
5728 Ok(local) => format!("UDP {} -> {} failed: {}", local, addr, e),
5729 Err(_) => format!("UDP -> {} failed: {}", addr, e),
5730 };
5731 Err(RtcError::Internal(reason))
5732 }
5733 },
5734 #[cfg(not(feature = "std"))]
5735 IceSocketWrapper::Udp(_) => {
5736 unimplemented!("direct UDP sockets are std-only")
5737 }
5738 IceSocketWrapper::SharedUdp(h) => {
5739 h.register_peer(addr);
5743 match <dyn crate::platform::net::UdpSocket>::try_send_to(
5744 h.socket().as_ref(),
5745 data,
5746 addr,
5747 ) {
5748 Ok(len) => Ok(len),
5749 Err(e) => {
5750 let reason = match h.local_addr() {
5751 Ok(local) => format!("shared UDP {} -> {} failed: {}", local, addr, e),
5752 Err(_) => format!("shared UDP -> {} failed: {}", addr, e),
5753 };
5754 Err(RtcError::Internal(reason))
5755 }
5756 }
5757 }
5758 _ => Err(RtcError::Internal(format!(
5761 "IceSocketWrapper::try_send_to not supported for this transport variant"
5762 ))),
5763 }
5764 }
5765
5766 pub async fn send_to(&self, data: &[u8], addr: SocketAddr) -> RtcResult<usize> {
5767 match self {
5768 IceSocketWrapper::Platform(s) => s
5769 .send_to(data, addr)
5770 .await
5771 .map_err(|e| RtcError::Internal(format!("platform send_to: {e}"))),
5772 #[cfg(feature = "std")]
5773 IceSocketWrapper::Udp(s) => loop {
5774 match s.try_send_to(data, addr) {
5775 Ok(len) => return Ok(len),
5776 Err(e) if e.kind() == ErrorKind::WouldBlock => {
5777 s.writable().await?;
5778 continue;
5779 }
5780 Err(e) => {
5781 if let Some(code) = e.raw_os_error()
5782 && code == 55
5783 {
5784 s.writable().await?;
5785 continue;
5786 }
5787 let reason = RtcError::Internal(format!(
5788 "UDP {} -> {} failed: {}",
5789 s.local_addr()?,
5790 addr,
5791 e
5792 ));
5793 return Err(reason);
5794 }
5795 }
5796 },
5797 #[cfg(not(feature = "std"))]
5798 IceSocketWrapper::Udp(_) => {
5799 unimplemented!("direct UDP sockets are std-only")
5800 }
5801 IceSocketWrapper::SharedUdp(h) => {
5802 let dest = addr;
5803 h.send_to(data, dest).await.map_err(RtcError::from)
5804 }
5805 #[cfg(feature = "std")]
5806 IceSocketWrapper::TcpListener(_) => {
5807 return Err(RtcError::Internal(format!(
5808 "send_to not supported on TcpListener"
5809 )));
5810 }
5811 #[cfg(feature = "std")]
5812 IceSocketWrapper::TcpStream(_, write, _) => {
5813 let len = data.len();
5814 if len > 0xFFFF {
5815 return Err(RtcError::Internal(format!(
5816 "STUN message too large for TCP framing"
5817 )));
5818 }
5819 let header = (len as u16).to_be_bytes();
5820 let mut framed = Vec::with_capacity(2 + len);
5821 framed.extend_from_slice(&header);
5822 framed.extend_from_slice(data);
5823 tcp_write_all(write, &framed).await?;
5824 Ok(data.len())
5825 }
5826 IceSocketWrapper::Turn(c, _) => {
5827 if let Some(channel) = c.get_channel(addr).await {
5828 c.send_channel_data(channel, data).await?;
5829 } else {
5830 c.send_indication(addr, data).await?;
5831 }
5832 Ok(data.len())
5833 }
5834 }
5835 }
5836
5837 pub async fn recv_from(&self, buf: &mut [u8]) -> RtcResult<(usize, SocketAddr)> {
5838 match self {
5839 IceSocketWrapper::Platform(s) => s.recv_from(buf).await.map_err(|e| e.into()),
5840 IceSocketWrapper::Udp(s) => s.recv_from(buf).await.map_err(|e| e.into()),
5841 IceSocketWrapper::SharedUdp(h) => match h.recv().await {
5842 Some((data, addr)) => {
5843 if data.len() > buf.len() {
5844 return Err(RtcError::Internal(format!(
5845 "shared UDP packet too large: {} > {}",
5846 data.len(),
5847 buf.len()
5848 )));
5849 }
5850 let len = data.len();
5851 buf[..len].copy_from_slice(&data);
5852 Ok((len, addr))
5853 }
5854 None => Err(RtcError::Internal(format!("shared UDP channel closed"))),
5855 },
5856 #[cfg(feature = "std")]
5857 IceSocketWrapper::TcpStream(read, _, peer) => {
5858 #[cfg(feature = "std")]
5859 use tokio::io::AsyncReadExt;
5860 let mut stream = read.lock().await;
5861 let mut len_buf = [0u8; 2];
5862 stream.read_exact(&mut len_buf).await?;
5863 let len = u16::from_be_bytes(len_buf) as usize;
5864 if len > buf.len() {
5865 return Err(RtcError::Internal(format!(
5866 "TCP STUN message too large: {} > {}",
5867 len,
5868 buf.len()
5869 )));
5870 }
5871 stream.read_exact(&mut buf[..len]).await?;
5872 Ok((len, *peer))
5873 }
5874 #[cfg(feature = "std")]
5875 IceSocketWrapper::TcpListener(_) => Err(RtcError::Internal(format!(
5876 "recv_from not supported on TcpListener wrapper directly"
5877 ))),
5878 IceSocketWrapper::Turn(_, _) => Err(RtcError::Internal(format!(
5879 "recv_from not supported on TURN wrapper directly"
5880 ))),
5881 }
5882 }
5883}
5884
5885#[cfg(all(test, feature = "std"))]
5886mod bind_socket_retry_tests {
5887 use super::*;
5892
5893 fn gatherer(start: u16, end: u16) -> IceGatherer {
5894 let (candidate_tx, _) = broadcast::channel(1);
5895 let (socket_tx, _socket_rx) = crate::platform::sync::mpsc::unbounded_channel();
5896 let mut config = RtcConfiguration::default();
5897 config.rtp_start_port = Some(start);
5898 config.rtp_end_port = Some(end);
5899 IceGatherer::new(config, candidate_tx, socket_tx)
5900 }
5901
5902 async fn occupy_even_port() -> (tokio::net::UdpSocket, u16) {
5905 loop {
5906 let s = tokio::net::UdpSocket::bind("127.0.0.1:0").await.unwrap();
5907 let p = s.local_addr().unwrap().port();
5908 if p % 2 == 0 {
5909 return (s, p);
5910 }
5911 }
5912 }
5913
5914 #[tokio::test]
5915 async fn skips_a_busy_port_and_binds_the_next_one() {
5916 let (_blocker, busy) = occupy_even_port().await;
5918 let other = busy + 2;
5919
5920 let g = gatherer(busy, other);
5921 let socket = g
5922 .bind_socket(IpAddr::from([127, 0, 0, 1]))
5923 .await
5924 .expect("bind_socket must skip the busy port");
5925 assert_eq!(socket.local_addr().unwrap().port(), other);
5926 }
5927
5928 #[tokio::test]
5929 async fn exhausts_the_range_with_the_port_exhaustion_error() {
5930 let (_blocker, busy) = occupy_even_port().await;
5933
5934 let g = gatherer(busy, busy);
5935 let err = g
5936 .bind_socket(IpAddr::from([127, 0, 0, 1]))
5937 .await
5938 .expect_err("a fully busy range must fail");
5939 assert!(
5940 err.to_string().contains("No available even RTP ports"),
5941 "expected port exhaustion, got: {err}"
5942 );
5943 }
5944}