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