xref: /webrtc/rtcp/src/header.rs (revision 97921129)
1 use crate::error::Error;
2 use util::marshal::{Marshal, MarshalSize, Unmarshal};
3 
4 use bytes::{Buf, BufMut};
5 
6 /// PacketType specifies the type of an RTCP packet
7 /// RTCP packet types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-4
8 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
9 #[repr(u8)]
10 pub enum PacketType {
11     #[default]
12     Unsupported = 0,
13     SenderReport = 200,              // RFC 3550, 6.4.1
14     ReceiverReport = 201,            // RFC 3550, 6.4.2
15     SourceDescription = 202,         // RFC 3550, 6.5
16     Goodbye = 203,                   // RFC 3550, 6.6
17     ApplicationDefined = 204,        // RFC 3550, 6.7 (unimplemented)
18     TransportSpecificFeedback = 205, // RFC 4585, 6051
19     PayloadSpecificFeedback = 206,   // RFC 4585, 6.3
20     ExtendedReport = 207,            // RFC 3611
21 }
22 
23 /// Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here
24 pub const FORMAT_SLI: u8 = 2;
25 /// Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here
26 pub const FORMAT_PLI: u8 = 1;
27 /// Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here
28 pub const FORMAT_FIR: u8 = 4;
29 /// Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here
30 pub const FORMAT_TLN: u8 = 1;
31 /// Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here
32 pub const FORMAT_RRR: u8 = 5;
33 /// Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here
34 pub const FORMAT_REMB: u8 = 15;
35 /// Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here.
36 /// https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5
37 pub const FORMAT_TCC: u8 = 15;
38 
39 impl std::fmt::Display for PacketType {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result40     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41         let s = match self {
42             PacketType::Unsupported => "Unsupported",
43             PacketType::SenderReport => "SR",
44             PacketType::ReceiverReport => "RR",
45             PacketType::SourceDescription => "SDES",
46             PacketType::Goodbye => "BYE",
47             PacketType::ApplicationDefined => "APP",
48             PacketType::TransportSpecificFeedback => "TSFB",
49             PacketType::PayloadSpecificFeedback => "PSFB",
50             PacketType::ExtendedReport => "XR",
51         };
52         write!(f, "{s}")
53     }
54 }
55 
56 impl From<u8> for PacketType {
from(b: u8) -> Self57     fn from(b: u8) -> Self {
58         match b {
59             200 => PacketType::SenderReport,              // RFC 3550, 6.4.1
60             201 => PacketType::ReceiverReport,            // RFC 3550, 6.4.2
61             202 => PacketType::SourceDescription,         // RFC 3550, 6.5
62             203 => PacketType::Goodbye,                   // RFC 3550, 6.6
63             204 => PacketType::ApplicationDefined,        // RFC 3550, 6.7 (unimplemented)
64             205 => PacketType::TransportSpecificFeedback, // RFC 4585, 6051
65             206 => PacketType::PayloadSpecificFeedback,   // RFC 4585, 6.3
66             207 => PacketType::ExtendedReport,            // RFC 3611
67             _ => PacketType::Unsupported,
68         }
69     }
70 }
71 
72 pub const RTP_VERSION: u8 = 2;
73 pub const VERSION_SHIFT: u8 = 6;
74 pub const VERSION_MASK: u8 = 0x3;
75 pub const PADDING_SHIFT: u8 = 5;
76 pub const PADDING_MASK: u8 = 0x1;
77 pub const COUNT_SHIFT: u8 = 0;
78 pub const COUNT_MASK: u8 = 0x1f;
79 
80 pub const HEADER_LENGTH: usize = 4;
81 pub const COUNT_MAX: usize = (1 << 5) - 1;
82 pub const SSRC_LENGTH: usize = 4;
83 pub const SDES_MAX_OCTET_COUNT: usize = (1 << 8) - 1;
84 
85 /// A Header is the common header shared by all RTCP packets
86 #[derive(Debug, PartialEq, Eq, Default, Clone)]
87 pub struct Header {
88     /// If the padding bit is set, this individual RTCP packet contains
89     /// some additional padding octets at the end which are not part of
90     /// the control information but are included in the length field.
91     pub padding: bool,
92     /// The number of reception reports, sources contained or FMT in this packet (depending on the Type)
93     pub count: u8,
94     /// The RTCP packet type for this packet
95     pub packet_type: PacketType,
96     /// The length of this RTCP packet in 32-bit words minus one,
97     /// including the header and any padding.
98     pub length: u16,
99 }
100 
101 /// Marshal encodes the Header in binary
102 impl MarshalSize for Header {
marshal_size(&self) -> usize103     fn marshal_size(&self) -> usize {
104         HEADER_LENGTH
105     }
106 }
107 
108 impl Marshal for Header {
marshal_to(&self, mut buf: &mut [u8]) -> Result<usize, util::Error>109     fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize, util::Error> {
110         if self.count > 31 {
111             return Err(Error::InvalidHeader.into());
112         }
113         if buf.remaining_mut() < HEADER_LENGTH {
114             return Err(Error::BufferTooShort.into());
115         }
116 
117         /*
118          *  0                   1                   2                   3
119          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
120          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
121          * |V=2|P|    RC   |   PT=SR=200   |             length            |
122          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
123          */
124         let b0 = (RTP_VERSION << VERSION_SHIFT)
125             | ((self.padding as u8) << PADDING_SHIFT)
126             | (self.count << COUNT_SHIFT);
127 
128         buf.put_u8(b0);
129         buf.put_u8(self.packet_type as u8);
130         buf.put_u16(self.length);
131 
132         Ok(HEADER_LENGTH)
133     }
134 }
135 
136 impl Unmarshal for Header {
137     /// Unmarshal decodes the Header from binary
unmarshal<B>(raw_packet: &mut B) -> Result<Self, util::Error> where Self: Sized, B: Buf,138     fn unmarshal<B>(raw_packet: &mut B) -> Result<Self, util::Error>
139     where
140         Self: Sized,
141         B: Buf,
142     {
143         if raw_packet.remaining() < HEADER_LENGTH {
144             return Err(Error::PacketTooShort.into());
145         }
146 
147         /*
148          *  0                   1                   2                   3
149          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
150          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151          * |V=2|P|    RC   |      PT       |             length            |
152          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153          */
154         let b0 = raw_packet.get_u8();
155         let version = (b0 >> VERSION_SHIFT) & VERSION_MASK;
156         if version != RTP_VERSION {
157             return Err(Error::BadVersion.into());
158         }
159 
160         let padding = ((b0 >> PADDING_SHIFT) & PADDING_MASK) > 0;
161         let count = (b0 >> COUNT_SHIFT) & COUNT_MASK;
162         let packet_type = PacketType::from(raw_packet.get_u8());
163         let length = raw_packet.get_u16();
164 
165         Ok(Header {
166             padding,
167             count,
168             packet_type,
169             length,
170         })
171     }
172 }
173 
174 #[cfg(test)]
175 mod test {
176     use super::*;
177     use bytes::Bytes;
178 
179     #[test]
test_header_unmarshal()180     fn test_header_unmarshal() {
181         let tests = vec![
182             (
183                 "valid",
184                 Bytes::from_static(&[
185                     // v=2, p=0, count=1, RR, len=7
186                     0x81u8, 0xc9, 0x00, 0x07,
187                 ]),
188                 Header {
189                     padding: false,
190                     count: 1,
191                     packet_type: PacketType::ReceiverReport,
192                     length: 7,
193                 },
194                 None,
195             ),
196             (
197                 "also valid",
198                 Bytes::from_static(&[
199                     // v=2, p=1, count=1, BYE, len=7
200                     0xa1, 0xcc, 0x00, 0x07,
201                 ]),
202                 Header {
203                     padding: true,
204                     count: 1,
205                     packet_type: PacketType::ApplicationDefined,
206                     length: 7,
207                 },
208                 None,
209             ),
210             (
211                 "bad version",
212                 Bytes::from_static(&[
213                     // v=0, p=0, count=0, RR, len=4
214                     0x00, 0xc9, 0x00, 0x04,
215                 ]),
216                 Header {
217                     padding: false,
218                     count: 0,
219                     packet_type: PacketType::Unsupported,
220                     length: 0,
221                 },
222                 Some(Error::BadVersion),
223             ),
224         ];
225 
226         for (name, data, want, want_error) in tests {
227             let buf = &mut data.clone();
228             let got = Header::unmarshal(buf);
229 
230             assert_eq!(
231                 got.is_err(),
232                 want_error.is_some(),
233                 "Unmarshal {name}: err = {got:?}, want {want_error:?}"
234             );
235 
236             if let Some(want_error) = want_error {
237                 let got_err = got.err().unwrap();
238                 assert_eq!(
239                     want_error, got_err,
240                     "Unmarshal {name}: err = {got_err:?}, want {want_error:?}",
241                 );
242             } else {
243                 let actual = got.unwrap();
244                 assert_eq!(
245                     actual, want,
246                     "Unmarshal {name}: got {actual:?}, want {want:?}"
247                 );
248             }
249         }
250     }
251 
252     #[test]
test_header_roundtrip()253     fn test_header_roundtrip() {
254         let tests = vec![
255             (
256                 "valid",
257                 Header {
258                     padding: true,
259                     count: 31,
260                     packet_type: PacketType::SenderReport,
261                     length: 4,
262                 },
263                 None,
264             ),
265             (
266                 "also valid",
267                 Header {
268                     padding: false,
269                     count: 28,
270                     packet_type: PacketType::ReceiverReport,
271                     length: 65535,
272                 },
273                 None,
274             ),
275             (
276                 "invalid count",
277                 Header {
278                     padding: false,
279                     count: 40,
280                     packet_type: PacketType::Unsupported,
281                     length: 0,
282                 },
283                 Some(Error::InvalidHeader),
284             ),
285         ];
286 
287         for (name, want, want_error) in tests {
288             let got = want.marshal();
289 
290             assert_eq!(
291                 got.is_ok(),
292                 want_error.is_none(),
293                 "Marshal {name}: err = {got:?}, want {want_error:?}"
294             );
295 
296             if let Some(err) = want_error {
297                 let got_err = got.err().unwrap();
298                 assert_eq!(
299                     err, got_err,
300                     "Unmarshal {name} rr: err = {got_err:?}, want {err:?}",
301                 );
302             } else {
303                 let data = got.ok().unwrap();
304                 let buf = &mut data.clone();
305                 let actual = Header::unmarshal(buf).unwrap_or_else(|_| panic!("Unmarshal {name}"));
306 
307                 assert_eq!(
308                     actual, want,
309                     "{name} round trip: got {actual:?}, want {want:?}"
310                 )
311             }
312         }
313     }
314 }
315