Skip to main content

srt_runtime/packet/
misc.rs

1//! The CIF-less / single-scalar-CIF control packets: Keep-Alive (§3.2.3),
2//! Congestion Warning (§3.2.6), Shutdown (§3.2.7), ACKACK (§3.2.8), Message
3//! Drop Request (§3.2.9), and Peer Error (§3.2.10).
4
5use super::{Error, Result, be32, put_be32};
6
7/// Peer error code for a file-system error — the only value
8/// `draft-sharabayko-srt-01` §3.2.10 currently defines.
9pub const PEER_ERROR_FILE_SYSTEM: u32 = 4000;
10
11/// Keep-Alive control packet (§3.2.3, Figure 12). No CIF.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize))]
14pub struct KeepAlivePacket {
15    /// Timestamp (§3).
16    pub timestamp: u32,
17    /// Destination Socket ID (§3).
18    pub dest_socket_id: u32,
19}
20
21/// Congestion Warning control packet (§3.2.6, Figure 15). Reserved for future
22/// use; no CIF.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize))]
25pub struct CongestionWarningPacket {
26    /// Timestamp (§3).
27    pub timestamp: u32,
28    /// Destination Socket ID (§3).
29    pub dest_socket_id: u32,
30}
31
32/// Shutdown control packet (§3.2.7, Figure 16). No CIF.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize))]
35pub struct ShutdownPacket {
36    /// Timestamp (§3).
37    pub timestamp: u32,
38    /// Destination Socket ID (§3).
39    pub dest_socket_id: u32,
40}
41
42/// ACKACK control packet (§3.2.8, Figure 17). No CIF.
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44#[cfg_attr(feature = "serde", derive(serde::Serialize))]
45pub struct AckAckPacket {
46    /// Acknowledgement Number of the Full ACK being acknowledged.
47    pub ack_number: u32,
48    /// Timestamp (§3).
49    pub timestamp: u32,
50    /// Destination Socket ID (§3).
51    pub dest_socket_id: u32,
52}
53
54/// Message Drop Request control packet (§3.2.9, Figure 18).
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize))]
57pub struct DropReqPacket {
58    /// The message number requested to be dropped (`0` if the sender no
59    /// longer has the packets and cannot restore it).
60    pub message_number: u32,
61    /// Timestamp (§3).
62    pub timestamp: u32,
63    /// Destination Socket ID (§3).
64    pub dest_socket_id: u32,
65    /// First Packet Sequence Number of the range to drop.
66    pub first_seq: u32,
67    /// Last Packet Sequence Number of the range to drop.
68    pub last_seq: u32,
69}
70
71impl DropReqPacket {
72    pub(crate) fn parse_cif(
73        message_number: u32,
74        timestamp: u32,
75        dest_socket_id: u32,
76        cif: &[u8],
77    ) -> Result<Self> {
78        if cif.len() != 8 {
79            return Err(Error::BufferTooShort {
80                need: 8,
81                have: cif.len(),
82                what: "drop request CIF",
83            });
84        }
85        Ok(DropReqPacket {
86            message_number,
87            timestamp,
88            dest_socket_id,
89            first_seq: be32(cif, 0),
90            last_seq: be32(cif, 4),
91        })
92    }
93
94    pub(crate) fn cif_len(&self) -> usize {
95        8
96    }
97
98    pub(crate) fn write_cif(&self, buf: &mut [u8]) {
99        put_be32(buf, 0, self.first_seq);
100        put_be32(buf, 4, self.last_seq);
101    }
102}
103
104/// Peer Error control packet (§3.2.10, Figure 19). No CIF.
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106#[cfg_attr(feature = "serde", derive(serde::Serialize))]
107pub struct PeerErrorPacket {
108    /// Peer error code (see [`PEER_ERROR_FILE_SYSTEM`]).
109    pub error_code: u32,
110    /// Timestamp (§3).
111    pub timestamp: u32,
112    /// Destination Socket ID (§3).
113    pub dest_socket_id: u32,
114}
115
116#[cfg(test)]
117mod tests {
118    use alloc::vec::Vec;
119
120    use super::super::control::ControlPacket;
121    use super::*;
122
123    #[test]
124    fn drop_req_round_trips() {
125        let d = DropReqPacket {
126            message_number: 7,
127            timestamp: 100,
128            dest_socket_id: 200,
129            first_seq: 10,
130            last_seq: 20,
131        };
132        let pkt = ControlPacket::DropReq(d);
133        let mut buf = [0u8; 24];
134        let n = pkt.serialize_into(&mut buf).unwrap();
135        assert_eq!(n, 24);
136        assert_eq!(&buf[4..8], &7u32.to_be_bytes()); // message number in word1
137        assert_eq!(&buf[16..20], &10u32.to_be_bytes());
138        assert_eq!(&buf[20..24], &20u32.to_be_bytes());
139        let parsed = ControlPacket::parse(&buf).unwrap();
140        assert_eq!(parsed, pkt);
141    }
142
143    #[test]
144    fn keepalive_congestion_shutdown_ackack_peererror_round_trip() {
145        let cases: Vec<ControlPacket> = alloc::vec![
146            ControlPacket::KeepAlive(KeepAlivePacket {
147                timestamp: 1,
148                dest_socket_id: 2
149            }),
150            ControlPacket::CongestionWarning(CongestionWarningPacket {
151                timestamp: 3,
152                dest_socket_id: 4
153            }),
154            ControlPacket::Shutdown(ShutdownPacket {
155                timestamp: 5,
156                dest_socket_id: 6
157            }),
158            ControlPacket::AckAck(AckAckPacket {
159                ack_number: 9,
160                timestamp: 7,
161                dest_socket_id: 8
162            }),
163            ControlPacket::PeerError(PeerErrorPacket {
164                error_code: PEER_ERROR_FILE_SYSTEM,
165                timestamp: 11,
166                dest_socket_id: 12
167            }),
168        ];
169        for pkt in cases {
170            let mut buf = [0u8; 16];
171            let n = pkt.serialize_into(&mut buf).unwrap();
172            assert_eq!(n, 16);
173            let parsed = ControlPacket::parse(&buf).unwrap();
174            assert_eq!(parsed, pkt);
175        }
176    }
177
178    #[test]
179    fn keepalive_rejects_trailing_bytes() {
180        let mut buf = [0u8; 17];
181        buf[0] = 0x80; // F=1
182        buf[1] = 0x01; // control type = 1 (KEEPALIVE)
183        assert!(matches!(
184            ControlPacket::parse(&buf),
185            Err(Error::UnexpectedTrailingBytes { .. })
186        ));
187    }
188}