1use super::{IceSocketWrapper, should_drop_packet};
2use crate::errors::RtcResult;
3use crate::stats::{StatsEntry, StatsId, StatsKind, StatsProvider};
4use crate::transports::PacketReceiver;
5use anyhow::Result;
6use async_trait::async_trait;
7use bytes::Bytes;
8use parking_lot::{Mutex, RwLock};
9use serde_json::json;
10use std::net::SocketAddr;
11use std::sync::atomic::{AtomicBool, AtomicU8, AtomicU32, AtomicU64, Ordering};
12use std::sync::{Arc, OnceLock, Weak};
13use tokio::sync::{mpsc, watch};
14use tracing::{debug, trace, warn};
15
16#[derive(Debug)]
41struct RtpCandidateState {
42 addr: SocketAddr,
43 #[allow(dead_code)]
44 ssrc: u32,
45 first_seq: u16,
46 last_seq: u16,
47 first_ts: u32,
48 packet_count: u8,
49 consecutive_count: u8,
51 has_marker: bool,
52}
53
54#[derive(Debug)]
56struct RtpProbationState {
57 candidates: Vec<RtpCandidateState>,
58 total_packets: u8,
59 max_packets: u8,
62}
63
64pub struct IceConn {
65 pub socket_rx: watch::Receiver<Option<IceSocketWrapper>>,
66 rtcp_socket_rx: watch::Receiver<Option<IceSocketWrapper>>,
67 pub remote_addr: RwLock<SocketAddr>,
68 pub remote_rtcp_addr: RwLock<Option<SocketAddr>>,
69 pub dtls_receiver: RwLock<Option<Weak<dyn PacketReceiver>>>,
70 pub rtp_receiver: RwLock<Option<Weak<dyn PacketReceiver>>>,
71 pub latch_on_rtp: AtomicBool,
72 pub rtp_latched: AtomicBool,
73 pub rtcp_latched: AtomicBool,
74 pub expected_ssrc: AtomicU32,
75 pub rtp_rx_count: AtomicU64,
76 pub label: Option<String>,
77 first_rtp_rx_logged: AtomicBool,
80 first_rtcp_rx_logged: AtomicBool,
83 first_out_seen: AtomicBool,
85 both_ways_logged: AtomicBool,
87 pub rx_packets: AtomicU64,
88 pub rx_bytes: AtomicU64,
89 dtls_no_receiver_drops: AtomicU64,
92 pub tx_packets: AtomicU64,
93 pub tx_bytes: AtomicU64,
94 probation: Mutex<Option<RtpProbationState>>,
98 probation_max_packets: AtomicU8,
101 deferred_send_tx: OnceLock<mpsc::UnboundedSender<(IceSocketWrapper, Vec<u8>, SocketAddr)>>,
107}
108
109impl IceConn {
110 pub fn new(
111 socket_rx: watch::Receiver<Option<IceSocketWrapper>>,
112 remote_addr: SocketAddr,
113 label: Option<String>,
114 ) -> Arc<Self> {
115 Self::new_with_rtcp(socket_rx.clone(), socket_rx, remote_addr, label, None)
116 }
117
118 pub(crate) fn new_with_rtcp(
119 socket_rx: watch::Receiver<Option<IceSocketWrapper>>,
120 rtcp_socket_rx: watch::Receiver<Option<IceSocketWrapper>>,
121 remote_addr: SocketAddr,
122 label: Option<String>,
123 probation_max_packets: Option<u8>,
124 ) -> Arc<Self> {
125 Arc::new(Self {
126 socket_rx,
127 rtcp_socket_rx,
128 remote_addr: RwLock::new(remote_addr),
129 remote_rtcp_addr: RwLock::new(None),
130 dtls_receiver: RwLock::new(None),
131 rtp_receiver: RwLock::new(None),
132 latch_on_rtp: AtomicBool::new(false),
133 rtp_latched: AtomicBool::new(false),
134 rtcp_latched: AtomicBool::new(false),
135 expected_ssrc: AtomicU32::new(0),
136 rtp_rx_count: AtomicU64::new(0),
137 label,
138 first_rtp_rx_logged: AtomicBool::new(false),
139 first_rtcp_rx_logged: AtomicBool::new(false),
140 first_out_seen: AtomicBool::new(false),
141 both_ways_logged: AtomicBool::new(false),
142 rx_packets: AtomicU64::new(0),
143 rx_bytes: AtomicU64::new(0),
144 dtls_no_receiver_drops: AtomicU64::new(0),
145 tx_packets: AtomicU64::new(0),
146 tx_bytes: AtomicU64::new(0),
147 probation: Mutex::new(None),
148 probation_max_packets: AtomicU8::new(probation_max_packets.unwrap_or(0)),
149 deferred_send_tx: OnceLock::new(),
150 })
151 }
152
153 pub fn set_probation_max_packets(&self, max: Option<u8>) {
154 self.probation_max_packets
155 .store(max.unwrap_or(0), Ordering::Relaxed);
156 }
157
158 pub fn mark_first_outbound(&self) {
161 if self.first_out_seen.swap(true, Ordering::Relaxed) {
162 return;
163 }
164 let label_str = self.label.as_deref().unwrap_or("unknown");
165 tracing::trace!("IceConn: first outbound RTP sent label={}", label_str);
166 self.maybe_log_both_ways(label_str);
167 }
168
169 fn maybe_log_both_ways(&self, label_str: &str) {
172 if self.both_ways_logged.load(Ordering::Relaxed) {
173 return;
174 }
175 let inbound_seen = self.first_rtp_rx_logged.load(Ordering::Relaxed)
176 || self.first_rtcp_rx_logged.load(Ordering::Relaxed);
177 if self.first_out_seen.load(Ordering::Relaxed)
178 && inbound_seen
179 && self
180 .both_ways_logged
181 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
182 .is_ok()
183 {
184 tracing::trace!(
185 "IceConn: media confirmed both directions (outbound + inbound) label={}",
186 label_str
187 );
188 }
189 }
190
191 pub fn enable_latch_on_rtp(&self) {
192 self.latch_on_rtp.store(true, Ordering::Relaxed);
193 let max = self.probation_max_packets.load(Ordering::Relaxed);
194 if max > 0 {
195 let mut p = self.probation.lock();
197 if p.is_none() {
198 *p = Some(RtpProbationState {
199 candidates: Vec::new(),
200 total_packets: 0,
201 max_packets: max,
202 });
203 }
204 } else {
205 self.probation.lock().take();
207 }
208 }
209
210 pub fn set_expected_ssrc(&self, ssrc: u32) {
214 self.expected_ssrc.store(ssrc, Ordering::Relaxed);
215 }
216
217 pub fn set_remote_rtcp_addr(&self, addr: Option<SocketAddr>) {
218 *self.remote_rtcp_addr.write() = addr;
219 self.rtcp_latched.store(false, Ordering::Relaxed);
220 }
221
222 pub fn local_addr(&self) -> SocketAddr {
226 let socket = self.socket_rx.borrow();
227 match socket.as_ref() {
228 Some(IceSocketWrapper::Udp(s)) => s
229 .local_addr()
230 .unwrap_or(SocketAddr::from(([0, 0, 0, 0], 0))),
231 Some(IceSocketWrapper::SharedUdp(h)) => h
232 .local_addr()
233 .unwrap_or(SocketAddr::from(([0, 0, 0, 0], 0))),
234 _ => SocketAddr::from(([0, 0, 0, 0], 0)),
235 }
236 }
237
238 pub(crate) fn set_remote_addr_from_selected_pair(
239 &self,
240 addr: SocketAddr,
241 reason: &'static str,
242 ) {
243 let current = *self.remote_addr.read();
244 if self.latch_on_rtp.load(Ordering::Relaxed)
245 && self.rtp_latched.load(Ordering::Relaxed)
246 && current != addr
247 {
248 warn!(
249 "IceConn: preserving latched RTP remote {} instead of selected-pair remote {} ({})",
250 current, addr, reason
251 );
252 return;
253 }
254
255 if current != addr {
256 debug!(
257 "IceConn: selected-pair remote changed {} -> {} ({})",
258 current, addr, reason
259 );
260 }
261 *self.remote_addr.write() = addr;
262 }
263
264 pub(crate) fn set_remote_addr_from_signaling(&self, addr: SocketAddr, reason: &'static str) {
265 self.reset_latch();
266 *self.remote_addr.write() = addr;
267 trace!(
268 "IceConn: signaling RTP remote set to {} ({}), latch reset",
269 addr, reason
270 );
271 }
272
273 pub fn reset_latch(&self) {
276 self.rtp_latched.store(false, Ordering::Relaxed);
277 self.rtcp_latched.store(false, Ordering::Relaxed);
278 let max = self.probation_max_packets.load(Ordering::Relaxed);
279 *self.probation.lock() = if self.latch_on_rtp.load(Ordering::Relaxed) && max > 0 {
280 Some(RtpProbationState {
281 candidates: Vec::new(),
282 total_packets: 0,
283 max_packets: max,
284 })
285 } else {
286 None
287 };
288 }
289
290 pub fn set_dtls_receiver(&self, receiver: Arc<dyn PacketReceiver>) {
291 *self.dtls_receiver.write() = Some(Arc::downgrade(&receiver));
292 }
293
294 pub fn set_rtp_receiver(&self, receiver: Arc<dyn PacketReceiver>) {
295 *self.rtp_receiver.write() = Some(Arc::downgrade(&receiver));
296 }
297
298 pub fn try_send(&self, buf: &[u8]) -> Result<usize> {
302 if should_drop_packet() {
303 return Ok(buf.len());
304 }
305 let socket = self.socket_rx.borrow().clone();
306 let Some(socket) = socket else {
307 let mut socket_rx = self.socket_rx.clone();
309 let socket = socket_rx.borrow_and_update().clone();
310 let Some(socket) = socket else {
311 tracing::trace!("IceConn: try_send failed - no selected socket");
312 return Err(anyhow::anyhow!("No selected socket"));
313 };
314 return self.do_try_send(socket, buf);
315 };
316 self.do_try_send(socket, buf)
317 }
318
319 fn do_try_send(&self, socket: IceSocketWrapper, buf: &[u8]) -> Result<usize> {
320 let remote = *self.remote_addr.read();
321 if remote.port() == 0 {
322 return Err(anyhow::anyhow!("Remote address not set"));
323 }
324 match &socket {
325 IceSocketWrapper::Udp(_) | IceSocketWrapper::SharedUdp(_) => {
326 let n = socket.try_send_to(buf, remote)?;
327 Ok(n)
331 }
332 _ => {
335 self.defer_async_send(socket, buf, remote);
336 Ok(buf.len())
337 }
338 }
339 }
340
341 fn defer_async_send(&self, socket: IceSocketWrapper, buf: &[u8], addr: SocketAddr) {
346 let tx = self.deferred_send_tx.get_or_init(|| {
347 let (tx, mut rx) = mpsc::unbounded_channel::<(IceSocketWrapper, Vec<u8>, SocketAddr)>();
348 tokio::spawn(async move {
349 while let Some((socket, buf, addr)) = rx.recv().await {
350 if let Err(e) = socket.send_to(&buf, addr).await {
351 debug!(
352 error = %e,
353 "IceConn: deferred async send failed (relay fast-path fallback)"
354 );
355 }
356 }
357 });
358 tx
359 });
360 if tx.send((socket, buf.to_vec(), addr)).is_err() {
361 trace!("IceConn: deferred send queue closed, dropping packet");
362 }
363 }
364
365 pub async fn send(&self, buf: &[u8]) -> Result<usize> {
366 if should_drop_packet() {
367 return Ok(buf.len());
368 }
369 let socket_rx = self.socket_rx.clone();
370 let socket_opt = socket_rx.borrow().clone();
371
372 if let Some(socket) = socket_opt {
373 let remote = *self.remote_addr.read();
374 if remote.port() == 0 {
375 return Err(anyhow::anyhow!("Remote address not set"));
376 }
377 let n = socket.send_to(buf, remote).await?;
378 self.tx_packets.fetch_add(1, Ordering::Relaxed);
379 self.tx_bytes.fetch_add(n as u64, Ordering::Relaxed);
380 Ok(n)
381 } else {
382 let mut socket_rx = self.socket_rx.clone();
384 let socket_opt = socket_rx.borrow_and_update().clone();
385 if let Some(socket) = socket_opt {
386 let remote = *self.remote_addr.read();
387 if remote.port() == 0 {
388 return Err(anyhow::anyhow!("Remote address not set"));
389 }
390 let n = socket.send_to(buf, remote).await?;
391 self.tx_packets.fetch_add(1, Ordering::Relaxed);
392 self.tx_bytes.fetch_add(n as u64, Ordering::Relaxed);
393 Ok(n)
394 } else {
395 tracing::trace!("IceConn: send failed - no selected socket");
396 Err(anyhow::anyhow!("No selected socket"))
397 }
398 }
399 }
400
401 pub async fn send_dtls_record_batch(&self, records: &[Vec<u8>]) -> Result<usize> {
404 if records.is_empty() {
405 return Ok(0);
406 }
407 if should_drop_packet() {
408 return Ok(records.iter().map(|r| r.len()).sum());
409 }
410
411 let remote = *self.remote_addr.read();
412 if remote.port() == 0 {
413 return Err(anyhow::anyhow!("Remote address not set"));
414 }
415
416 let socket_rx = self.socket_rx.clone();
417 let mut socket_opt = socket_rx.borrow().clone();
418 if socket_opt.is_none() {
419 let mut rx = self.socket_rx.clone();
420 socket_opt = rx.borrow_and_update().clone();
421 }
422
423 let Some(socket) = socket_opt else {
424 tracing::trace!("IceConn: send_dtls_record_batch failed - no selected socket");
425 return Err(anyhow::anyhow!("No selected socket"));
426 };
427
428 let total_payload: usize = records.iter().map(|r| r.len()).sum();
429 self.tx_packets
430 .fetch_add(records.len() as u64, Ordering::Relaxed);
431
432 match &socket {
433 IceSocketWrapper::TcpStream(_, write, _) => {
434 let mut framed = Vec::new();
435 for record in records {
436 if record.len() > 0xFFFF {
437 return Err(anyhow::anyhow!("DTLS record too large for TCP framing"));
438 }
439 framed.extend_from_slice(&(record.len() as u16).to_be_bytes());
440 framed.extend_from_slice(record);
441 }
442 super::tcp_write_all(write, &framed).await?;
443 self.tx_bytes
444 .fetch_add(framed.len() as u64, Ordering::Relaxed);
445 Ok(total_payload)
446 }
447 _ => {
448 let mut total = 0usize;
449 for record in records {
450 total += self.send(record).await?;
451 }
452 Ok(total)
453 }
454 }
455 }
456
457 pub async fn send_rtcp(&self, buf: &[u8]) -> Result<usize> {
458 let rtcp_addr = *self.remote_rtcp_addr.read();
459 let remote = if let Some(rtcp_addr) = rtcp_addr {
460 rtcp_addr
461 } else {
462 *self.remote_addr.read()
463 };
464
465 if remote.port() == 0 {
466 return Err(anyhow::anyhow!("Remote address not set"));
467 }
468
469 let mut socket_rx = if rtcp_addr.is_some() {
470 self.rtcp_socket_rx.clone()
471 } else {
472 self.socket_rx.clone()
473 };
474 let mut socket_opt = socket_rx.borrow().clone();
475 if socket_opt.is_none() {
476 socket_opt = socket_rx.borrow_and_update().clone();
477 }
478
479 if socket_opt.is_none() && rtcp_addr.is_some() {
480 let mut fallback_rx = self.socket_rx.clone();
481 socket_opt = fallback_rx.borrow().clone();
482 if socket_opt.is_none() {
483 socket_opt = fallback_rx.borrow_and_update().clone();
484 }
485 }
486
487 if let Some(socket) = socket_opt {
488 let n = socket.send_to(buf, remote).await?;
489 self.tx_packets.fetch_add(1, Ordering::Relaxed);
490 self.tx_bytes.fetch_add(n as u64, Ordering::Relaxed);
491 Ok(n)
492 } else {
493 tracing::trace!("IceConn: send_rtcp failed - no selected socket");
494 Err(anyhow::anyhow!("No selected socket"))
495 }
496 }
497}
498
499#[async_trait]
500impl PacketReceiver for IceConn {
501 async fn receive(&self, packet: Bytes, addr: SocketAddr, marshal_buf: &mut Vec<u8>) {
502 if packet.is_empty() {
503 return;
504 }
505
506 self.rx_packets.fetch_add(1, Ordering::Relaxed);
507 self.rx_bytes
508 .fetch_add(packet.len() as u64, Ordering::Relaxed);
509
510 let first_byte = packet[0];
511 let current_remote = *self.remote_addr.read();
513
514 let socket_is_inbound_tcp = {
518 let socket_rx = self.socket_rx.clone();
519 matches!(
520 socket_rx.borrow().as_ref(),
521 Some(IceSocketWrapper::TcpStream(_, _, _))
522 )
523 };
524 if current_remote.port() == 0 || (socket_is_inbound_tcp && current_remote != addr) {
525 *self.remote_addr.write() = addr;
526 } else if addr != current_remote {
527 tracing::trace!(
532 "IceConn: Received packet from new address {:?} (byte={}) - ignoring address change",
533 addr,
534 first_byte
535 );
536 }
537
538 if (20..64).contains(&first_byte) {
539 let receiver = {
541 let rx_lock = self.dtls_receiver.read();
542 if let Some(rx) = &*rx_lock {
543 rx.upgrade()
544 } else {
545 None
546 }
547 };
548
549 if let Some(strong_rx) = receiver {
550 strong_rx.receive(packet, addr, marshal_buf).await;
552 } else {
553 let drops = self.dtls_no_receiver_drops.fetch_add(1, Ordering::Relaxed) + 1;
554 debug!(
555 drops,
556 len = packet.len(),
557 from = %addr,
558 "IceConn: Received DTLS packet but no receiver registered — dropped"
559 );
560 }
561 } else if (128..192).contains(&first_byte) {
562 let is_rtcp = packet.len() >= 2 && (200..=211).contains(&packet[1]);
564
565 if self.latch_on_rtp.load(Ordering::Relaxed) {
566 if is_rtcp {
567 let mut remote_rtcp_addr = self.remote_rtcp_addr.write();
570 if let Some(current_rtcp_remote) = *remote_rtcp_addr
571 && addr != current_rtcp_remote
572 && !self.rtcp_latched.load(Ordering::Relaxed)
573 {
574 *remote_rtcp_addr = Some(addr);
575 self.rtcp_latched.store(true, Ordering::Relaxed);
576 }
577 } else if !self.rtp_latched.load(Ordering::Relaxed) && packet.len() >= 12 {
578 let expected = self.expected_ssrc.load(Ordering::Relaxed);
579 let pkt_ssrc =
580 u32::from_be_bytes([packet[8], packet[9], packet[10], packet[11]]);
581
582 let ssrc_ok = expected == 0 || pkt_ssrc == expected;
583
584 if ssrc_ok {
585 let seq = u16::from_be_bytes([packet[2], packet[3]]);
586 let ts = u32::from_be_bytes([packet[4], packet[5], packet[6], packet[7]]);
587 let marker = (packet[1] & 0x80) != 0;
588
589 let mut probation_guard = self.probation.lock();
590 if let Some(ref mut prob) = *probation_guard {
591 prob.total_packets = prob.total_packets.saturating_add(1);
592
593 let pos = prob.candidates.iter().position(|c| c.addr == addr);
594 if let Some(i) = pos {
595 let c = &mut prob.candidates[i];
596 if seq == c.last_seq.wrapping_add(1) {
597 c.consecutive_count = c.consecutive_count.saturating_add(1);
598 } else {
599 c.consecutive_count = 0;
601 }
602 c.last_seq = seq;
603 c.packet_count = c.packet_count.saturating_add(1);
604 if marker {
605 c.has_marker = true;
606 }
607 if ts < c.first_ts {
608 c.first_ts = ts;
609 }
610 if seq < c.first_seq {
611 c.first_seq = seq;
612 }
613 } else {
614 prob.candidates.push(RtpCandidateState {
615 addr,
616 ssrc: pkt_ssrc,
617 first_seq: seq,
618 last_seq: seq,
619 first_ts: ts,
620 packet_count: 1,
621 consecutive_count: 0,
622 has_marker: marker,
623 });
624 }
625
626 if addr != current_remote {
627 *self.remote_addr.write() = addr;
628 }
629
630 let total = prob.total_packets;
631 let winner: Option<SocketAddr>;
632
633 let marker_winner = prob
636 .candidates
637 .iter()
638 .filter(|c| c.has_marker)
639 .min_by_key(|c| c.first_seq);
640
641 if let Some(mw) = marker_winner {
642 winner = Some(mw.addr);
643 } else if total >= prob.max_packets {
644 winner = prob
648 .candidates
649 .iter()
650 .max_by(|a, b| {
651 a.packet_count
652 .cmp(&b.packet_count)
653 .then(b.first_seq.cmp(&a.first_seq))
654 })
655 .map(|c| c.addr);
656 } else {
657 winner = if total >= 3 {
661 prob.candidates
662 .iter()
663 .find(|c| c.consecutive_count >= 2)
664 .map(|c| c.addr)
665 } else {
666 None
667 };
668 }
669
670 if let Some(win_addr) = winner {
671 *probation_guard = None; drop(probation_guard);
674
675 if win_addr != current_remote {
676 *self.remote_addr.write() = win_addr;
677 }
678 self.rtp_latched.store(true, Ordering::Relaxed);
679 trace!(
680 "IceConn: RTP latched to {} after probation \
681 (expected_ssrc={}, total_obs={})",
682 win_addr, expected, total
683 );
684 }
685 } else {
686 if addr != current_remote {
690 *self.remote_addr.write() = addr;
691 }
692 self.rtp_latched.store(true, Ordering::Relaxed);
693 trace!(
694 "IceConn: RTP latched to {} immediately \
695 (expected_ssrc={})",
696 addr, expected
697 );
698 }
699 }
700 }
701 }
702 let receiver = {
703 let rx_lock = self.rtp_receiver.read();
704 if let Some(rx) = &*rx_lock {
705 rx.upgrade()
706 } else {
707 None
708 }
709 };
710
711 if let Some(strong_rx) = receiver {
712 self.rtp_rx_count.fetch_add(1, Ordering::Relaxed);
713 let label_str = self.label.as_deref().unwrap_or("unknown");
714 if is_rtcp {
715 if self
716 .first_rtcp_rx_logged
717 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
718 .is_ok()
719 {
720 tracing::debug!(
721 "IceConn: first inbound RTCP ({} bytes) from {} label={} — remote alive",
722 packet.len(),
723 addr,
724 label_str
725 );
726 }
727 } else if self
728 .first_rtp_rx_logged
729 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
730 .is_ok()
731 {
732 tracing::debug!(
733 "IceConn: first inbound RTP ({} bytes) from {} label={}",
734 packet.len(),
735 addr,
736 label_str
737 );
738 }
739 self.maybe_log_both_ways(label_str);
740 strong_rx.receive(packet, addr, marshal_buf).await;
741 } else {
742 trace!(
743 "IceConn: No RTP receiver registered for packet from {}",
744 addr
745 );
746 }
747 }
748 }
749}
750
751#[async_trait]
752impl StatsProvider for IceConn {
753 async fn collect(&self) -> RtcResult<Vec<StatsEntry>> {
754 let rx_packets = self.rx_packets.load(Ordering::Relaxed);
755 let rx_bytes = self.rx_bytes.load(Ordering::Relaxed);
756 let tx_packets = self.tx_packets.load(Ordering::Relaxed);
757 let tx_bytes = self.tx_bytes.load(Ordering::Relaxed);
758 let label = self.label.as_deref().unwrap_or("unknown");
759 let id = StatsId::new(format!("ice-conn-{}", label));
760 let entry = StatsEntry::new(id, StatsKind::Transport)
761 .with_value("label", json!(label))
762 .with_value("rxPackets", json!(rx_packets))
763 .with_value("rxBytes", json!(rx_bytes))
764 .with_value("txPackets", json!(tx_packets))
765 .with_value("txBytes", json!(tx_bytes));
766 Ok(vec![entry])
767 }
768}
769
770#[cfg(test)]
771mod tests {
772 use super::*;
773 use bytes::Bytes;
774 use std::net::{IpAddr, Ipv4Addr};
775 use tokio::io::AsyncReadExt;
776 use tokio::io::AsyncWriteExt;
777 use tokio::net::UdpSocket;
778 use tokio::sync::watch;
779
780 #[tokio::test]
781 async fn test_ice_conn_send_rtcp_mux() {
782 let socket = UdpSocket::bind("127.0.0.1:0").await.unwrap();
783 let socket_wrapper = IceSocketWrapper::Udp(Arc::new(socket));
784 let (_tx, rx) = watch::channel(Some(socket_wrapper));
785
786 let receiver = UdpSocket::bind("127.0.0.1:0").await.unwrap();
787 let receiver_addr = receiver.local_addr().unwrap();
788
789 let conn = IceConn::new(rx, receiver_addr, None);
790
791 conn.send_rtcp(b"hello").await.unwrap();
793
794 let mut buf = [0u8; 1024];
795 let (len, _) = receiver.recv_from(&mut buf).await.unwrap();
796 assert_eq!(&buf[..len], b"hello");
797 }
798
799 #[tokio::test]
804 async fn test_try_send_delivers_on_shared_udp_transport() {
805 let probe = UdpSocket::bind("127.0.0.1:0").await.unwrap();
808 let bind_addr = probe.local_addr().unwrap();
809 drop(probe);
810
811 let (_local, handle, _guard) =
812 crate::transports::ice::shared_udp::acquire(bind_addr, "fastpath-test".to_string())
813 .await
814 .unwrap();
815 let shared_socket = handle.socket().clone();
819 let (_tx, rx) = watch::channel(Some(IceSocketWrapper::SharedUdp(Arc::new(handle))));
820
821 let receiver = UdpSocket::bind("127.0.0.1:0").await.unwrap();
822 let receiver_addr = receiver.local_addr().unwrap();
823 let conn = IceConn::new(rx, receiver_addr, None);
824
825 shared_socket.writable().await.unwrap();
826 conn.try_send(b"relayed")
827 .expect("fast-path send must not fail on shared UDP");
828
829 let mut buf = [0u8; 32];
830 let (len, _) = tokio::time::timeout(
831 std::time::Duration::from_millis(500),
832 receiver.recv_from(&mut buf),
833 )
834 .await
835 .expect("shared-UDP fast-path send must deliver")
836 .unwrap();
837 assert_eq!(&buf[..len], b"relayed");
838 }
839
840 #[tokio::test]
844 async fn test_try_send_defers_on_non_udp_transport() {
845 let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
846 let listen_addr = listener.local_addr().unwrap();
847 let mut client = tokio::net::TcpStream::connect(listen_addr).await.unwrap();
848 let (server, peer) = listener.accept().await.unwrap();
849 let (read, write) = server.into_split();
850
851 let wrapper = IceSocketWrapper::TcpStream(
852 Arc::new(tokio::sync::Mutex::new(read)),
853 Arc::new(tokio::sync::Mutex::new(write)),
854 peer,
855 );
856 let (_tx, rx) = watch::channel(Some(wrapper));
857 let conn = IceConn::new(rx, peer, None);
858
859 conn.try_send(b"relayed")
861 .expect("fast-path send must not fail on non-UDP transport");
862
863 let mut header = [0u8; 2];
865 tokio::time::timeout(
866 std::time::Duration::from_millis(500),
867 tokio::io::AsyncReadExt::read_exact(&mut client, &mut header),
868 )
869 .await
870 .expect("deferred fast-path send must deliver")
871 .unwrap();
872 let n = u16::from_be_bytes(header) as usize;
873 let mut body = vec![0u8; n];
874 tokio::io::AsyncReadExt::read_exact(&mut client, &mut body)
875 .await
876 .unwrap();
877 assert_eq!(&body[..], b"relayed");
878 }
879
880 #[tokio::test]
881 async fn test_ice_conn_send_rtcp_no_mux() {
882 let rtp_socket = Arc::new(UdpSocket::bind("127.0.0.1:0").await.unwrap());
883 let rtp_socket_addr = rtp_socket.local_addr().unwrap();
884 let socket_wrapper = IceSocketWrapper::Udp(rtp_socket);
885 let (_tx, rx) = watch::channel(Some(socket_wrapper));
886
887 let rtcp_socket = Arc::new(UdpSocket::bind("127.0.0.1:0").await.unwrap());
888 let rtcp_socket_addr = rtcp_socket.local_addr().unwrap();
889 let rtcp_socket_wrapper = IceSocketWrapper::Udp(rtcp_socket);
890 let (_rtcp_tx, rtcp_rx) = watch::channel(Some(rtcp_socket_wrapper));
891
892 let rtp_receiver = UdpSocket::bind("127.0.0.1:0").await.unwrap();
893 let rtp_addr = rtp_receiver.local_addr().unwrap();
894
895 let rtcp_receiver = UdpSocket::bind("127.0.0.1:0").await.unwrap();
896 let rtcp_addr = rtcp_receiver.local_addr().unwrap();
897
898 let conn = IceConn::new_with_rtcp(rx, rtcp_rx, rtp_addr, None, None);
899 conn.set_remote_rtcp_addr(Some(rtcp_addr));
900
901 conn.send(b"rtp").await.unwrap();
903 let mut buf = [0u8; 1024];
904 let (len, rtp_src) = rtp_receiver.recv_from(&mut buf).await.unwrap();
905 assert_eq!(&buf[..len], b"rtp");
906 assert_eq!(rtp_src, rtp_socket_addr);
907
908 conn.send_rtcp(b"rtcp").await.unwrap();
910 let (len, rtcp_src) = rtcp_receiver.recv_from(&mut buf).await.unwrap();
911 assert_eq!(&buf[..len], b"rtcp");
912 assert_eq!(rtcp_src, rtcp_socket_addr);
913 }
914
915 #[tokio::test]
916 async fn test_changed_signaling_remote_resets_latch_and_retargets_send() {
917 let socket = Arc::new(UdpSocket::bind("127.0.0.1:0").await.unwrap());
918 let socket_wrapper = IceSocketWrapper::Udp(socket);
919 let (_tx, rx) = watch::channel(Some(socket_wrapper));
920
921 let old_receiver = UdpSocket::bind("127.0.0.1:0").await.unwrap();
922 let old_addr = old_receiver.local_addr().unwrap();
923 let new_receiver = UdpSocket::bind("127.0.0.1:0").await.unwrap();
924 let new_addr = new_receiver.local_addr().unwrap();
925
926 let conn = IceConn::new(rx, old_addr, None);
927 conn.enable_latch_on_rtp();
928 conn.rtp_latched.store(true, Ordering::Relaxed);
929
930 conn.set_remote_addr_from_signaling(new_addr, "test SDP endpoint change");
931
932 assert_eq!(*conn.remote_addr.read(), new_addr);
933 assert!(!conn.rtp_latched.load(Ordering::Relaxed));
934
935 conn.send(b"retargeted").await.unwrap();
936 let mut buf = [0u8; 32];
937 let (len, _) = tokio::time::timeout(
938 std::time::Duration::from_millis(100),
939 new_receiver.recv_from(&mut buf),
940 )
941 .await
942 .expect("new signaling endpoint should receive RTP")
943 .unwrap();
944 assert_eq!(&buf[..len], b"retargeted");
945 assert!(
946 tokio::time::timeout(
947 std::time::Duration::from_millis(20),
948 old_receiver.recv_from(&mut buf),
949 )
950 .await
951 .is_err(),
952 "old signaling endpoint must stop receiving after retarget"
953 );
954 }
955
956 struct NoopReceiver;
957
958 #[async_trait]
959 impl PacketReceiver for NoopReceiver {
960 async fn receive(&self, _packet: Bytes, _addr: SocketAddr, _buf: &mut Vec<u8>) {}
961 }
962
963 #[tokio::test]
964 async fn test_ice_conn_latches_remote_addr_on_rtp() {
965 let (_tx, rx) = watch::channel(None);
966 let initial_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4000);
967 let latched_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5000);
968 let conn = IceConn::new(rx, initial_addr, None);
969 conn.enable_latch_on_rtp();
970 conn.set_rtp_receiver(Arc::new(NoopReceiver));
971
972 let pkt = Bytes::from_static(&[
974 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, ]);
979 let mut marshal_buf = Vec::new();
980 conn.receive(pkt, latched_addr, &mut marshal_buf).await;
981
982 assert_eq!(*conn.remote_addr.read(), latched_addr);
983 }
984
985 #[tokio::test]
986 async fn test_rtcp_does_not_override_rtp_remote_addr() {
987 let (_tx, rx) = watch::channel(None);
988 let rtp_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4000);
989 let rtcp_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4001);
990 let conn = IceConn::new(rx, rtp_addr, None);
991 conn.enable_latch_on_rtp();
992 conn.set_rtp_receiver(Arc::new(NoopReceiver));
993 conn.set_remote_rtcp_addr(Some(rtcp_addr));
994
995 let rtp_src = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5000);
996 let rtp_pkt = Bytes::from_static(&[
998 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
999 ]);
1000 let mut marshal_buf = Vec::new();
1001 conn.receive(rtp_pkt, rtp_src, &mut marshal_buf).await;
1002 assert_eq!(*conn.remote_addr.read(), rtp_src);
1003 assert!(conn.rtp_latched.load(Ordering::Relaxed));
1004
1005 let rtcp_src = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5001);
1006 conn.receive(
1007 Bytes::from_static(&[0x80, 0xC8, 0x00, 0x00]),
1008 rtcp_src,
1009 &mut marshal_buf,
1010 )
1011 .await;
1012
1013 assert_eq!(
1014 *conn.remote_addr.read(),
1015 rtp_src,
1016 "RTCP should not override RTP remote address"
1017 );
1018 }
1019
1020 #[tokio::test]
1021 async fn test_rtcp_latches_rtcp_addr_in_non_mux_mode() {
1022 let (_tx, rx) = watch::channel(None);
1023 let rtp_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4000);
1024 let initial_rtcp_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4001);
1025 let conn = IceConn::new(rx, rtp_addr, None);
1026 conn.enable_latch_on_rtp();
1027 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1028 conn.set_remote_rtcp_addr(Some(initial_rtcp_addr));
1029
1030 let rtp_src = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5000);
1031 let rtp_pkt = Bytes::from_static(&[
1032 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
1033 ]);
1034 let mut marshal_buf = Vec::new();
1035 conn.receive(rtp_pkt, rtp_src, &mut marshal_buf).await;
1036
1037 let rtcp_src = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5001);
1038 conn.receive(
1039 Bytes::from_static(&[0x80, 0xC8, 0x00, 0x00]),
1040 rtcp_src,
1041 &mut marshal_buf,
1042 )
1043 .await;
1044
1045 assert_eq!(
1046 *conn.remote_rtcp_addr.read(),
1047 Some(rtcp_src),
1048 "RTCP should latch its own destination"
1049 );
1050 assert!(conn.rtcp_latched.load(Ordering::Relaxed));
1051 }
1052
1053 #[tokio::test]
1054 async fn test_rtcp_does_not_re_latch_after_locked() {
1055 let (_tx, rx) = watch::channel(None);
1056 let rtp_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4000);
1057 let conn = IceConn::new(rx, rtp_addr, None);
1058 conn.enable_latch_on_rtp();
1059 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1060 conn.set_remote_rtcp_addr(Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4001)));
1061
1062 let rtp_src = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5000);
1063 let rtp_pkt = Bytes::from_static(&[
1064 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
1065 ]);
1066 let mut marshal_buf = Vec::new();
1067 conn.receive(rtp_pkt, rtp_src, &mut marshal_buf).await;
1068
1069 let rtcp_src = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5001);
1070 conn.receive(
1071 Bytes::from_static(&[0x80, 0xC8, 0x00, 0x00]),
1072 rtcp_src,
1073 &mut marshal_buf,
1074 )
1075 .await;
1076 assert_eq!(*conn.remote_rtcp_addr.read(), Some(rtcp_src));
1077
1078 let rogue_rtcp_src = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 6001);
1079 conn.receive(
1080 Bytes::from_static(&[0x80, 0xC8, 0x00, 0x00]),
1081 rogue_rtcp_src,
1082 &mut marshal_buf,
1083 )
1084 .await;
1085
1086 assert_eq!(
1087 *conn.remote_rtcp_addr.read(),
1088 Some(rtcp_src),
1089 "RTCP should not re-latch after already latched"
1090 );
1091 }
1092
1093 #[tokio::test]
1094 async fn test_rtcp_ignored_in_mux_mode() {
1095 let (_tx, rx) = watch::channel(None);
1096 let rtp_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 4000);
1097 let conn = IceConn::new(rx, rtp_addr, None);
1098 conn.enable_latch_on_rtp();
1099 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1100
1101 let rtp_src = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 5000);
1102 let rtp_pkt = Bytes::from_static(&[
1103 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
1104 ]);
1105 let mut marshal_buf = Vec::new();
1106 conn.receive(rtp_pkt, rtp_src, &mut marshal_buf).await;
1107 assert_eq!(*conn.remote_addr.read(), rtp_src);
1108
1109 conn.receive(
1110 Bytes::from_static(&[0x80, 0xC8, 0x00, 0x00]),
1111 rtp_src,
1112 &mut marshal_buf,
1113 )
1114 .await;
1115 assert_eq!(*conn.remote_addr.read(), rtp_src);
1116 assert!(
1117 conn.remote_rtcp_addr.read().is_none(),
1118 "RTCP address should remain None in mux mode"
1119 );
1120 }
1121
1122 #[tokio::test]
1123 async fn test_ssrc_based_latch_ignores_port_mismatch() {
1124 let (_tx, rx) = watch::channel(None);
1128 let sdp_addr: SocketAddr = "10.17.230.54:4162".parse().unwrap();
1129 let real_addr: SocketAddr = "112.96.43.157:17687".parse().unwrap();
1130 let expected_ssrc: u32 = 787_088_145;
1131
1132 let conn = IceConn::new(rx, sdp_addr, None);
1133 conn.enable_latch_on_rtp();
1134 conn.set_expected_ssrc(expected_ssrc);
1135 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1136
1137 let mut pkt = vec![0x80u8, 0x00, 0x10, 0x98, 0x00, 0x00, 0x00, 0xa0];
1139 pkt.extend_from_slice(&expected_ssrc.to_be_bytes()); let mut pkt2 = vec![0x80u8, 0x00, 0x10, 0x99, 0x00, 0x00, 0x00, 0xa1];
1144 pkt2.extend_from_slice(&expected_ssrc.to_be_bytes());
1145 let mut marshal_buf = Vec::new();
1146 conn.receive(Bytes::from(pkt.clone()), real_addr, &mut marshal_buf)
1147 .await;
1148 conn.receive(Bytes::from(pkt2.clone()), real_addr, &mut marshal_buf)
1149 .await;
1150
1151 let mut pkt3 = vec![0x80u8, 0x00, 0x10, 0x9a, 0x00, 0x00, 0x00, 0xa2];
1153 pkt3.extend_from_slice(&expected_ssrc.to_be_bytes());
1154 conn.receive(Bytes::from(pkt3), real_addr, &mut marshal_buf)
1155 .await;
1156
1157 assert_eq!(
1158 *conn.remote_addr.read(),
1159 real_addr,
1160 "Should latch to real NAT address when SSRC matches"
1161 );
1162 assert!(
1163 conn.rtp_latched.load(Ordering::Relaxed),
1164 "rtp_latched should be set after SSRC match"
1165 );
1166 }
1167
1168 #[tokio::test]
1169 async fn test_ssrc_based_latch_ignores_wrong_ssrc() {
1170 let (_tx, rx) = watch::channel(None);
1172 let sdp_addr: SocketAddr = "10.17.230.54:4162".parse().unwrap();
1173 let rogue_addr: SocketAddr = "1.2.3.4:9999".parse().unwrap();
1174 let expected_ssrc: u32 = 787_088_145;
1175 let wrong_ssrc: u32 = 99_999_999;
1176
1177 let conn = IceConn::new(rx, sdp_addr, None);
1178 conn.enable_latch_on_rtp();
1179 conn.set_expected_ssrc(expected_ssrc);
1180 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1181
1182 let mut pkt = vec![0x80u8, 0x00, 0x10, 0x98, 0x00, 0x00, 0x00, 0xa0];
1183 pkt.extend_from_slice(&wrong_ssrc.to_be_bytes());
1184
1185 let mut marshal_buf = Vec::new();
1186 conn.receive(Bytes::from(pkt), rogue_addr, &mut marshal_buf)
1187 .await;
1188
1189 assert_eq!(
1190 *conn.remote_addr.read(),
1191 sdp_addr,
1192 "Should NOT latch when SSRC does not match"
1193 );
1194 assert!(
1195 !conn.rtp_latched.load(Ordering::Relaxed),
1196 "rtp_latched should remain false for wrong SSRC"
1197 );
1198 }
1199
1200 #[tokio::test]
1201 async fn test_address_based_latch_fallback_when_no_expected_ssrc() {
1202 let (_tx, rx) = watch::channel(None);
1205 let initial_addr: SocketAddr = "10.0.0.1:4000".parse().unwrap();
1206 let new_addr: SocketAddr = "10.0.0.2:5000".parse().unwrap();
1207
1208 let conn = IceConn::new(rx, initial_addr, None);
1209 conn.enable_latch_on_rtp();
1210 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1211 for seq in 1u16..=3 {
1215 let pkt = Bytes::from(vec![
1216 0x80,
1217 0x00,
1218 (seq >> 8) as u8,
1219 seq as u8,
1220 0x00,
1221 0x00,
1222 0x00,
1223 seq as u8,
1224 0x00,
1225 0x00,
1226 0x01,
1227 0x23,
1228 ]);
1229 let mut marshal_buf = Vec::new();
1230 conn.receive(pkt, new_addr, &mut marshal_buf).await;
1231 }
1232
1233 assert_eq!(*conn.remote_addr.read(), new_addr);
1234 assert!(conn.rtp_latched.load(Ordering::Relaxed));
1235 }
1236
1237 #[tokio::test]
1243 async fn test_probation_marker_wins_over_first_arriving_packet() {
1244 let (_tx, rx) = watch::channel(None);
1245 let sdp_addr: SocketAddr = "223.104.80.120:4000".parse().unwrap();
1246 let port_4114: SocketAddr = "223.104.80.120:4114".parse().unwrap();
1247 let port_4014: SocketAddr = "223.104.80.120:4014".parse().unwrap();
1248 let ssrc: u32 = 0x6c0d_1ca5;
1249
1250 let conn = IceConn::new(rx, sdp_addr, None);
1251 conn.set_probation_max_packets(Some(6));
1252 conn.enable_latch_on_rtp();
1253 conn.set_expected_ssrc(ssrc);
1254 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1255
1256 let mut pkt_4114 = vec![0x80u8, 0x08, 0x53, 0xCA, 0x00, 0x00, 0x00, 0xA0];
1258 pkt_4114.extend_from_slice(&ssrc.to_be_bytes());
1259 let mut marshal_buf = Vec::new();
1260 conn.receive(Bytes::from(pkt_4114), port_4114, &mut marshal_buf)
1261 .await;
1262
1263 assert!(
1265 !conn.rtp_latched.load(Ordering::Relaxed),
1266 "Should not latch after just one packet with no marker"
1267 );
1268
1269 let mut pkt_4014 = vec![0x80u8, 0x88, 0x53, 0xC9, 0x00, 0x00, 0x00, 0xA0];
1271 pkt_4014.extend_from_slice(&ssrc.to_be_bytes());
1272 conn.receive(Bytes::from(pkt_4014), port_4014, &mut marshal_buf)
1273 .await;
1274
1275 assert!(
1276 conn.rtp_latched.load(Ordering::Relaxed),
1277 "Should latch after marker packet"
1278 );
1279 assert_eq!(
1280 *conn.remote_addr.read(),
1281 port_4014,
1282 "Should latch to port 4014 (marker=true), not port 4114 (first arrived)"
1283 );
1284 }
1285
1286 #[tokio::test]
1289 async fn test_probation_consecutive_dominance() {
1290 let (_tx, rx) = watch::channel(None);
1291 let sdp_addr: SocketAddr = "10.0.0.1:4000".parse().unwrap();
1292 let real_src: SocketAddr = "10.0.0.1:5000".parse().unwrap();
1293 let stray_src: SocketAddr = "10.0.0.1:5001".parse().unwrap();
1294
1295 let conn = IceConn::new(rx, sdp_addr, None);
1296 conn.set_probation_max_packets(Some(6));
1297 conn.enable_latch_on_rtp();
1298 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1299
1300 let stray = Bytes::from(vec![
1302 0x80, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x02,
1303 ]);
1304 let mut marshal_buf = Vec::new();
1305 conn.receive(stray, stray_src, &mut marshal_buf).await;
1306
1307 for seq in 1u16..=3 {
1309 let pkt = Bytes::from(vec![
1310 0x80, 0x00, 0x00, seq as u8, 0x00, 0x00, 0x00, seq as u8, 0x00, 0x00, 0x00, 0x01,
1311 ]);
1312 conn.receive(pkt, real_src, &mut marshal_buf).await;
1313 }
1314
1315 assert!(
1316 conn.rtp_latched.load(Ordering::Relaxed),
1317 "Should latch after consecutive dominance"
1318 );
1319 assert_eq!(
1320 *conn.remote_addr.read(),
1321 real_src,
1322 "Should latch to the source with consecutive packets"
1323 );
1324 }
1325
1326 #[tokio::test]
1329 async fn test_probation_timeout_fallback_selects_dominant() {
1330 let (_tx, rx) = watch::channel(None);
1331 let sdp_addr: SocketAddr = "10.0.0.1:4000".parse().unwrap();
1332 let dominant: SocketAddr = "10.0.0.1:5000".parse().unwrap();
1333 let minor: SocketAddr = "10.0.0.1:5001".parse().unwrap();
1334
1335 let probation_max = 6u8;
1336 let conn = IceConn::new(rx, sdp_addr, None);
1337 conn.set_probation_max_packets(Some(probation_max));
1338 conn.enable_latch_on_rtp();
1339 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1340
1341 let minor_pkt = Bytes::from(vec![
1343 0x80, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x02,
1344 ]);
1345 let mut marshal_buf = Vec::new();
1346 conn.receive(minor_pkt, minor, &mut marshal_buf).await;
1347
1348 for i in 0..(probation_max - 1) {
1350 let seq = i * 2 + 10;
1353 let pkt = Bytes::from(vec![
1354 0x80, 0x00, 0x00, seq, 0x00, 0x00, 0x00, seq, 0x00, 0x00, 0x00, 0x01,
1355 ]);
1356 conn.receive(pkt, dominant, &mut marshal_buf).await;
1357 }
1358
1359 assert!(
1360 conn.rtp_latched.load(Ordering::Relaxed),
1361 "Should latch after PROBATION_MAX_PACKETS total packets"
1362 );
1363 assert_eq!(
1364 *conn.remote_addr.read(),
1365 dominant,
1366 "Should latch to source with most packets"
1367 );
1368 }
1369
1370 #[tokio::test]
1373 async fn test_probation_latch_is_sticky_after_commit() {
1374 let (_tx, rx) = watch::channel(None);
1375 let sdp_addr: SocketAddr = "10.0.0.1:4000".parse().unwrap();
1376 let good_src: SocketAddr = "10.0.0.1:5000".parse().unwrap();
1377 let rogue_src: SocketAddr = "10.0.0.1:6000".parse().unwrap();
1378
1379 let conn = IceConn::new(rx, sdp_addr, None);
1380 conn.set_probation_max_packets(Some(6));
1381 conn.enable_latch_on_rtp();
1382 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1383
1384 let pkt = Bytes::from(vec![
1386 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
1387 ]);
1388 let mut marshal_buf = Vec::new();
1389 conn.receive(pkt, good_src, &mut marshal_buf).await;
1390 assert!(conn.rtp_latched.load(Ordering::Relaxed));
1391 assert_eq!(*conn.remote_addr.read(), good_src);
1392
1393 for seq in 2u8..=5 {
1395 let rogue_pkt = Bytes::from(vec![
1396 0x80, 0x00, 0x00, seq, 0x00, 0x00, 0x00, seq, 0x00, 0x00, 0x00, 0x99,
1397 ]);
1398 conn.receive(rogue_pkt, rogue_src, &mut marshal_buf).await;
1399 }
1400 assert_eq!(
1401 *conn.remote_addr.read(),
1402 good_src,
1403 "Latched address must not change after latch is committed"
1404 );
1405 }
1406
1407 #[tokio::test]
1410 async fn test_reset_latch_allows_re_latching() {
1411 let (_tx, rx) = watch::channel(None);
1412 let sdp_addr: SocketAddr = "10.0.0.1:4000".parse().unwrap();
1413 let first_src: SocketAddr = "10.0.0.1:5000".parse().unwrap();
1414 let second_src: SocketAddr = "10.0.0.2:5000".parse().unwrap();
1415
1416 let conn = IceConn::new(rx, sdp_addr, None);
1417 conn.set_probation_max_packets(Some(6));
1418 conn.enable_latch_on_rtp();
1419 conn.set_rtp_receiver(Arc::new(NoopReceiver));
1420
1421 let pkt = Bytes::from(vec![
1422 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
1423 ]);
1424 let mut marshal_buf = Vec::new();
1425 conn.receive(pkt.clone(), first_src, &mut marshal_buf).await;
1426 assert_eq!(*conn.remote_addr.read(), first_src);
1427
1428 conn.reset_latch();
1429 assert!(!conn.rtp_latched.load(Ordering::Relaxed));
1430
1431 let pkt2 = Bytes::from(vec![
1433 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
1434 ]);
1435 conn.receive(pkt2, second_src, &mut marshal_buf).await;
1436 assert_eq!(
1437 *conn.remote_addr.read(),
1438 second_src,
1439 "Should re-latch to new source after reset_latch()"
1440 );
1441 }
1442
1443 async fn tcp_loopback_pair() -> (tokio::net::TcpStream, IceSocketWrapper) {
1450 let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
1451 let server_addr = listener.local_addr().unwrap();
1452
1453 let client_stream = tokio::net::TcpStream::connect(server_addr).await.unwrap();
1454 let (server_stream, _) = listener.accept().await.unwrap();
1455
1456 let wrapper = {
1457 let (read, write) = client_stream.into_split();
1458 IceSocketWrapper::TcpStream(
1459 Arc::new(tokio::sync::Mutex::new(read)),
1460 Arc::new(tokio::sync::Mutex::new(write)),
1461 server_addr,
1462 )
1463 };
1464
1465 (server_stream, wrapper)
1466 }
1467
1468 #[tokio::test]
1471 async fn test_tcp_rfc4571_framing_roundtrip() {
1472 let (mut server_stream, wrapper) = tcp_loopback_pair().await;
1473
1474 let payload = b"hello rfc4571";
1475 let len = payload.len() as u16;
1476 let mut expected_frame = Vec::with_capacity(2 + payload.len());
1477 expected_frame.extend_from_slice(&len.to_be_bytes());
1478 expected_frame.extend_from_slice(payload);
1479
1480 wrapper
1482 .send_to(payload, server_stream.local_addr().unwrap())
1483 .await
1484 .unwrap();
1485
1486 let mut len_buf = [0u8; 2];
1488 let s = &mut server_stream;
1489 s.read_exact(&mut len_buf).await.unwrap();
1490 let frame_len = u16::from_be_bytes(len_buf) as usize;
1491 let mut frame = vec![0u8; frame_len];
1492 s.read_exact(&mut frame).await.unwrap();
1493 assert_eq!(&frame, payload);
1494 }
1495
1496 #[tokio::test]
1499 async fn test_tcp_rfc4571_multiple_writes() {
1500 let (mut server_stream, wrapper) = tcp_loopback_pair().await;
1501
1502 let msgs: &[&[u8]] = &[b"msg-a", b"msg-bb", b"msg-ccc"];
1503 for msg in msgs {
1504 wrapper
1505 .send_to(msg, server_stream.local_addr().unwrap())
1506 .await
1507 .unwrap();
1508 }
1509
1510 let s = &mut server_stream;
1511 for expected in msgs {
1512 let mut len_buf = [0u8; 2];
1513 s.read_exact(&mut len_buf).await.unwrap();
1514 let frame_len = u16::from_be_bytes(len_buf) as usize;
1515 let mut frame = vec![0u8; frame_len];
1516 s.read_exact(&mut frame).await.unwrap();
1517 assert_eq!(&frame, expected);
1518 }
1519 }
1520
1521 #[tokio::test]
1524 async fn test_tcp_recv_from_rfc4571() {
1525 let (mut server_stream, wrapper) = tcp_loopback_pair().await;
1526 let server_addr = server_stream.local_addr().unwrap();
1527
1528 let payload = b"recv-test-payload";
1529 let len = payload.len() as u16;
1530 let mut frame = Vec::with_capacity(2 + payload.len());
1531 frame.extend_from_slice(&len.to_be_bytes());
1532 frame.extend_from_slice(payload);
1533
1534 server_stream.writable().await.unwrap();
1536 let s = &mut server_stream;
1537 s.write_all(&frame).await.unwrap();
1538
1539 let mut buf = [0u8; 2048];
1541 let (n, addr) = wrapper.recv_from(&mut buf).await.unwrap();
1542 assert_eq!(&buf[..n], payload);
1543 assert_eq!(addr, server_addr);
1544 }
1545
1546 #[tokio::test]
1549 async fn test_send_dtls_record_batch_tcp() {
1550 let (mut server_stream, wrapper) = tcp_loopback_pair().await;
1551 let server_addr = server_stream.local_addr().unwrap();
1552
1553 let (socket_tx, socket_rx) = watch::channel(Some(wrapper));
1554 let conn = IceConn::new(socket_rx, server_addr, Some("test-tcp".into()));
1555 drop(socket_tx);
1556
1557 let records: Vec<Vec<u8>> = vec![
1558 b"dtls-record-1".to_vec(),
1559 b"dtls-record-22".to_vec(),
1560 b"dtls-record-333".to_vec(),
1561 ];
1562
1563 conn.send_dtls_record_batch(&records).await.unwrap();
1564
1565 let s = &mut server_stream;
1566 for expected in &records {
1567 let mut len_buf = [0u8; 2];
1568 s.read_exact(&mut len_buf).await.unwrap();
1569 let frame_len = u16::from_be_bytes(len_buf) as usize;
1570 let mut frame = vec![0u8; frame_len];
1571 s.read_exact(&mut frame).await.unwrap();
1572 assert_eq!(&frame, expected.as_slice());
1573 }
1574 }
1575
1576 #[tokio::test]
1579 async fn test_send_dtls_record_batch_udp_fallback() {
1580 let udp = Arc::new(tokio::net::UdpSocket::bind("127.0.0.1:0").await.unwrap());
1581 let wrapper = IceSocketWrapper::Udp(udp.clone());
1582 let (socket_tx, socket_rx) = watch::channel(Some(wrapper));
1583
1584 let receiver = tokio::net::UdpSocket::bind("127.0.0.1:0").await.unwrap();
1585 let receiver_addr = receiver.local_addr().unwrap();
1586
1587 let conn = IceConn::new(socket_rx, receiver_addr, None);
1588 drop(socket_tx);
1589
1590 let records: Vec<Vec<u8>> = vec![b"rec-a".to_vec(), b"rec-b".to_vec()];
1591 conn.send_dtls_record_batch(&records).await.unwrap();
1592
1593 let mut buf = [0u8; 2048];
1595 for expected in &records {
1596 let (len, _) = receiver.recv_from(&mut buf).await.unwrap();
1597 assert_eq!(&buf[..len], expected.as_slice());
1598 }
1599 }
1600}