Skip to main content

rtc_rtcp/
packet.rs

1use crate::{
2    goodbye::*, header::*, payload_feedbacks::full_intra_request::*,
3    payload_feedbacks::picture_loss_indication::*,
4    payload_feedbacks::receiver_estimated_maximum_bitrate::*,
5    payload_feedbacks::slice_loss_indication::*, raw_packet::*, receiver_report::*,
6    sender_report::*, source_description::*, transport_feedbacks::cc_feedback_report::*,
7    transport_feedbacks::rapid_resynchronization_request::*,
8    transport_feedbacks::transport_layer_cc::*, transport_feedbacks::transport_layer_nack::*,
9};
10use shared::{
11    error::{Error, Result},
12    marshal::{Marshal, Unmarshal},
13};
14
15use crate::extended_report::ExtendedReport;
16use bytes::{Buf, BytesMut};
17use std::any::Any;
18use std::fmt;
19
20/// Packet represents an RTCP packet, a protocol used for out-of-band statistics and
21/// control information for an RTP session
22pub trait Packet: Send + Sync + Marshal + Unmarshal + fmt::Display + fmt::Debug {
23    /// This packet's RTCP header.
24    fn header(&self) -> Header;
25    /// The SSRCs this packet is about.
26    ///
27    /// Used to route feedback: a report's destination SSRCs identify the streams it concerns,
28    /// which is how an SFU decides where to forward it.
29    fn destination_ssrc(&self) -> Vec<u32>;
30    /// The encoded size in bytes, header and padding included.
31    fn raw_size(&self) -> usize;
32    /// Downcasting hook, so a caller holding `Box<dyn Packet>` can recover the concrete type.
33    fn as_any(&self) -> &dyn Any;
34    /// Compares against another packet, since `PartialEq` is not object safe.
35    fn equal(&self, other: &dyn Packet) -> bool;
36    /// Clones this packet behind a trait object, since `Clone` is not object safe.
37    fn cloned(&self) -> Box<dyn Packet>;
38}
39
40impl PartialEq for dyn Packet {
41    fn eq(&self, other: &Self) -> bool {
42        self.equal(other)
43    }
44}
45
46impl Clone for Box<dyn Packet> {
47    fn clone(&self) -> Box<dyn Packet> {
48        self.cloned()
49    }
50}
51
52/// marshal takes an array of Packets and serializes them to a single buffer
53pub fn marshal(packets: &[Box<dyn Packet>]) -> Result<BytesMut> {
54    // Size the compound packet up front and marshal each sub-packet straight
55    // into it, instead of allocating a fresh BytesMut per sub-packet
56    // (p.marshal()) and copying it in.
57    let total: usize = packets.iter().map(|p| p.marshal_size()).sum();
58    let mut out = BytesMut::new();
59    out.resize(total, 0);
60    let mut offset = 0;
61    for p in packets {
62        offset += p.marshal_to(&mut out[offset..])?;
63    }
64    Ok(out)
65}
66
67/// Unmarshal takes an entire udp datagram (which may consist of multiple RTCP packets) and
68/// returns the unmarshaled packets it contains.
69///
70/// If this is a reduced-size RTCP packet a feedback packet (Goodbye, SliceLossIndication, etc)
71/// will be returned. Otherwise, the underlying type of the returned packet will be
72/// CompoundPacket.
73pub fn unmarshal<B>(raw_data: &mut B) -> Result<Vec<Box<dyn Packet>>>
74where
75    B: Buf,
76{
77    let mut packets = vec![];
78
79    while raw_data.has_remaining() {
80        let p = unmarshaller(raw_data)?;
81        packets.push(p);
82    }
83
84    match packets.len() {
85        // Empty Packet
86        0 => Err(Error::InvalidHeader),
87
88        // Multiple Packet
89        _ => Ok(packets),
90    }
91}
92
93/// unmarshaller is a factory which pulls the first RTCP packet from a bytestream,
94/// and returns it's parsed representation, and the amount of data that was processed.
95pub(crate) fn unmarshaller<B>(raw_data: &mut B) -> Result<Box<dyn Packet>>
96where
97    B: Buf,
98{
99    let h = Header::unmarshal(raw_data)?;
100
101    let length = (h.length as usize) * 4;
102    if length > raw_data.remaining() {
103        return Err(Error::PacketTooShort);
104    }
105
106    // Re-serialize the just-parsed header into a stack buffer rather than a fresh
107    // heap `BytesMut` (`h.marshal()`), then chain it with the body so the
108    // sub-packet unmarshaller re-reads the same bytes -- one fewer heap
109    // allocation per RTCP sub-packet on the receive path.
110    let mut header_buf = [0u8; HEADER_LENGTH];
111    h.marshal_to(&mut header_buf[..])?;
112    let mut in_packet = header_buf.as_slice().chain(raw_data.take(length));
113
114    let p: Box<dyn Packet> = match h.packet_type {
115        PacketType::SenderReport => Box::new(SenderReport::unmarshal(&mut in_packet)?),
116        PacketType::ReceiverReport => Box::new(ReceiverReport::unmarshal(&mut in_packet)?),
117        PacketType::SourceDescription => Box::new(SourceDescription::unmarshal(&mut in_packet)?),
118        PacketType::Goodbye => Box::new(Goodbye::unmarshal(&mut in_packet)?),
119
120        PacketType::TransportSpecificFeedback => match h.count {
121            FORMAT_TLN => Box::new(TransportLayerNack::unmarshal(&mut in_packet)?),
122            FORMAT_RRR => Box::new(RapidResynchronizationRequest::unmarshal(&mut in_packet)?),
123            FORMAT_TCC => Box::new(TransportLayerCc::unmarshal(&mut in_packet)?),
124            FORMAT_CCFB => Box::new(CcFeedbackReport::unmarshal(&mut in_packet)?),
125            _ => Box::new(RawPacket::unmarshal(&mut in_packet)?),
126        },
127        PacketType::PayloadSpecificFeedback => match h.count {
128            FORMAT_PLI => Box::new(PictureLossIndication::unmarshal(&mut in_packet)?),
129            FORMAT_SLI => Box::new(SliceLossIndication::unmarshal(&mut in_packet)?),
130            FORMAT_REMB => Box::new(ReceiverEstimatedMaximumBitrate::unmarshal(&mut in_packet)?),
131            FORMAT_FIR => Box::new(FullIntraRequest::unmarshal(&mut in_packet)?),
132            _ => Box::new(RawPacket::unmarshal(&mut in_packet)?),
133        },
134        PacketType::ExtendedReport => Box::new(ExtendedReport::unmarshal(&mut in_packet)?),
135        _ => Box::new(RawPacket::unmarshal(&mut in_packet)?),
136    };
137
138    Ok(p)
139}
140
141#[cfg(test)]
142mod test {
143    use super::*;
144    use crate::reception_report::*;
145    use bytes::Bytes;
146
147    #[test]
148    fn test_packet_unmarshal() {
149        let mut data = Bytes::from_static(&[
150            // Receiver Report (offset=0)
151            0x81, 0xc9, 0x0, 0x7, // v=2, p=0, count=1, RR, len=7
152            0x90, 0x2f, 0x9e, 0x2e, // ssrc=0x902f9e2e
153            0xbc, 0x5e, 0x9a, 0x40, // ssrc=0xbc5e9a40
154            0x0, 0x0, 0x0, 0x0, // fracLost=0, totalLost=0
155            0x0, 0x0, 0x46, 0xe1, // lastSeq=0x46e1
156            0x0, 0x0, 0x1, 0x11, // jitter=273
157            0x9, 0xf3, 0x64, 0x32, // lsr=0x9f36432
158            0x0, 0x2, 0x4a, 0x79, // delay=150137
159            // Source Description (offset=32)
160            0x81, 0xca, 0x0, 0xc, // v=2, p=0, count=1, SDES, len=12
161            0x90, 0x2f, 0x9e, 0x2e, // ssrc=0x902f9e2e
162            0x1, 0x26, // CNAME, len=38
163            0x7b, 0x39, 0x63, 0x30, 0x30, 0x65, 0x62, 0x39, 0x32, 0x2d, 0x31, 0x61, 0x66, 0x62,
164            0x2d, 0x39, 0x64, 0x34, 0x39, 0x2d, 0x61, 0x34, 0x37, 0x64, 0x2d, 0x39, 0x31, 0x66,
165            0x36, 0x34, 0x65, 0x65, 0x65, 0x36, 0x39, 0x66, 0x35,
166            0x7d, // text="{9c00eb92-1afb-9d49-a47d-91f64eee69f5}"
167            0x0, 0x0, 0x0, 0x0, // END + padding
168            // Goodbye (offset=84)
169            0x81, 0xcb, 0x0, 0x1, // v=2, p=0, count=1, BYE, len=1
170            0x90, 0x2f, 0x9e, 0x2e, // source=0x902f9e2e
171            0x81, 0xce, 0x0, 0x2, // Picture Loss Indication (offset=92)
172            0x90, 0x2f, 0x9e, 0x2e, // sender=0x902f9e2e
173            0x90, 0x2f, 0x9e, 0x2e, // media=0x902f9e2e
174            0x85, 0xcd, 0x0, 0x2, // RapidResynchronizationRequest (offset=104)
175            0x90, 0x2f, 0x9e, 0x2e, // sender=0x902f9e2e
176            0x90, 0x2f, 0x9e, 0x2e, // media=0x902f9e2e
177        ]);
178
179        let packet = unmarshal(&mut data).expect("Error unmarshalling packets");
180
181        let a = ReceiverReport {
182            ssrc: 0x902f9e2e,
183            reports: vec![ReceptionReport {
184                ssrc: 0xbc5e9a40,
185                fraction_lost: 0,
186                total_lost: 0,
187                last_sequence_number: 0x46e1,
188                jitter: 273,
189                last_sender_report: 0x9f36432,
190                delay: 150137,
191            }],
192            ..Default::default()
193        };
194
195        let b = SourceDescription {
196            chunks: vec![SourceDescriptionChunk {
197                source: 0x902f9e2e,
198                items: vec![SourceDescriptionItem {
199                    sdes_type: SdesType::SdesCname,
200                    text: Bytes::from_static(b"{9c00eb92-1afb-9d49-a47d-91f64eee69f5}"),
201                }],
202            }],
203        };
204
205        let c = Goodbye {
206            sources: vec![0x902f9e2e],
207            ..Default::default()
208        };
209
210        let d = PictureLossIndication {
211            sender_ssrc: 0x902f9e2e,
212            media_ssrc: 0x902f9e2e,
213        };
214
215        let e = RapidResynchronizationRequest {
216            sender_ssrc: 0x902f9e2e,
217            media_ssrc: 0x902f9e2e,
218        };
219
220        let expected: Vec<Box<dyn Packet>> = vec![
221            Box::new(a),
222            Box::new(b),
223            Box::new(c),
224            Box::new(d),
225            Box::new(e),
226        ];
227
228        assert!(packet == expected, "Invalid packets");
229    }
230
231    #[test]
232    fn test_packet_unmarshal_empty() -> Result<()> {
233        let result = unmarshal(&mut Bytes::new());
234        if let Err(got) = result {
235            let want = Error::InvalidHeader;
236            assert_eq!(got, want, "Unmarshal(nil) err = {got}, want {want}");
237        } else {
238            panic!("want error");
239        }
240
241        Ok(())
242    }
243
244    #[test]
245    fn test_packet_invalid_header_length() -> Result<()> {
246        let mut data = Bytes::from_static(&[
247            // Goodbye (offset=84)
248            // v=2, p=0, count=1, BYE, len=100
249            0x81, 0xcb, 0x0, 0x64,
250        ]);
251
252        let result = unmarshal(&mut data);
253        if let Err(got) = result {
254            let want = Error::PacketTooShort;
255            assert_eq!(
256                got, want,
257                "Unmarshal(invalid_header_length) err = {got}, want {want}"
258            );
259        } else {
260            panic!("want error");
261        }
262
263        Ok(())
264    }
265    #[test]
266    fn test_packet_unmarshal_firefox() -> Result<()> {
267        // issue report from https://github.com/webrtc-rs/srtp/issues/7
268        let tests = vec![
269            Bytes::from_static(&[
270                143, 205, 0, 6, 65, 227, 184, 49, 118, 243, 78, 96, 42, 63, 0, 5, 12, 162, 166, 0,
271                32, 5, 200, 4, 0, 4, 0, 0,
272            ]),
273            Bytes::from_static(&[
274                143, 205, 0, 9, 65, 227, 184, 49, 118, 243, 78, 96, 42, 68, 0, 17, 12, 162, 167, 1,
275                32, 17, 88, 0, 4, 0, 4, 8, 108, 0, 4, 0, 4, 12, 0, 4, 0, 4, 4, 0,
276            ]),
277            Bytes::from_static(&[
278                143, 205, 0, 8, 65, 227, 184, 49, 118, 243, 78, 96, 42, 91, 0, 12, 12, 162, 168, 3,
279                32, 12, 220, 4, 0, 4, 0, 8, 128, 4, 0, 4, 0, 8, 0, 0,
280            ]),
281            Bytes::from_static(&[
282                143, 205, 0, 7, 65, 227, 184, 49, 118, 243, 78, 96, 42, 103, 0, 8, 12, 162, 169, 4,
283                32, 8, 232, 4, 0, 4, 0, 4, 4, 0, 0, 0,
284            ]),
285        ];
286
287        for mut test in tests {
288            unmarshal(&mut test)?;
289        }
290
291        Ok(())
292    }
293
294    // Round-trips a compound through packet::marshal -> packet::unmarshal ->
295    // packet::marshal and asserts byte-stability, covering the in-place compound
296    // marshal and the sub-packet unmarshaller.
297    #[test]
298    fn test_marshal_compound_roundtrip() -> Result<()> {
299        use crate::reception_report::ReceptionReport;
300
301        let rr = ReceiverReport {
302            ssrc: 0x902f9e2e,
303            reports: vec![ReceptionReport {
304                ssrc: 0xbc5e9a40,
305                fraction_lost: 0,
306                total_lost: 0,
307                last_sequence_number: 0x46e1,
308                jitter: 273,
309                last_sender_report: 0x9f36432,
310                delay: 150137,
311            }],
312            ..Default::default()
313        };
314        let pli = PictureLossIndication {
315            sender_ssrc: 0x902f9e2e,
316            media_ssrc: 0x902f9e2e,
317        };
318        let packets: Vec<Box<dyn Packet>> = vec![Box::new(rr), Box::new(pli)];
319
320        let raw1 = marshal(&packets)?;
321        let out = unmarshal(&mut raw1.clone().freeze())?;
322        assert_eq!(out.len(), 2, "expected two sub-packets");
323        let raw2 = marshal(&out)?;
324        assert_eq!(raw1, raw2, "compound marshal/unmarshal round-trip mismatch");
325
326        Ok(())
327    }
328}