Skip to main content

srt_runtime/packet/
ack.rs

1//! ACK (Acknowledgment) control packet — `draft-sharabayko-srt-01` §3.2.4,
2//! Figure 13.
3//!
4//! Three variants share the same header shape and differ only in how much of
5//! the CIF is present, distinguished by CIF length on the wire:
6//!
7//! - **Full** (28-byte CIF): all seven fields, sent every 10 ms.
8//! - **Small** (16-byte CIF): fields up to and including Available Buffer
9//!   Size.
10//! - **Light** (4-byte CIF): only Last Acknowledged Packet Sequence Number.
11
12use super::{Error, Result, be32, put_be32};
13
14/// CIF length, in bytes, of a Full ACK (§3.2.4).
15pub const ACK_CIF_LEN_FULL: usize = 28;
16/// CIF length, in bytes, of a Small ACK (§3.2.4).
17pub const ACK_CIF_LEN_SMALL: usize = 16;
18/// CIF length, in bytes, of a Light ACK (§3.2.4).
19pub const ACK_CIF_LEN_LIGHT: usize = 4;
20
21/// The ACK Control Information Field — its shape (Full/Small/Light) is
22/// selected by which fields are present on the wire (§3.2.4). Data-carrying
23/// ADT: see [`AckPacket`] for the label convention rationale.
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize))]
26#[non_exhaustive]
27pub enum AckCif {
28    /// Full ACK — all seven CIF fields.
29    Full {
30        /// Last Acknowledged Packet Sequence Number.
31        last_ack_seq: u32,
32        /// RTT estimate, in microseconds.
33        rtt_us: u32,
34        /// RTT variance, in microseconds.
35        rtt_var_us: u32,
36        /// Available receiver buffer size, in packets.
37        avail_buf_size: u32,
38        /// Packets receiving rate, in packets per second.
39        pkt_recv_rate: u32,
40        /// Estimated link capacity, in packets per second.
41        est_link_capacity: u32,
42        /// Estimated receiving rate, in bytes per second.
43        recv_rate_bps: u32,
44    },
45    /// Small ACK — fields up to and including Available Buffer Size.
46    Small {
47        /// Last Acknowledged Packet Sequence Number.
48        last_ack_seq: u32,
49        /// RTT estimate, in microseconds.
50        rtt_us: u32,
51        /// RTT variance, in microseconds.
52        rtt_var_us: u32,
53        /// Available receiver buffer size, in packets.
54        avail_buf_size: u32,
55    },
56    /// Light ACK — only Last Acknowledged Packet Sequence Number.
57    Light {
58        /// Last Acknowledged Packet Sequence Number.
59        last_ack_seq: u32,
60    },
61}
62
63/// ACK control packet (§3.2.4, Figure 13). `ack_number` occupies the header
64/// `Type-specific Information` word ("the sequential number of the full
65/// acknowledgment packet starting from 1"); per §3.2.4 it "should be set to
66/// 0" for Small/Light ACKs, but is stored and round-tripped verbatim
67/// regardless of variant.
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize))]
70pub struct AckPacket {
71    /// Acknowledgement Number.
72    pub ack_number: u32,
73    /// Timestamp (§3).
74    pub timestamp: u32,
75    /// Destination Socket ID (§3).
76    pub dest_socket_id: u32,
77    /// The CIF, shaped per variant.
78    pub cif: AckCif,
79}
80
81impl AckPacket {
82    pub(crate) fn parse_cif(
83        ack_number: u32,
84        timestamp: u32,
85        dest_socket_id: u32,
86        cif: &[u8],
87    ) -> Result<Self> {
88        let parsed = match cif.len() {
89            ACK_CIF_LEN_FULL => AckCif::Full {
90                last_ack_seq: be32(cif, 0),
91                rtt_us: be32(cif, 4),
92                rtt_var_us: be32(cif, 8),
93                avail_buf_size: be32(cif, 12),
94                pkt_recv_rate: be32(cif, 16),
95                est_link_capacity: be32(cif, 20),
96                recv_rate_bps: be32(cif, 24),
97            },
98            ACK_CIF_LEN_SMALL => AckCif::Small {
99                last_ack_seq: be32(cif, 0),
100                rtt_us: be32(cif, 4),
101                rtt_var_us: be32(cif, 8),
102                avail_buf_size: be32(cif, 12),
103            },
104            ACK_CIF_LEN_LIGHT => AckCif::Light {
105                last_ack_seq: be32(cif, 0),
106            },
107            other => return Err(Error::InvalidAckLength { len: other }),
108        };
109        Ok(AckPacket {
110            ack_number,
111            timestamp,
112            dest_socket_id,
113            cif: parsed,
114        })
115    }
116
117    pub(crate) fn cif_len(&self) -> usize {
118        match self.cif {
119            AckCif::Full { .. } => ACK_CIF_LEN_FULL,
120            AckCif::Small { .. } => ACK_CIF_LEN_SMALL,
121            AckCif::Light { .. } => ACK_CIF_LEN_LIGHT,
122        }
123    }
124
125    pub(crate) fn write_cif(&self, buf: &mut [u8]) -> Result<()> {
126        match self.cif {
127            AckCif::Full {
128                last_ack_seq,
129                rtt_us,
130                rtt_var_us,
131                avail_buf_size,
132                pkt_recv_rate,
133                est_link_capacity,
134                recv_rate_bps,
135            } => {
136                put_be32(buf, 0, last_ack_seq);
137                put_be32(buf, 4, rtt_us);
138                put_be32(buf, 8, rtt_var_us);
139                put_be32(buf, 12, avail_buf_size);
140                put_be32(buf, 16, pkt_recv_rate);
141                put_be32(buf, 20, est_link_capacity);
142                put_be32(buf, 24, recv_rate_bps);
143            }
144            AckCif::Small {
145                last_ack_seq,
146                rtt_us,
147                rtt_var_us,
148                avail_buf_size,
149            } => {
150                put_be32(buf, 0, last_ack_seq);
151                put_be32(buf, 4, rtt_us);
152                put_be32(buf, 8, rtt_var_us);
153                put_be32(buf, 12, avail_buf_size);
154            }
155            AckCif::Light { last_ack_seq } => {
156                put_be32(buf, 0, last_ack_seq);
157            }
158        }
159        Ok(())
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::super::control::ControlPacket;
166    use super::*;
167
168    #[test]
169    fn full_ack_round_trips_hand_computed_bytes() {
170        let pkt = ControlPacket::Ack(AckPacket {
171            ack_number: 42,
172            timestamp: 1000,
173            dest_socket_id: 2000,
174            cif: AckCif::Full {
175                last_ack_seq: 1,
176                rtt_us: 2,
177                rtt_var_us: 3,
178                avail_buf_size: 4,
179                pkt_recv_rate: 5,
180                est_link_capacity: 6,
181                recv_rate_bps: 7,
182            },
183        });
184        let mut buf = [0u8; 16 + 28];
185        let n = pkt.serialize_into(&mut buf).unwrap();
186        assert_eq!(n, 44);
187        assert_eq!(buf[0], 0x80); // F=1
188        assert_eq!(&buf[0..4], &(0x8002_0000u32).to_be_bytes()); // control type=2
189        assert_eq!(&buf[4..8], &42u32.to_be_bytes());
190        assert_eq!(&buf[16..20], &1u32.to_be_bytes());
191        assert_eq!(&buf[40..44], &7u32.to_be_bytes());
192        assert_eq!(ControlPacket::parse(&buf).unwrap(), pkt);
193    }
194
195    #[test]
196    fn small_and_light_ack_round_trip() {
197        for cif in [
198            AckCif::Small {
199                last_ack_seq: 10,
200                rtt_us: 20,
201                rtt_var_us: 30,
202                avail_buf_size: 40,
203            },
204            AckCif::Light { last_ack_seq: 99 },
205        ] {
206            let pkt = ControlPacket::Ack(AckPacket {
207                ack_number: 0,
208                timestamp: 1,
209                dest_socket_id: 2,
210                cif,
211            });
212            let mut buf = alloc::vec![0u8; pkt.serialized_len()];
213            pkt.serialize_into(&mut buf).unwrap();
214            assert_eq!(ControlPacket::parse(&buf).unwrap(), pkt);
215        }
216    }
217
218    #[test]
219    fn invalid_ack_cif_length_errs() {
220        let mut buf = [0u8; 16 + 5];
221        buf[0] = 0x80;
222        buf[1] = 0x02; // ACK
223        assert_eq!(
224            ControlPacket::parse(&buf).unwrap_err(),
225            Error::InvalidAckLength { len: 5 }
226        );
227    }
228
229    #[test]
230    fn mutate_field_changes_bytes() {
231        let mut pkt = AckPacket {
232            ack_number: 1,
233            timestamp: 2,
234            dest_socket_id: 3,
235            cif: AckCif::Light { last_ack_seq: 4 },
236        };
237        let mut buf1 = [0u8; 20];
238        ControlPacket::Ack(pkt).serialize_into(&mut buf1).unwrap();
239        pkt.ack_number = 99;
240        let mut buf2 = [0u8; 20];
241        ControlPacket::Ack(pkt).serialize_into(&mut buf2).unwrap();
242        assert_ne!(buf1, buf2);
243    }
244}