1use crate::rlc_fec::{RepairSymbol, RlcDecoder, RlcEncoder};
40use std::collections::{BTreeMap, HashMap, HashSet};
41use std::io;
42use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
43use std::time::{Duration, Instant};
44
45const STREAM: u8 = 20;
46const STREAM_REPAIR: u8 = 21;
47const STREAM_NAK: u8 = 22;
48const STREAM_ACK: u8 = 23;
49const STREAM_FIN: u8 = 24;
50
51const STREAM_HDR: usize = 1 + 8 + 4 + 4;
54const REPAIR_HDR: usize = 1 + 8 + 4 + 4 + 4 + 2 + 1;
57const FIN_LEN: usize = 1 + 8 + 4 + 4 + 2;
59const ACK_LEN: usize = 1 + 8 + 4 + 4;
61
62#[derive(Clone, Copy, PartialEq, Eq, Debug)]
64pub enum Protection {
65 Protected,
68 Bulk,
70}
71
72pub fn recommend_protection(loss: f32) -> Protection {
75 if loss > 0.01 {
76 Protection::Protected
77 } else {
78 Protection::Bulk
79 }
80}
81
82#[derive(Clone, Debug)]
84pub struct StreamData {
85 pub stream_id: u32,
87 pub data: Vec<u8>,
89 pub fin: bool,
91}
92
93fn derive_conn_id(local_port: u16) -> u64 {
96 let nanos = std::time::SystemTime::now()
97 .duration_since(std::time::UNIX_EPOCH)
98 .map(|d| d.as_nanos() as u64)
99 .unwrap_or(0);
100 let mut x = nanos ^ ((local_port as u64) << 48);
101 x = (x ^ (x >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
102 x = (x ^ (x >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
103 x ^ (x >> 31)
104}
105
106fn set_buffers(sock: &UdpSocket) {
107 let s = socket2::SockRef::from(sock);
108 s.set_recv_buffer_size(4 * 1024 * 1024).ok();
109 s.set_send_buffer_size(4 * 1024 * 1024).ok();
110}
111
112struct SendStream {
117 protection: Protection,
118 enc: Option<RlcEncoder>,
119 sent: BTreeMap<u32, Vec<u8>>,
121 next_source_id: u32,
122 acked_through: u32,
124 pending: Vec<u8>,
126 fin_info: Option<(u32, u16)>,
128}
129
130impl SendStream {
131 fn outstanding(&self) -> u32 {
132 self.sent.len() as u32
133 }
134 fn fully_acked(&self) -> bool {
135 match self.fin_info {
136 Some((final_sid, _)) => self.acked_through > final_sid,
137 None => false,
138 }
139 }
140}
141
142pub struct StreamMuxSender {
144 sock: UdpSocket,
145 peer: SocketAddr,
146 cid: u64,
147 symbol_len: usize,
148 streams: HashMap<u32, SendStream>,
149 conn_window: u32,
151 per_stream_window: u32,
153 rlc_window: usize,
155 rlc_step: usize,
156 rlc_dt: u8,
157 last_fin_resend: Instant,
159}
160
161impl StreamMuxSender {
162 pub fn bind<A: ToSocketAddrs>(
166 local: A,
167 peer: SocketAddr,
168 symbol_len: usize,
169 conn_window: u32,
170 per_stream_window: u32,
171 ) -> io::Result<Self> {
172 let sock = UdpSocket::bind(local)?;
173 sock.set_nonblocking(true)?;
174 set_buffers(&sock);
175 let cid = derive_conn_id(sock.local_addr().map(|a| a.port()).unwrap_or(0));
176 Ok(Self {
177 sock,
178 peer,
179 cid,
180 symbol_len,
181 streams: HashMap::new(),
182 conn_window: conn_window.max(1),
183 per_stream_window: per_stream_window.max(1),
184 rlc_window: 32,
185 rlc_step: 4,
186 rlc_dt: 15,
187 last_fin_resend: Instant::now(),
188 })
189 }
190
191 pub fn conn_id(&self) -> u64 {
193 self.cid
194 }
195
196 pub fn stream_protection(&self, stream_id: u32) -> Option<Protection> {
198 self.streams.get(&stream_id).map(|s| s.protection)
199 }
200
201 pub fn local_addr(&self) -> io::Result<SocketAddr> {
203 self.sock.local_addr()
204 }
205
206 pub fn open_stream(&mut self, stream_id: u32, protection: Protection) {
209 let (w, s, d) = (self.rlc_window, self.rlc_step, self.rlc_dt);
210 let symbol_len = self.symbol_len;
211 self.streams.entry(stream_id).or_insert_with(|| SendStream {
212 protection,
213 enc: match protection {
214 Protection::Protected => Some(RlcEncoder::new(w, s, d, symbol_len)),
215 Protection::Bulk => None,
216 },
217 sent: BTreeMap::new(),
218 next_source_id: 0,
219 acked_through: 0,
220 pending: Vec::new(),
221 fin_info: None,
222 });
223 }
224
225 fn total_outstanding(&self) -> u32 {
226 self.streams.values().map(|s| s.outstanding()).sum()
227 }
228
229 pub fn write(&mut self, stream_id: u32, data: &[u8], fin: bool) -> io::Result<()> {
234 if !self.streams.contains_key(&stream_id) {
235 self.open_stream(stream_id, Protection::Bulk);
236 }
237 let chunk = self.symbol_len;
238 self.streams.get_mut(&stream_id).unwrap().pending.extend_from_slice(data);
240 loop {
241 let have = self.streams.get(&stream_id).unwrap().pending.len();
242 if have < chunk {
243 break;
244 }
245 let sym: Vec<u8> = self
246 .streams
247 .get_mut(&stream_id)
248 .unwrap()
249 .pending
250 .drain(..chunk)
251 .collect();
252 self.send_symbol(stream_id, &sym)?;
253 }
254 if fin {
255 let tail: Vec<u8> = std::mem::take(&mut self.streams.get_mut(&stream_id).unwrap().pending);
257 let final_len = tail.len() as u16;
258 let final_sid = self.streams.get(&stream_id).unwrap().next_source_id;
259 self.send_symbol(stream_id, &tail)?;
260 self.streams.get_mut(&stream_id).unwrap().fin_info = Some((final_sid, final_len));
261 self.wire_fin(stream_id, final_sid, final_len)?;
262 }
263 Ok(())
264 }
265
266 fn send_symbol(&mut self, stream_id: u32, payload: &[u8]) -> io::Result<()> {
268 let start = Instant::now();
269 loop {
270 self.pump()?;
271 let per_stream_ok = self
272 .streams
273 .get(&stream_id)
274 .map(|s| s.outstanding() < self.per_stream_window)
275 .unwrap_or(true);
276 let conn_ok = self.total_outstanding() < self.conn_window;
277 if per_stream_ok && conn_ok {
278 break;
279 }
280 if start.elapsed() > Duration::from_secs(60) {
281 break;
282 }
283 std::thread::sleep(Duration::from_micros(50));
284 }
285
286 let mut sym = vec![0u8; self.symbol_len];
287 sym[..payload.len()].copy_from_slice(payload);
288
289 let stream = self.streams.get_mut(&stream_id).unwrap();
290 let sid = stream.next_source_id;
291 stream.next_source_id += 1;
292 stream.sent.insert(sid, sym.clone());
293 let repair = stream.enc.as_mut().and_then(|e| e.push_source(&sym).1);
294
295 self.wire_stream(stream_id, sid, &sym)?;
296 if let Some(r) = repair {
297 self.wire_repair(stream_id, &r)?;
298 }
299 Ok(())
300 }
301
302 fn wire_stream(&self, stream_id: u32, sid: u32, sym: &[u8]) -> io::Result<()> {
303 let mut pkt = Vec::with_capacity(STREAM_HDR + sym.len());
304 pkt.push(STREAM);
305 pkt.extend_from_slice(&self.cid.to_le_bytes());
306 pkt.extend_from_slice(&stream_id.to_le_bytes());
307 pkt.extend_from_slice(&sid.to_le_bytes());
308 pkt.extend_from_slice(sym);
309 self.sock.send_to(&pkt, self.peer)?;
310 Ok(())
311 }
312
313 fn wire_fin(&self, stream_id: u32, final_sid: u32, final_len: u16) -> io::Result<()> {
314 let mut pkt = Vec::with_capacity(FIN_LEN);
315 pkt.push(STREAM_FIN);
316 pkt.extend_from_slice(&self.cid.to_le_bytes());
317 pkt.extend_from_slice(&stream_id.to_le_bytes());
318 pkt.extend_from_slice(&final_sid.to_le_bytes());
319 pkt.extend_from_slice(&final_len.to_le_bytes());
320 self.sock.send_to(&pkt, self.peer)?;
321 Ok(())
322 }
323
324 fn wire_repair(&self, stream_id: u32, r: &RepairSymbol) -> io::Result<()> {
325 let mut pkt = Vec::with_capacity(REPAIR_HDR + r.payload.len());
326 pkt.push(STREAM_REPAIR);
327 pkt.extend_from_slice(&self.cid.to_le_bytes());
328 pkt.extend_from_slice(&stream_id.to_le_bytes());
329 pkt.extend_from_slice(&r.repair_key.to_le_bytes());
330 pkt.extend_from_slice(&r.first_source_id.to_le_bytes());
331 pkt.extend_from_slice(&r.window_size.to_le_bytes());
332 pkt.push(r.dt);
333 pkt.extend_from_slice(&r.payload);
334 self.sock.send_to(&pkt, self.peer)?;
335 Ok(())
336 }
337
338 pub fn pump(&mut self) -> io::Result<()> {
344 let mut buf = vec![0u8; self.symbol_len + STREAM_HDR + 64];
345 loop {
346 match self.sock.recv_from(&mut buf) {
347 Ok((n, _)) if n >= 1 => self.handle_feedback(&buf[..n])?,
348 Ok(_) => {}
349 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
350 Err(ref e) if e.kind() == io::ErrorKind::TimedOut => break,
351 Err(ref e) if e.kind() == io::ErrorKind::ConnectionReset => break,
352 Err(e) => return Err(e),
353 }
354 }
355 if self.last_fin_resend.elapsed() >= Duration::from_millis(5) {
356 let pending: Vec<(u32, u32, u16)> = self
357 .streams
358 .iter()
359 .filter(|(_, s)| s.fin_info.is_some() && !s.fully_acked())
360 .map(|(&id, s)| {
361 let (fs, fl) = s.fin_info.unwrap();
362 (id, fs, fl)
363 })
364 .collect();
365 for (id, fs, fl) in pending {
366 self.wire_fin(id, fs, fl)?;
367 }
368 self.last_fin_resend = Instant::now();
369 }
370 Ok(())
371 }
372
373 fn handle_feedback(&mut self, m: &[u8]) -> io::Result<()> {
374 if m.len() < 13 {
375 return Ok(());
376 }
377 let cid = u64::from_le_bytes(m[1..9].try_into().unwrap());
378 if cid != self.cid {
379 return Ok(());
380 }
381 let stream_id = u32::from_le_bytes(m[9..13].try_into().unwrap());
382 match m[0] {
383 STREAM_NAK => {
384 let mut off = 13;
385 let mut want = Vec::new();
386 while off + 4 <= m.len() {
387 want.push(u32::from_le_bytes(m[off..off + 4].try_into().unwrap()));
388 off += 4;
389 }
390 let mut resend_fin = false;
391 for sid in want {
392 let frame = self
393 .streams
394 .get(&stream_id)
395 .and_then(|s| s.sent.get(&sid))
396 .cloned();
397 if let Some(sym) = frame {
398 self.wire_stream(stream_id, sid, &sym)?;
399 }
400 if let Some((final_sid, _)) =
402 self.streams.get(&stream_id).and_then(|s| s.fin_info)
403 && sid >= final_sid
404 {
405 resend_fin = true;
406 }
407 }
408 if resend_fin
409 && let Some((final_sid, final_len)) =
410 self.streams.get(&stream_id).and_then(|s| s.fin_info)
411 {
412 self.wire_fin(stream_id, final_sid, final_len)?;
413 }
414 }
415 STREAM_ACK if m.len() >= ACK_LEN => {
416 let through = u32::from_le_bytes(m[13..17].try_into().unwrap());
417 if let Some(s) = self.streams.get_mut(&stream_id)
418 && through > s.acked_through
419 {
420 s.acked_through = through;
421 s.sent.retain(|&sid, _| sid >= through);
422 if let Some(e) = s.enc.as_mut() {
423 e.forget_below(through);
424 }
425 }
426 }
427 _ => {}
428 }
429 Ok(())
430 }
431
432 pub fn flush(&mut self, timeout: Duration) -> io::Result<bool> {
436 let start = Instant::now();
437 loop {
438 self.pump()?;
439 let pending: Vec<(u32, u32, u16)> = self
440 .streams
441 .iter()
442 .filter(|(_, s)| !s.fully_acked() && s.fin_info.is_some())
443 .map(|(&id, s)| {
444 let (fs, fl) = s.fin_info.unwrap();
445 (id, fs, fl)
446 })
447 .collect();
448 let done = self.total_outstanding() == 0
449 && self.streams.values().all(|s| s.fin_info.is_none() || s.fully_acked());
450 if done || start.elapsed() >= timeout {
451 return Ok(done);
452 }
453 for (id, fs, fl) in pending {
454 self.wire_fin(id, fs, fl)?;
455 }
456 std::thread::sleep(Duration::from_micros(200));
457 }
458 }
459}
460
461struct RecvStream {
466 protection: Protection,
467 dec: Option<RlcDecoder>,
468 chunks: BTreeMap<u32, Vec<u8>>,
470 delivered_through: u32,
472 gap_since: BTreeMap<u32, Instant>,
474 highest_seen: u32,
475 final_info: Option<(u32, u16)>,
477 fin_delivered: bool,
478}
479
480pub struct StreamMuxReceiver {
482 sock: UdpSocket,
483 peer: Option<SocketAddr>,
484 cid: Option<u64>,
485 symbol_len: usize,
486 streams: HashMap<u32, RecvStream>,
487 last_nak: Instant,
488 debug_loss: HashMap<u32, (u32, u64)>,
490 dropped_once: HashSet<(u32, u32)>,
494 fec_recovered: u64,
496 naks_sent: u64,
497}
498
499impl StreamMuxReceiver {
500 pub fn bind<A: ToSocketAddrs>(local: A, symbol_len: usize) -> io::Result<Self> {
502 let sock = UdpSocket::bind(local)?;
503 sock.set_nonblocking(true)?;
504 set_buffers(&sock);
505 Ok(Self {
506 sock,
507 peer: None,
508 cid: None,
509 symbol_len,
510 streams: HashMap::new(),
511 last_nak: Instant::now(),
512 debug_loss: HashMap::new(),
513 dropped_once: HashSet::new(),
514 fec_recovered: 0,
515 naks_sent: 0,
516 })
517 }
518
519 pub fn local_addr(&self) -> io::Result<SocketAddr> {
521 self.sock.local_addr()
522 }
523
524 pub fn fec_recovered(&self) -> u64 {
526 self.fec_recovered
527 }
528
529 pub fn naks_sent(&self) -> u64 {
531 self.naks_sent
532 }
533
534 pub fn stream_protection(&self, stream_id: u32) -> Option<Protection> {
536 self.streams.get(&stream_id).map(|s| s.protection)
537 }
538
539 pub fn expect_stream(&mut self, stream_id: u32, protection: Protection) {
543 self.stream_entry(stream_id, protection);
544 }
545
546 pub fn with_stream_loss(mut self, stream_id: u32, pct: u32, seed: u64) -> Self {
549 self.debug_loss.insert(stream_id, (pct.min(100), seed | 1));
550 self
551 }
552
553 fn stream_entry(&mut self, stream_id: u32, protection: Protection) -> &mut RecvStream {
554 let symbol_len = self.symbol_len;
555 self.streams.entry(stream_id).or_insert_with(|| RecvStream {
556 protection,
557 dec: match protection {
558 Protection::Protected => Some(RlcDecoder::new(symbol_len).with_horizon(128)),
559 Protection::Bulk => None,
560 },
561 chunks: BTreeMap::new(),
562 delivered_through: 0,
563 gap_since: BTreeMap::new(),
564 highest_seen: 0,
565 final_info: None,
566 fin_delivered: false,
567 })
568 }
569
570 fn stream_entry_for(&mut self, stream_id: u32) -> &mut RecvStream {
571 if !self.streams.contains_key(&stream_id) {
572 self.stream_entry(stream_id, Protection::Bulk);
573 }
574 self.streams.get_mut(&stream_id).unwrap()
575 }
576
577 pub fn poll(&mut self) -> io::Result<Vec<StreamData>> {
580 let mut buf = vec![0u8; self.symbol_len + REPAIR_HDR + 64];
581 loop {
582 match self.sock.recv_from(&mut buf) {
583 Ok((n, from)) if n >= 1 => {
584 self.ingest(&buf[..n], from);
585 }
586 Ok(_) => {}
587 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
588 Err(ref e) if e.kind() == io::ErrorKind::TimedOut => break,
589 Err(ref e) if e.kind() == io::ErrorKind::ConnectionReset => break,
590 Err(e) => return Err(e),
591 }
592 }
593 let mut out = Vec::new();
594 let stream_ids: Vec<u32> = self.streams.keys().copied().collect();
595 for sid in stream_ids {
596 self.recover_stream(sid);
597 if let Some(d) = self.deliver_stream(sid) {
598 out.push(d);
599 }
600 }
601 self.maybe_nak()?;
602 self.send_acks()?;
603 if out.is_empty() {
604 std::thread::sleep(Duration::from_micros(100));
605 }
606 Ok(out)
607 }
608
609 fn ingest(&mut self, pkt: &[u8], from: SocketAddr) {
611 if pkt.len() < 13 {
612 return;
613 }
614 let cid = u64::from_le_bytes(pkt[1..9].try_into().unwrap());
615 match self.cid {
616 None => {
617 self.cid = Some(cid);
618 self.peer = Some(from);
619 }
620 Some(c) if c == cid => self.peer = Some(from),
621 Some(_) => return,
622 }
623 let stream_id = u32::from_le_bytes(pkt[9..13].try_into().unwrap());
624 match pkt[0] {
625 STREAM if pkt.len() >= STREAM_HDR + self.symbol_len => {
626 let sid = u32::from_le_bytes(pkt[13..17].try_into().unwrap());
627 if self.drop_symbol(stream_id, sid) {
628 return;
629 }
630 let sym = pkt[STREAM_HDR..STREAM_HDR + self.symbol_len].to_vec();
631 let st = self.stream_entry_for(stream_id);
632 st.highest_seen = st.highest_seen.max(sid);
633 st.gap_since.remove(&sid);
634 if sid >= st.delivered_through {
635 st.chunks.entry(sid).or_insert(sym.clone());
636 }
637 if let Some(d) = st.dec.as_mut() {
638 d.on_source(sid, &sym);
639 }
640 }
641 STREAM_REPAIR if pkt.len() >= REPAIR_HDR + self.symbol_len => {
642 let repair_key = u32::from_le_bytes(pkt[13..17].try_into().unwrap());
643 let first_source_id = u32::from_le_bytes(pkt[17..21].try_into().unwrap());
644 let window_size = u16::from_le_bytes(pkt[21..23].try_into().unwrap());
645 let dt = pkt[23];
646 let payload = pkt[REPAIR_HDR..REPAIR_HDR + self.symbol_len].to_vec();
647 let st = self.stream_entry_for(stream_id);
648 if let Some(d) = st.dec.as_mut() {
649 d.add_repair(RepairSymbol {
650 repair_key,
651 first_source_id,
652 window_size,
653 dt,
654 payload,
655 });
656 }
657 }
658 STREAM_FIN if pkt.len() >= FIN_LEN => {
659 let final_sid = u32::from_le_bytes(pkt[13..17].try_into().unwrap());
660 let final_len = u16::from_le_bytes(pkt[17..19].try_into().unwrap());
661 let st = self.stream_entry_for(stream_id);
662 st.final_info = Some((final_sid, final_len));
663 st.highest_seen = st.highest_seen.max(final_sid);
664 }
665 _ => {}
666 }
667 }
668
669 fn recover_stream(&mut self, stream_id: u32) {
670 let Some(st) = self.streams.get_mut(&stream_id) else {
671 return;
672 };
673 let Some(dec) = st.dec.as_mut() else {
674 return;
675 };
676 let recovered = dec.recover();
677 for sid in &recovered {
678 if *sid >= st.delivered_through
679 && let Some(sym) = dec.get(*sid)
680 {
681 st.chunks.entry(*sid).or_insert_with(|| sym.to_vec());
682 st.gap_since.remove(sid);
683 }
684 }
685 self.fec_recovered += recovered.len() as u64;
686 }
687
688 fn deliver_stream(&mut self, stream_id: u32) -> Option<StreamData> {
695 let st = self.streams.get_mut(&stream_id)?;
696 let mut data = Vec::new();
697 let mut fin = false;
698 loop {
699 let s = st.delivered_through;
700 let is_final = st.final_info.map(|(fs, _)| s == fs).unwrap_or(false);
701 let known_non_final = match st.final_info {
702 Some((fs, _)) => s < fs,
703 None => s < st.highest_seen,
704 };
705 if !(is_final || known_non_final) {
706 break;
707 }
708 let Some(sym) = st.chunks.remove(&s) else {
709 break;
710 };
711 if is_final {
712 let len = st.final_info.unwrap().1 as usize;
713 data.extend_from_slice(&sym[..len.min(sym.len())]);
714 st.delivered_through += 1;
715 fin = true;
716 st.fin_delivered = true;
717 break;
718 }
719 data.extend_from_slice(&sym);
720 st.delivered_through += 1;
721 }
722 if let Some(d) = st.dec.as_mut() {
723 d.forget_below(st.delivered_through);
724 }
725 if data.is_empty() && !fin {
726 return None;
727 }
728 Some(StreamData {
729 stream_id,
730 data,
731 fin,
732 })
733 }
734
735 fn maybe_nak(&mut self) -> io::Result<()> {
738 if self.last_nak.elapsed() < Duration::from_millis(2) {
739 return Ok(());
740 }
741 let Some(peer) = self.peer else {
742 return Ok(());
743 };
744 let cid = self.cid.unwrap_or(0);
745 let now = Instant::now();
746 let mut sent_any = false;
747 let stream_ids: Vec<u32> = self.streams.keys().copied().collect();
748 for stream_id in stream_ids {
749 let st = self.streams.get_mut(&stream_id).unwrap();
750 let mut missing = Vec::new();
751 let mut sid = st.delivered_through;
752 while sid <= st.highest_seen && missing.len() < 16 {
753 if !st.chunks.contains_key(&sid) {
754 let first = *st.gap_since.entry(sid).or_insert(now);
755 if now.duration_since(first) >= Duration::from_millis(2) {
757 missing.push(sid);
758 }
759 }
760 sid += 1;
761 }
762 if missing.is_empty() {
763 continue;
764 }
765 let mut pkt = Vec::with_capacity(13 + 4 * missing.len());
766 pkt.push(STREAM_NAK);
767 pkt.extend_from_slice(&cid.to_le_bytes());
768 pkt.extend_from_slice(&stream_id.to_le_bytes());
769 for m in missing {
770 pkt.extend_from_slice(&m.to_le_bytes());
771 }
772 self.sock.send_to(&pkt, peer)?;
773 self.naks_sent += 1;
774 sent_any = true;
775 }
776 if sent_any {
777 self.last_nak = now;
778 }
779 Ok(())
780 }
781
782 fn send_acks(&mut self) -> io::Result<()> {
785 let Some(peer) = self.peer else {
786 return Ok(());
787 };
788 let cid = self.cid.unwrap_or(0);
789 let frontiers: Vec<(u32, u32)> = self
790 .streams
791 .iter()
792 .map(|(&id, s)| (id, s.delivered_through))
793 .collect();
794 for (stream_id, through) in frontiers {
795 let mut pkt = Vec::with_capacity(ACK_LEN);
796 pkt.push(STREAM_ACK);
797 pkt.extend_from_slice(&cid.to_le_bytes());
798 pkt.extend_from_slice(&stream_id.to_le_bytes());
799 pkt.extend_from_slice(&through.to_le_bytes());
800 self.sock.send_to(&pkt, peer)?;
801 }
802 Ok(())
803 }
804
805 fn drop_symbol(&mut self, stream_id: u32, sid: u32) -> bool {
808 let Some((pct, seed)) = self.debug_loss.get(&stream_id).copied() else {
809 return false;
810 };
811 if pct == 0 {
812 return false;
813 }
814 if let Some(st) = self.streams.get(&stream_id)
815 && (st.chunks.contains_key(&sid) || sid < st.delivered_through)
816 {
817 return false;
818 }
819 if self.dropped_once.contains(&(stream_id, sid)) {
823 return false;
824 }
825 let mut x = seed ^ (sid as u64).wrapping_mul(0x9e37_79b9_7f4a_7c15);
826 x = (x ^ (x >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
827 x ^= x >> 27;
828 if ((x % 100) as u32) < pct {
829 self.dropped_once.insert((stream_id, sid));
830 true
831 } else {
832 false
833 }
834 }
835}
836
837#[cfg(test)]
838mod tests {
839 use super::*;
840 use std::sync::mpsc;
841
842 #[test]
846 fn two_streams_deliver_independently_with_selective_fec() {
847 let symbol_len = 256usize;
848 let per_stream = 20_000usize;
849 let (addr_tx, addr_rx) = mpsc::channel();
850
851 let expected1: Vec<u8> = (0..per_stream).map(|i| (i % 251) as u8).collect();
852 let expected2: Vec<u8> = (0..per_stream).map(|i| ((i * 7 + 3) % 251) as u8).collect();
853 let e1 = expected1.clone();
854 let e2 = expected2.clone();
855
856 let rx = std::thread::spawn(move || {
857 let mut recv = StreamMuxReceiver::bind("127.0.0.1:0", symbol_len)
858 .unwrap()
859 .with_stream_loss(1, 12, 0xC0DE);
860 recv.expect_stream(1, Protection::Protected);
861 recv.expect_stream(2, Protection::Bulk);
862 addr_tx.send(recv.local_addr().unwrap()).unwrap();
863 let (mut got1, mut got2) = (Vec::new(), Vec::new());
864 let (mut fin1, mut fin2) = (false, false);
865 let start = Instant::now();
866 while !(fin1 && fin2) {
867 if start.elapsed() > Duration::from_secs(30) {
868 break;
869 }
870 for d in recv.poll().unwrap() {
871 match d.stream_id {
872 1 => {
873 got1.extend_from_slice(&d.data);
874 fin1 |= d.fin;
875 }
876 2 => {
877 got2.extend_from_slice(&d.data);
878 fin2 |= d.fin;
879 }
880 _ => {}
881 }
882 }
883 }
884 for _ in 0..50 {
885 recv.poll().ok();
886 std::thread::sleep(Duration::from_millis(2));
887 }
888 (got1, got2, fin1, fin2, recv.fec_recovered())
889 });
890
891 let recv_addr = addr_rx.recv().unwrap();
892 let tx = std::thread::spawn(move || {
893 let mut send =
894 StreamMuxSender::bind("127.0.0.1:0", recv_addr, symbol_len, 256, 64).unwrap();
895 send.open_stream(1, Protection::Protected);
896 send.open_stream(2, Protection::Bulk);
897 let chunk = 300usize;
898 let (mut o1, mut o2) = (0usize, 0usize);
899 while o1 < e1.len() || o2 < e2.len() {
900 if o1 < e1.len() {
901 let end = (o1 + chunk).min(e1.len());
902 send.write(1, &e1[o1..end], end == e1.len()).unwrap();
903 o1 = end;
904 }
905 if o2 < e2.len() {
906 let end = (o2 + chunk).min(e2.len());
907 send.write(2, &e2[o2..end], end == e2.len()).unwrap();
908 o2 = end;
909 }
910 }
911 send.flush(Duration::from_secs(25)).unwrap();
912 });
913
914 let (got1, got2, fin1, fin2, fec) = rx.join().unwrap();
915 tx.join().unwrap();
916 assert!(fin1 && fin2, "both streams must finish");
917 assert_eq!(got1, expected1, "protected stream 1 delivered exactly");
918 assert_eq!(got2, expected2, "bulk stream 2 delivered exactly");
919 assert!(fec > 0, "the protected stream must have recovered losses via FEC");
920 }
921
922 #[test]
926 fn a_stalled_stream_does_not_block_another() {
927 let symbol_len = 128usize;
928 let n = 6_000usize;
929 let (addr_tx, addr_rx) = mpsc::channel();
930 let expected2: Vec<u8> = (0..n).map(|i| (i % 251) as u8).collect();
931 let e2 = expected2.clone();
932
933 let rx = std::thread::spawn(move || {
934 let mut recv = StreamMuxReceiver::bind("127.0.0.1:0", symbol_len)
937 .unwrap()
938 .with_stream_loss(1, 30, 0xBEEF);
939 recv.expect_stream(1, Protection::Bulk);
940 recv.expect_stream(2, Protection::Bulk);
941 addr_tx.send(recv.local_addr().unwrap()).unwrap();
942 let mut got2 = Vec::new();
943 let mut fin2 = false;
944 let start = Instant::now();
945 while !fin2 {
946 if start.elapsed() > Duration::from_secs(30) {
947 break;
948 }
949 for d in recv.poll().unwrap() {
950 if d.stream_id == 2 {
951 got2.extend_from_slice(&d.data);
952 fin2 |= d.fin;
953 }
954 }
955 }
956 for _ in 0..50 {
957 recv.poll().ok();
958 std::thread::sleep(Duration::from_millis(2));
959 }
960 (got2, fin2)
961 });
962
963 let recv_addr = addr_rx.recv().unwrap();
964 let tx = std::thread::spawn(move || {
965 let mut send =
966 StreamMuxSender::bind("127.0.0.1:0", recv_addr, symbol_len, 512, 256).unwrap();
967 send.open_stream(1, Protection::Bulk);
968 send.open_stream(2, Protection::Bulk);
969 let chunk = 100usize;
971 let (mut o1, mut o2) = (0usize, 0usize);
972 let one: Vec<u8> = (0..n).map(|i| (i % 13) as u8).collect();
973 while o1 < one.len() || o2 < e2.len() {
974 if o1 < one.len() {
975 let end = (o1 + chunk).min(one.len());
976 send.write(1, &one[o1..end], end == one.len()).unwrap();
977 o1 = end;
978 }
979 if o2 < e2.len() {
980 let end = (o2 + chunk).min(e2.len());
981 send.write(2, &e2[o2..end], end == e2.len()).unwrap();
982 o2 = end;
983 }
984 }
985 send.flush(Duration::from_secs(25)).unwrap();
986 });
987
988 let (got2, fin2) = rx.join().unwrap();
989 tx.join().unwrap();
990 assert!(fin2, "the clean stream finished despite the other stalling");
991 assert_eq!(got2, expected2, "the clean stream delivered exactly");
992 }
993}