File
Blob: firmware/vendor/str0m/tests/ice-remote-binding-keepalive.rs
| 1 | use std::net::Ipv4Addr; |
| 2 | use std::time::Duration; |
| 3 | |
| 4 | use netem::NetemConfig; |
| 5 | use str0m::{Event, IceConnectionState, RtcError}; |
| 6 | |
| 7 | mod common; |
| 8 | use common::{Peer, TestRtc, init_crypto_default, init_log, progress}; |
| 9 | |
| 10 | /// Test that candidate pairs are kept alive based on incoming binding requests, |
| 11 | /// even when outgoing binding requests are not being responded to. |
| 12 | /// |
| 13 | /// This specifically tests the fix for issue #846 where Chrome v144+ would cause |
| 14 | /// disconnections when not using ICE Lite mode. The fix ensures that |
| 15 | /// `is_still_possible()` considers recently received binding requests as evidence |
| 16 | /// of connectivity, similar to how ICE Lite mode works. |
| 17 | #[test] |
| 18 | pub fn pair_kept_alive_by_remote_binding_requests() -> Result<(), RtcError> { |
| 19 | init_log(); |
| 20 | init_crypto_default(); |
| 21 | |
| 22 | // Create two non-ICE-lite peers |
| 23 | let mut l = TestRtc::new(Peer::Left); |
| 24 | let mut r = TestRtc::new(Peer::Right); |
| 25 | |
| 26 | // Add some latency to simulate real network conditions |
| 27 | l.set_netem(NetemConfig::new().latency(Duration::from_millis(10))); |
| 28 | r.set_netem(NetemConfig::new().latency(Duration::from_millis(10))); |
| 29 | |
| 30 | l.add_host_candidate((Ipv4Addr::new(1, 1, 1, 1), 1000).into()); |
| 31 | r.add_host_candidate((Ipv4Addr::new(2, 2, 2, 2), 2000).into()); |
| 32 | |
| 33 | let mut change = l.sdp_api(); |
| 34 | change.add_channel("ch".into()); |
| 35 | let (offer, pending) = change.apply().unwrap(); |
| 36 | let answer = r.sdp_api().accept_offer(offer)?; |
| 37 | l.sdp_api().accept_answer(pending, answer)?; |
| 38 | |
| 39 | // First, establish the connection |
| 40 | loop { |
| 41 | if l.duration() > Duration::from_secs(5) { |
| 42 | panic!("Timeout waiting for initial connection"); |
| 43 | } |
| 44 | |
| 45 | if l.is_connected() && r.is_connected() { |
| 46 | break; |
| 47 | } |
| 48 | |
| 49 | progress(&mut l, &mut r)?; |
| 50 | } |
| 51 | |
| 52 | // Now continue running for a while to ensure the connection stays stable |
| 53 | // This tests that the pairs are not prematurely pruned |
| 54 | let stable_start = l.duration(); |
| 55 | loop { |
| 56 | if l.duration() - stable_start > Duration::from_secs(3) { |
| 57 | // Connection remained stable for 3 seconds |
| 58 | break; |
| 59 | } |
| 60 | |
| 61 | let l_disconnected = l.events.iter().any(|(_, e)| { |
| 62 | matches!( |
| 63 | e, |
| 64 | Event::IceConnectionStateChange(IceConnectionState::Disconnected) |
| 65 | ) |
| 66 | }); |
| 67 | let r_disconnected = r.events.iter().any(|(_, e)| { |
| 68 | matches!( |
| 69 | e, |
| 70 | Event::IceConnectionStateChange(IceConnectionState::Disconnected) |
| 71 | ) |
| 72 | }); |
| 73 | |
| 74 | if l_disconnected || r_disconnected { |
| 75 | panic!("Connection was unexpectedly disconnected during stability test"); |
| 76 | } |
| 77 | |
| 78 | progress(&mut l, &mut r)?; |
| 79 | } |
| 80 | |
| 81 | Ok(()) |
| 82 | } |