Skip to main content

sapflow_srt/
receiver.rs

1//! One connection's receiving side, after the handshake: the receive
2//! buffer, timestamp-based delivery (TSBPD) with too-late packet drop, ACKs,
3//! NAKs, RTT, keepalives and the idle timeout.
4//!
5//! Times are microseconds on the listener's clock (`i64`, never negative in
6//! practice); packet timestamps are extended to 64 bits so nothing here
7//! wraps except the sequence numbers, which are compared circularly.
8
9use std::collections::VecDeque;
10
11use crate::crypto::Decryptor;
12use crate::loss::{LossList, Timing};
13use crate::packet::{Ack, AckStats, Control, ControlPacket, DataPacket, MAX_LOSS_ENTRIES};
14use crate::rtt::Rtt;
15use crate::seq::{Seq, TimestampExtender};
16
17/// Full ACKs go out at most this often (the specification's SYN interval).
18pub const ACK_INTERVAL: i64 = 10_000;
19/// A light ACK after this many packets with no ACK.
20pub const LIGHT_ACK_PACKETS: u32 = 64;
21/// A keepalive when nothing has been sent for this long.
22pub const KEEPALIVE_INTERVAL: i64 = 1_000_000;
23/// Packet arrivals a drift estimate is taken over.
24const DRIFT_WINDOW: u32 = 1000;
25/// The most one drift estimate may move delivery times.
26const DRIFT_STEP: i64 = 5_000;
27/// Drift is never corrected by more than this in all.
28const DRIFT_MAX: i64 = 500_000;
29/// A packet is never held longer than its latency plus this, whatever its
30/// timestamp claims.
31const MAX_HOLD_BEYOND_LATENCY: i64 = 1_000_000;
32/// Unanswered full ACKs remembered for RTT measurement.
33const ACKS_REMEMBERED: usize = 64;
34
35/// Per-connection receiver settings.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub struct Settings {
38    /// Microseconds.
39    pub latency: i64,
40    /// Packets the receive buffer holds.
41    pub buffer: usize,
42    /// Close after this long with nothing received (microseconds).
43    pub peer_idle: i64,
44    /// Largest data payload accepted, in bytes; larger packets are ignored.
45    pub max_payload: usize,
46}
47
48/// Counts for one connection.
49#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
50pub struct Stats {
51    /// Data packets received, every copy.
52    pub received: u64,
53    /// Payload bytes in those packets.
54    pub received_bytes: u64,
55    /// Of those, retransmissions.
56    pub retransmitted: u64,
57    /// Copies of packets already held.
58    pub duplicates: u64,
59    /// Copies of packets already delivered or given up on.
60    pub belated: u64,
61    /// Packets found missing (each counted once).
62    pub lost: u64,
63    /// Missing packets skipped at their delivery time.
64    pub dropped: u64,
65    /// Packets handed over in order for delivery.
66    pub delivered: u64,
67    /// Data packets refused for a plaintext/key mismatch or expired key.
68    pub encrypted: u64,
69    /// Data packets decrypted.
70    pub decrypted: u64,
71    /// Key material refresh messages refused: encryption is not in use on the
72    /// connection, or the message failed to unwrap or validate.
73    pub km_rejected: u64,
74    /// NAK packets sent.
75    pub naks_sent: u64,
76    /// ACK packets sent, light and full.
77    pub acks_sent: u64,
78}
79
80/// Why a receiver closed.
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum CloseReason {
83    /// The peer sent SHUTDOWN.
84    Shutdown,
85    /// Nothing arrived for the idle timeout.
86    Timeout,
87}
88
89#[derive(Debug)]
90struct Slot {
91    deliver_at: i64,
92    payload: Vec<u8>,
93}
94
95/// Packets and bytes a second, over the last whole second.
96#[derive(Debug, Default)]
97struct RateMeter {
98    since: i64,
99    packets: u32,
100    bytes: u64,
101    rate: (u32, u32),
102}
103
104impl RateMeter {
105    fn add(&mut self, now: i64, bytes: usize) {
106        let elapsed = now - self.since;
107        if elapsed >= 1_000_000 {
108            let per_s = |n: u64| u32::try_from(n * 1_000_000 / elapsed as u64).unwrap_or(u32::MAX);
109            self.rate = (per_s(u64::from(self.packets)), per_s(self.bytes));
110            self.since = now;
111            self.packets = 0;
112            self.bytes = 0;
113        }
114        self.packets = self.packets.saturating_add(1);
115        self.bytes = self.bytes.saturating_add(bytes as u64);
116    }
117}
118
119/// Link capacity from the spacing of back-to-back packets: the median of
120/// the last 16 gaps between consecutive originals.
121#[derive(Debug, Default)]
122struct PacketPairs {
123    last: Option<(Seq, i64)>,
124    gaps: VecDeque<i64>,
125}
126
127impl PacketPairs {
128    fn add(&mut self, seq: Seq, now: i64) {
129        if let Some((s, t)) = self.last
130            && s.next() == seq
131        {
132            if self.gaps.len() >= 16 {
133                self.gaps.pop_front();
134            }
135            self.gaps.push_back((now - t).max(1));
136        }
137        self.last = Some((seq, now));
138    }
139
140    /// Packets per second; 1000 before there is anything to go on (as
141    /// libsrt reports at first, observed).
142    fn capacity(&self) -> u32 {
143        if self.gaps.is_empty() {
144            return 1000;
145        }
146        let mut g: Vec<i64> = self.gaps.iter().copied().collect();
147        g.sort_unstable();
148        let median = g.get(g.len() / 2).copied().unwrap_or(1).max(1);
149        u32::try_from(1_000_000 / median).unwrap_or(u32::MAX)
150    }
151}
152
153/// Follows the sender's clock: the earliest arrival relative to the
154/// timestamp, over a window of packets, so queueing delay does not count.
155#[derive(Debug, Default)]
156struct Drift {
157    offset: i64,
158    window_min: Option<i64>,
159    count: u32,
160}
161
162impl Drift {
163    fn sample(&mut self, lateness: i64) {
164        self.window_min = Some(self.window_min.map_or(lateness, |m| m.min(lateness)));
165        self.count += 1;
166        if self.count >= DRIFT_WINDOW {
167            let target = self.window_min.unwrap_or(self.offset);
168            self.offset = (self.offset + (target - self.offset).clamp(-DRIFT_STEP, DRIFT_STEP))
169                .clamp(-DRIFT_MAX, DRIFT_MAX);
170            self.window_min = None;
171            self.count = 0;
172        }
173    }
174}
175
176/// One connection's receiving side; see the module docs. Give it packets and
177/// the time, then take its control packets and deliveries.
178pub struct Receiver {
179    settings: Settings,
180    peer_socket: u32,
181    /// When the connection opened; our packets' timestamps count from here.
182    start: i64,
183    /// Local time of sender timestamp 0.
184    base: i64,
185    ts: TimestampExtender,
186    drift: Drift,
187    /// The next packet to deliver; everything before it is delivered or
188    /// given up on.
189    head: Seq,
190    buf: VecDeque<Option<Slot>>,
191    /// The first sequence number not yet received (what an ACK reports).
192    ack_pos: Seq,
193    loss: LossList,
194    rtt: Rtt,
195    next_ack_number: u32,
196    last_ack_sent: Seq,
197    last_full_ack: i64,
198    unanswered: VecDeque<(u32, i64)>,
199    since_ack: u32,
200    last_sent: i64,
201    last_received: i64,
202    /// The latest time seen.
203    now: i64,
204    rate: RateMeter,
205    pairs: PacketPairs,
206    stats: Stats,
207    closed: Option<CloseReason>,
208    /// Control packets to send, encoded.
209    send: VecDeque<Vec<u8>>,
210    deliver: VecDeque<Vec<u8>>,
211    crypto: Option<Decryptor>,
212    next_km: i64,
213}
214
215impl Receiver {
216    /// `hs_timestamp` is the conclusion's timestamp, `initial_seq` the
217    /// sender's first sequence number, both from its handshake.
218    pub fn new(
219        settings: Settings,
220        now: i64,
221        peer_socket: u32,
222        initial_seq: Seq,
223        hs_timestamp: u32,
224    ) -> Self {
225        Self {
226            settings,
227            peer_socket,
228            start: now,
229            base: now - i64::from(hs_timestamp),
230            ts: TimestampExtender::starting_at(hs_timestamp),
231            drift: Drift::default(),
232            head: initial_seq,
233            buf: VecDeque::new(),
234            ack_pos: initial_seq,
235            loss: LossList::new(),
236            rtt: Rtt::new(),
237            next_ack_number: 1,
238            last_ack_sent: initial_seq,
239            last_full_ack: now,
240            unanswered: VecDeque::new(),
241            since_ack: 0,
242            last_sent: now,
243            last_received: now,
244            now,
245            rate: RateMeter {
246                since: now,
247                ..RateMeter::default()
248            },
249            pairs: PacketPairs::default(),
250            stats: Stats::default(),
251            closed: None,
252            send: VecDeque::new(),
253            deliver: VecDeque::new(),
254            crypto: None,
255            next_km: 0,
256        }
257    }
258
259    /// The connection's counters so far.
260    pub fn stats(&self) -> Stats {
261        self.stats
262    }
263
264    /// The round-trip time estimate.
265    pub fn rtt(&self) -> &Rtt {
266        &self.rtt
267    }
268
269    /// The TSBPD latency this connection delivers with, in microseconds.
270    pub fn latency(&self) -> i64 {
271        self.settings.latency
272    }
273
274    pub(crate) fn set_crypto(&mut self, crypto: Option<Decryptor>) {
275        self.crypto = crypto;
276    }
277
278    /// Why the connection closed, or `None` while it is open.
279    pub fn closed(&self) -> Option<CloseReason> {
280        self.closed
281    }
282
283    /// Takes the next encoded control packet to send to the caller, if any.
284    pub fn take_send(&mut self) -> Option<Vec<u8>> {
285        self.send.pop_front()
286    }
287
288    /// Takes the next payload due for delivery, in sequence order, if any.
289    pub fn take_delivery(&mut self) -> Option<Vec<u8>> {
290        self.deliver.pop_front()
291    }
292
293    /// Packets held, received or not.
294    pub fn buffered(&self) -> usize {
295        self.buf.len()
296    }
297
298    fn queue(&mut self, now: i64, body: Control) {
299        let ts = (now - self.start) as u32;
300        let mut out = Vec::with_capacity(64);
301        ControlPacket::new(ts, self.peer_socket, body).encode(&mut out);
302        self.send.push_back(out);
303        self.last_sent = now;
304    }
305
306    /// Takes a data packet that arrived at `now`: checks its encryption,
307    /// buffers it, reports any gap in a NAK, sends a light ACK after enough
308    /// packets and releases what is due.
309    pub fn on_data(&mut self, now: i64, p: &DataPacket) {
310        self.now = self.now.max(now);
311        if self.closed.is_some() {
312            return;
313        }
314        if (self.crypto.is_some() && !matches!(p.key, 1 | 2))
315            || (self.crypto.is_none() && p.key != 0)
316        {
317            // A key mismatch must never become plaintext delivery.
318            self.stats.encrypted += 1;
319            return;
320        }
321        if p.payload.len() > self.settings.max_payload {
322            return;
323        }
324        self.stats.received += 1;
325        self.stats.received_bytes += p.payload.len() as u64;
326        if p.retransmitted {
327            self.stats.retransmitted += 1;
328        }
329        // Reject replay/duplicate sequences before allocating or decrypting.
330        let distance = self.head.distance_to(p.seq);
331        if distance < 0 {
332            self.stats.belated += 1;
333            return;
334        }
335        if self.buf.get(distance as usize).is_some_and(Option::is_some) {
336            self.stats.duplicates += 1;
337            return;
338        }
339        let mut payload = p.payload.to_vec();
340        if let Some(crypto) = &mut self.crypto {
341            if crypto.decrypt(p.key, p.seq, &mut payload).is_err() {
342                self.stats.encrypted += 1;
343                return;
344            }
345            self.stats.decrypted += 1;
346        }
347        self.last_received = now;
348        let ext = self.ts.extend(p.timestamp);
349        if !p.retransmitted {
350            self.drift
351                .sample(now.saturating_sub(self.base.saturating_add(ext)));
352            self.rate.add(now, p.payload.len());
353            self.pairs.add(p.seq, now);
354        }
355        let deliver_at = self
356            .base
357            .saturating_add(self.drift.offset)
358            .saturating_add(ext)
359            .saturating_add(self.settings.latency)
360            .min(now.saturating_add(self.settings.latency + MAX_HOLD_BEYOND_LATENCY));
361
362        let mut d = self.head.distance_to(p.seq);
363        if d < 0 {
364            self.stats.belated += 1;
365            return;
366        }
367        if d as usize >= self.settings.buffer {
368            self.make_room(p.seq);
369            d = self.head.distance_to(p.seq);
370        }
371        let idx = d as usize;
372        let slot = Slot {
373            deliver_at,
374            payload,
375        };
376        if let Some(existing) = self.buf.get_mut(idx) {
377            if existing.is_some() {
378                self.stats.duplicates += 1;
379                return;
380            }
381            *existing = Some(slot);
382            self.loss.remove(p.seq);
383        } else {
384            if idx > self.buf.len() {
385                // A gap: report it at once.
386                let first = self.head.add(self.buf.len() as u32);
387                let last = p.seq.prev();
388                self.stats.lost += first.distance_to(last) as u64 + 1;
389                self.loss.add(first, last, now, deliver_at);
390                self.stats.naks_sent += 1;
391                self.queue(now, Control::Nak(vec![(first, last)]));
392                self.buf.resize_with(idx, || None);
393            }
394            self.buf.push_back(Some(slot));
395        }
396        self.advance_ack_pos();
397        self.since_ack += 1;
398        if self.since_ack >= LIGHT_ACK_PACKETS && self.ack_pos != self.last_ack_sent {
399            self.light_ack(now);
400        }
401        self.nak_due(now);
402        self.release(now);
403    }
404
405    /// `seq` is beyond the buffer: deliver or give up the oldest packets to
406    /// make room. A jump further than the whole buffer starts afresh at
407    /// `seq` rather than reporting everything between as lost.
408    fn make_room(&mut self, seq: Seq) {
409        let d = self.head.distance_to(seq) as usize;
410        let excess = d + 1 - self.settings.buffer;
411        if excess > self.buf.len() {
412            self.flush();
413            self.head = seq;
414            self.loss.clear();
415        } else {
416            for _ in 0..excess {
417                self.pop_front();
418            }
419            self.loss.remove_before(self.head);
420        }
421        self.advance_ack_pos();
422    }
423
424    /// Delivers or drops the packet at the head.
425    fn pop_front(&mut self) {
426        match self.buf.pop_front() {
427            Some(Some(slot)) => {
428                self.stats.delivered += 1;
429                self.deliver.push_back(slot.payload);
430            }
431            Some(None) => self.stats.dropped += 1,
432            None => {}
433        }
434        self.head = self.head.next();
435    }
436
437    /// Delivers everything held, in order, now.
438    fn flush(&mut self) {
439        while !self.buf.is_empty() {
440            self.pop_front();
441        }
442        self.loss.clear();
443        self.advance_ack_pos();
444    }
445
446    fn advance_ack_pos(&mut self) {
447        let mut i = self.head.distance_to(self.ack_pos).max(0) as usize;
448        while matches!(self.buf.get(i), Some(Some(_))) {
449            i += 1;
450        }
451        self.ack_pos = self.head.add(i as u32);
452    }
453
454    /// TSBPD: hands over every packet whose time has come; a missing packet
455    /// is skipped once a later one is due (too-late packet drop).
456    fn release(&mut self, now: i64) {
457        loop {
458            match self.buf.front() {
459                Some(Some(slot)) if slot.deliver_at <= now => self.pop_front(),
460                Some(None) => {
461                    let due = self
462                        .buf
463                        .iter()
464                        .position(Option::is_some)
465                        .and_then(|i| Some((i, self.buf.get(i)?.as_ref()?.deliver_at)));
466                    match due {
467                        Some((i, at)) if at <= now => {
468                            for _ in 0..i {
469                                self.pop_front();
470                            }
471                            self.loss.remove_before(self.head);
472                            self.advance_ack_pos();
473                        }
474                        _ => break,
475                    }
476                }
477                _ => break,
478            }
479        }
480    }
481
482    fn timing(&self) -> Timing {
483        Timing {
484            rtt: self.rtt.rtt(),
485            retry: self.rtt.retry(),
486        }
487    }
488
489    fn nak_due(&mut self, now: i64) {
490        if self.loss.is_empty() {
491            return;
492        }
493        let ranges = self.loss.due(now, self.timing(), MAX_LOSS_ENTRIES / 2);
494        if !ranges.is_empty() {
495            self.stats.naks_sent += 1;
496            self.queue(now, Control::Nak(ranges));
497        }
498    }
499
500    fn light_ack(&mut self, now: i64) {
501        self.last_ack_sent = self.ack_pos;
502        self.since_ack = 0;
503        self.stats.acks_sent += 1;
504        let ack = Ack {
505            number: 0,
506            ack: self.ack_pos,
507            stats: None,
508        };
509        self.queue(now, Control::Ack(ack));
510    }
511
512    fn full_ack(&mut self, now: i64) {
513        let number = self.next_ack_number;
514        self.next_ack_number = self.next_ack_number.wrapping_add(1).max(1);
515        self.last_ack_sent = self.ack_pos;
516        self.last_full_ack = now;
517        self.since_ack = 0;
518        self.stats.acks_sent += 1;
519        if self.unanswered.len() >= ACKS_REMEMBERED {
520            self.unanswered.pop_front();
521        }
522        self.unanswered.push_back((number, now));
523        let clamp = |v: i64| u32::try_from(v.max(0)).unwrap_or(u32::MAX);
524        let free = self.settings.buffer.saturating_sub(self.buf.len());
525        let ack = Ack {
526            number,
527            ack: self.ack_pos,
528            stats: Some(AckStats {
529                rtt: clamp(self.rtt.rtt()),
530                rtt_var: clamp(self.rtt.var()),
531                buffer: u32::try_from(free).unwrap_or(u32::MAX),
532                rates: Some((self.rate.rate.0, self.pairs.capacity(), self.rate.rate.1)),
533            }),
534        };
535        self.queue(now, Control::Ack(ack));
536    }
537
538    /// Takes a control packet that arrived at `now`. An ACKACK gives an RTT
539    /// sample, SHUTDOWN flushes and closes, a drop request stops asking for
540    /// those packets and a key material refresh is answered (at most one per
541    /// 100 ms). Any other control packet only shows the caller is alive.
542    pub fn on_control(&mut self, now: i64, c: &Control) {
543        self.now = self.now.max(now);
544        if self.closed.is_some() {
545            return;
546        }
547        if let Control::Other {
548            control_type: 0x7fff,
549            subtype: 3,
550            info: 0,
551            cif,
552        } = c
553        {
554            // One bounded unwrap and response per 100ms per connection;
555            // repeated or hostile KM cannot drive KDF work or queue growth.
556            if now < self.next_km {
557                return;
558            }
559            self.next_km = now.saturating_add(100_000);
560            if self
561                .crypto
562                .as_mut()
563                .is_some_and(|crypto| crypto.refresh(cif).is_ok())
564            {
565                self.last_received = now;
566                self.queue(
567                    now,
568                    Control::Other {
569                        control_type: 0x7fff,
570                        subtype: 4,
571                        info: 0,
572                        cif: cif.clone(),
573                    },
574                );
575            } else {
576                self.stats.km_rejected += 1;
577            }
578            return;
579        }
580        self.last_received = now;
581        match c {
582            Control::AckAck { number } => {
583                if let Some(i) = self.unanswered.iter().position(|(n, _)| n == number) {
584                    if let Some((_, sent)) = self.unanswered.get(i).copied() {
585                        self.rtt.sample(now - sent);
586                    }
587                    self.unanswered.drain(..=i);
588                }
589            }
590            Control::Shutdown => {
591                self.flush();
592                self.closed = Some(CloseReason::Shutdown);
593            }
594            Control::DropRequest { first, last, .. } => {
595                // The sender no longer has these: stop asking for them.
596                self.loss.remove_range(*first, *last);
597            }
598            _ => {}
599        }
600    }
601
602    /// Does what is due at `now`: the idle timeout, delivery of due packets,
603    /// a full ACK, NAK re-requests and a keepalive.
604    pub fn on_timer(&mut self, now: i64) {
605        self.now = self.now.max(now);
606        if self.closed.is_some() {
607            return;
608        }
609        if now - self.last_received >= self.settings.peer_idle {
610            self.closed = Some(CloseReason::Timeout);
611            return;
612        }
613        self.release(now);
614        if self.ack_pos != self.last_ack_sent && now - self.last_full_ack >= ACK_INTERVAL {
615            self.full_ack(now);
616        }
617        self.nak_due(now);
618        if now - self.last_sent >= KEEPALIVE_INTERVAL {
619            self.queue(now, Control::KeepAlive);
620        }
621    }
622
623    /// When [`on_timer`](Self::on_timer) next has something to do.
624    pub fn next_timer(&self) -> i64 {
625        let mut t = self
626            .last_received
627            .saturating_add(self.settings.peer_idle)
628            .min(self.last_sent + KEEPALIVE_INTERVAL);
629        if self.ack_pos != self.last_ack_sent {
630            t = t.min(self.last_full_ack + ACK_INTERVAL);
631        }
632        if let Some(at) = self.loss.next_due(self.now, self.timing()) {
633            t = t.min(at);
634        }
635        if let Some(at) = self
636            .buf
637            .iter()
638            .find_map(|s| s.as_ref().map(|s| s.deliver_at))
639        {
640            t = t.min(at);
641        }
642        t
643    }
644
645    /// Ends the connection from this side: a SHUTDOWN to the peer.
646    pub fn shutdown(&mut self, now: i64) {
647        self.queue(now, Control::Shutdown);
648    }
649}
650
651#[cfg(test)]
652mod tests {
653    use super::*;
654    use crate::packet::{Packet, Position};
655
656    const MS: i64 = 1000;
657    const LATENCY: i64 = 200 * MS;
658    const ISN: u32 = 1000;
659
660    fn settings() -> Settings {
661        Settings {
662            latency: LATENCY,
663            buffer: 64,
664            peer_idle: 5_000 * MS,
665            max_payload: 1456,
666        }
667    }
668
669    /// A receiver opened at time 0 by a handshake stamped 0, so a packet
670    /// stamped `t` is due at `t + LATENCY`.
671    fn rx() -> Receiver {
672        Receiver::new(settings(), 0, 77, Seq::new(ISN), 0)
673    }
674
675    fn data(seq: u32, ts: u32, payload: &[u8]) -> DataPacket<'_> {
676        DataPacket {
677            seq: Seq::new(seq),
678            position: Position::Only,
679            in_order: false,
680            key: 0,
681            retransmitted: false,
682            message: 1,
683            timestamp: ts,
684            dest: 5,
685            payload,
686        }
687    }
688
689    fn sent(r: &mut Receiver) -> Vec<Control> {
690        std::iter::from_fn(|| r.take_send())
691            .map(|b| match Packet::parse(&b) {
692                Ok(Packet::Control(c)) => {
693                    assert_eq!(c.dest, 77);
694                    c.body
695                }
696                other => panic!("{other:?}"),
697            })
698            .collect()
699    }
700
701    fn delivered(r: &mut Receiver) -> Vec<Vec<u8>> {
702        std::iter::from_fn(|| r.take_delivery()).collect()
703    }
704
705    #[test]
706    fn delivers_in_order_at_timestamp_plus_latency() {
707        let mut r = rx();
708        r.on_data(10 * MS, &data(ISN, 10 * MS as u32, b"a"));
709        r.on_data(20 * MS, &data(ISN + 1, 20 * MS as u32, b"b"));
710        assert!(delivered(&mut r).is_empty());
711        assert_eq!(r.next_timer(), 10 * MS, "the first full ACK");
712        r.on_timer(10 * MS);
713        assert_eq!(r.next_timer(), 210 * MS);
714        r.on_timer(209 * MS);
715        assert!(delivered(&mut r).is_empty());
716        r.on_timer(210 * MS);
717        assert_eq!(delivered(&mut r), vec![b"a".to_vec()]);
718        r.on_timer(220 * MS);
719        assert_eq!(delivered(&mut r), vec![b"b".to_vec()]);
720        assert_eq!(r.stats().delivered, 2);
721    }
722
723    #[test]
724    fn a_gap_is_reported_at_once_and_filled_by_a_retransmission() {
725        let mut r = rx();
726        r.on_data(0, &data(ISN, 0, b"0"));
727        r.on_data(MS, &data(ISN + 3, MS as u32, b"3"));
728        let s = |v| Seq::new(v);
729        assert_eq!(
730            sent(&mut r),
731            vec![Control::Nak(vec![(s(ISN + 1), s(ISN + 2))])]
732        );
733        assert_eq!(r.stats().lost, 2);
734        let mut p = data(ISN + 1, 0, b"1");
735        p.retransmitted = true;
736        r.on_data(5 * MS, &p);
737        let mut p = data(ISN + 2, 0, b"2");
738        p.retransmitted = true;
739        r.on_data(6 * MS, &p);
740        r.on_timer(300 * MS);
741        assert_eq!(
742            delivered(&mut r),
743            [b"0", b"1", b"2", b"3"].map(|x| x.to_vec()).to_vec()
744        );
745        assert_eq!(r.stats().dropped, 0);
746        assert_eq!(r.stats().retransmitted, 2);
747    }
748
749    #[test]
750    fn a_missing_packet_is_skipped_when_the_next_is_due() {
751        let mut r = rx();
752        r.on_data(0, &data(ISN, 0, b"0"));
753        r.on_data(2 * MS, &data(ISN + 2, 2 * MS as u32, b"2"));
754        r.on_timer(200 * MS);
755        assert_eq!(delivered(&mut r), vec![b"0".to_vec()]);
756        r.on_timer(201 * MS);
757        assert!(delivered(&mut r).is_empty(), "waits for 1 until 2 is due");
758        r.on_timer(202 * MS);
759        assert_eq!(delivered(&mut r), vec![b"2".to_vec()]);
760        assert_eq!(r.stats().dropped, 1);
761        // The ACK moves past the dropped packet (the fake ACK).
762        sent(&mut r);
763        r.on_timer(300 * MS);
764        let acks: Vec<_> = sent(&mut r)
765            .into_iter()
766            .filter_map(|c| match c {
767                Control::Ack(a) => Some(a.ack),
768                _ => None,
769            })
770            .collect();
771        assert_eq!(acks.last(), Some(&Seq::new(ISN + 3)));
772        // The retransmission arriving now is too late.
773        let mut p = data(ISN + 1, 0, b"1");
774        p.retransmitted = true;
775        r.on_data(301 * MS, &p);
776        assert_eq!(r.stats().belated, 1);
777        assert!(delivered(&mut r).is_empty());
778    }
779
780    #[test]
781    fn acks_and_rtt_from_ackack() {
782        let mut r = rx();
783        r.on_data(0, &data(ISN, 0, b"0"));
784        r.on_timer(10 * MS);
785        let c = sent(&mut r);
786        let [Control::Ack(a)] = c.as_slice() else {
787            panic!("{c:?}");
788        };
789        assert_eq!(a.number, 1);
790        assert_eq!(a.ack, Seq::new(ISN + 1));
791        let st = a.stats.expect("full ACK");
792        assert_eq!((st.rtt, st.rtt_var), (100_000, 50_000));
793        assert_eq!(st.buffer, 63);
794        r.on_control(40 * MS, &Control::AckAck { number: 1 });
795        assert_eq!(r.rtt().rtt(), 30 * MS);
796        // Nothing new: no ACK.
797        r.on_timer(50 * MS);
798        assert!(sent(&mut r).is_empty());
799        r.on_data(51 * MS, &data(ISN + 1, 51 * MS as u32, b"1"));
800        r.on_timer(60 * MS);
801        let c = sent(&mut r);
802        assert!(
803            matches!(c.as_slice(), [Control::Ack(a)] if a.number == 2 && a.stats.is_some_and(|s| s.rtt == 30_000)),
804            "{c:?}"
805        );
806    }
807
808    #[test]
809    fn light_ack_every_64_packets() {
810        let mut r = Receiver::new(
811            Settings {
812                buffer: 1000,
813                ..settings()
814            },
815            0,
816            77,
817            Seq::new(ISN),
818            0,
819        );
820        for i in 0..64 {
821            r.on_data(0, &data(ISN + i, 0, b"x"));
822        }
823        let c = sent(&mut r);
824        assert!(
825            matches!(c.as_slice(), [Control::Ack(Ack { number: 0, stats: None, ack })] if *ack == Seq::new(ISN + 64)),
826            "{c:?}"
827        );
828    }
829
830    #[test]
831    fn nak_again_after_a_round_trip_and_its_variance() {
832        let mut r = Receiver::new(
833            Settings {
834                latency: 2_000 * MS,
835                ..settings()
836            },
837            0,
838            77,
839            Seq::new(ISN),
840            0,
841        );
842        // One RTT sample: 60 ms, so the variance is 30 ms and a loss is
843        // asked for again 60 + 4 x 30 = 180 ms after the last request.
844        r.on_data(0, &data(ISN, 0, b"0"));
845        r.on_timer(10 * MS);
846        r.on_control(70 * MS, &Control::AckAck { number: 1 });
847        assert_eq!((r.rtt().rtt(), r.rtt().retry()), (60 * MS, 180 * MS));
848        sent(&mut r);
849        // A gap far from its 2 s deadline, so only the ordinary interval
850        // applies.
851        r.on_data(71 * MS, &data(ISN + 2, 71 * MS as u32, b"2"));
852        let naks = |c: Vec<Control>| c.iter().filter(|c| matches!(c, Control::Nak(_))).count();
853        assert_eq!(naks(sent(&mut r)), 1, "the immediate NAK");
854        assert_eq!(r.next_timer(), 251 * MS);
855        r.on_timer(250 * MS);
856        assert_eq!(naks(sent(&mut r)), 0);
857        r.on_timer(251 * MS);
858        assert_eq!(naks(sent(&mut r)), 1);
859        assert_eq!(r.next_timer(), 431 * MS);
860    }
861
862    #[test]
863    fn idle_timeout_and_keepalive() {
864        let mut r = rx();
865        assert_eq!(r.next_timer(), KEEPALIVE_INTERVAL);
866        r.on_timer(KEEPALIVE_INTERVAL);
867        assert_eq!(sent(&mut r), vec![Control::KeepAlive]);
868        r.on_control(4_000 * MS, &Control::KeepAlive);
869        r.on_timer(8_999 * MS);
870        assert_eq!(r.closed(), None);
871        r.on_timer(9_000 * MS);
872        assert_eq!(r.closed(), Some(CloseReason::Timeout));
873    }
874
875    #[test]
876    fn shutdown_delivers_what_is_held() {
877        let mut r = rx();
878        r.on_data(0, &data(ISN, 0, b"0"));
879        r.on_data(0, &data(ISN + 1, 0, b"1"));
880        r.on_control(MS, &Control::Shutdown);
881        assert_eq!(r.closed(), Some(CloseReason::Shutdown));
882        assert_eq!(delivered(&mut r).len(), 2);
883    }
884
885    #[test]
886    fn sequence_numbers_wrap() {
887        let mut r = Receiver::new(settings(), 0, 77, Seq::new(Seq::MAX - 1), 0);
888        for (i, s) in [Seq::MAX - 1, Seq::MAX, 0, 1].into_iter().enumerate() {
889            r.on_data(0, &data(s, i as u32, &[i as u8]));
890        }
891        r.on_timer(LATENCY + 10);
892        assert_eq!(delivered(&mut r), vec![vec![0], vec![1], vec![2], vec![3]]);
893    }
894
895    #[test]
896    fn timestamps_wrap() {
897        // The handshake 3 ms before the 32-bit wrap.
898        let hs = u32::MAX - 3_000;
899        let mut r = Receiver::new(settings(), 0, 77, Seq::new(ISN), hs);
900        r.on_data(2 * MS, &data(ISN, hs.wrapping_add(2_000), b"0"));
901        r.on_data(5 * MS, &data(ISN + 1, hs.wrapping_add(5_000), b"1"));
902        r.on_timer(LATENCY + 2 * MS);
903        assert_eq!(delivered(&mut r), vec![b"0".to_vec()]);
904        r.on_timer(LATENCY + 5 * MS);
905        assert_eq!(delivered(&mut r), vec![b"1".to_vec()]);
906    }
907
908    #[test]
909    fn a_full_buffer_delivers_early_and_a_huge_jump_starts_afresh() {
910        let mut r = rx();
911        for i in 0..64 {
912            r.on_data(0, &data(ISN + i, 0, b"x"));
913        }
914        r.on_data(0, &data(ISN + 64, 0, b"y"));
915        assert_eq!(delivered(&mut r).len(), 1, "the oldest made room");
916        assert_eq!(r.buffered(), 64);
917        r.on_data(0, &data(ISN + 1_000_000, 0, b"z"));
918        assert_eq!(delivered(&mut r).len(), 64, "everything held, at once");
919        assert_eq!(r.buffered(), 1);
920        assert_eq!(r.stats().lost, 0, "a jump is not a loss");
921    }
922
923    #[test]
924    fn encrypted_and_oversized_packets_are_refused() {
925        let mut r = rx();
926        let mut p = data(ISN, 0, b"x");
927        p.key = 1;
928        r.on_data(0, &p);
929        let big = vec![0u8; 1457];
930        r.on_data(0, &data(ISN, 0, &big));
931        assert_eq!(r.stats().encrypted, 1);
932        assert_eq!(r.stats().received, 0);
933        assert_eq!(r.buffered(), 0);
934    }
935
936    #[test]
937    fn a_far_future_timestamp_is_not_held_forever() {
938        let mut r = rx();
939        r.on_data(0, &data(ISN, 2_000_000_000, b"x"));
940        assert!(r.next_timer() <= LATENCY + MAX_HOLD_BEYOND_LATENCY);
941    }
942
943    #[test]
944    fn drift_follows_a_slow_sender_clock() {
945        let mut r = rx();
946        // The sender's clock runs 0.1% slow: each packet arrives a little
947        // later than its timestamp says.
948        for i in 0..3000u32 {
949            let now = i64::from(i) * 4 * MS;
950            let ts = (now - now / 1000) as u32;
951            r.on_data(now, &data(ISN + i, ts, b"x"));
952            r.on_timer(now);
953            delivered(&mut r);
954            sent(&mut r);
955        }
956        // 12 s in, the sender is 12 ms behind; corrections follow it in
957        // bounded steps.
958        assert!(r.drift.offset > 4 * MS, "{}", r.drift.offset);
959        assert!(r.drift.offset <= 12 * MS, "{}", r.drift.offset);
960    }
961
962    #[test]
963    fn drop_request_stops_naks() {
964        let mut r = rx();
965        r.on_data(0, &data(ISN, 0, b"0"));
966        r.on_data(0, &data(ISN + 5, 100 * MS as u32, b"5"));
967        sent(&mut r);
968        r.on_control(
969            MS,
970            &Control::DropRequest {
971                message: 0,
972                first: Seq::new(ISN + 1),
973                last: Seq::new(ISN + 4),
974            },
975        );
976        r.on_timer(150 * MS);
977        assert!(!sent(&mut r).iter().any(|c| matches!(c, Control::Nak(_))));
978    }
979}