1 use super::*;
2 use crate::goodbye::Goodbye;
3 use crate::payload_feedbacks::picture_loss_indication::PictureLossIndication;
4 
5 // An RTCP packet from a packet dump
6 const REAL_PACKET: [u8; 116] = [
7     // Receiver Report (offset=0)
8     0x81, 0xc9, 0x0, 0x7, // v=2, p=0, count=1, RR, len=7
9     0x90, 0x2f, 0x9e, 0x2e, // ssrc=0x902f9e2e
10     0xbc, 0x5e, 0x9a, 0x40, // ssrc=0xbc5e9a40
11     0x0, 0x0, 0x0, 0x0, // fracLost=0, totalLost=0
12     0x0, 0x0, 0x46, 0xe1, // lastSeq=0x46e1
13     0x0, 0x0, 0x1, 0x11, // jitter=273
14     0x9, 0xf3, 0x64, 0x32, // lsr=0x9f36432
15     0x0, 0x2, 0x4a, 0x79, // delay=150137
16     // Source Description (offset=32)
17     0x81, 0xca, 0x0, 0xc, // v=2, p=0, count=1, SDES, len=12
18     0x90, 0x2f, 0x9e, 0x2e, // ssrc=0x902f9e2e
19     0x1, 0x26, // CNAME, len=38
20     0x7b, 0x39, 0x63, 0x30, 0x30, 0x65, 0x62, 0x39, 0x32, 0x2d, 0x31, 0x61, 0x66, 0x62, 0x2d, 0x39,
21     0x64, 0x34, 0x39, 0x2d, 0x61, 0x34, 0x37, 0x64, 0x2d, 0x39, 0x31, 0x66, 0x36, 0x34, 0x65, 0x65,
22     0x65, 0x36, 0x39, 0x66, 0x35, 0x7d, // text="{9c00eb92-1afb-9d49-a47d-91f64eee69f5}"
23     0x0, 0x0, 0x0, 0x0, // END + padding
24     // Goodbye (offset=84)
25     0x81, 0xcb, 0x0, 0x1, // v=2, p=0, count=1, BYE, len=1
26     0x90, 0x2f, 0x9e, 0x2e, // source=0x902f9e2e
27     0x81, 0xce, 0x0, 0x2, // Picture Loss Indication (offset=92)
28     0x90, 0x2f, 0x9e, 0x2e, // sender=0x902f9e2e
29     0x90, 0x2f, 0x9e, 0x2e, // media=0x902f9e2e
30     0x85, 0xcd, 0x0, 0x2, // RapidResynchronizationRequest (offset=104)
31     0x90, 0x2f, 0x9e, 0x2e, // sender=0x902f9e2e
32     0x90, 0x2f, 0x9e, 0x2e, // media=0x902f9e2e
33 ];
34 
35 #[test]
test_read_eof()36 fn test_read_eof() {
37     let mut short_header = Bytes::from_static(&[
38         0x81, 0xc9, // missing type & len
39     ]);
40     let result = unmarshal(&mut short_header);
41     assert!(result.is_err(), "missing type & len");
42 }
43 
44 #[test]
test_bad_compound()45 fn test_bad_compound() {
46     let mut bad_compound = Bytes::copy_from_slice(&REAL_PACKET[..34]);
47     let result = unmarshal(&mut bad_compound);
48     assert!(result.is_err(), "trailing data!");
49 
50     let mut bad_compound = Bytes::copy_from_slice(&REAL_PACKET[84..104]);
51     let p = unmarshal(&mut bad_compound).expect("Error unmarshalling packet");
52     let compound = CompoundPacket(p);
53 
54     // this should return an error,
55     // it violates the "must start with RR or SR" rule
56     match compound.validate() {
57         Ok(_) => panic!("validation should return an error"),
58 
59         Err(err) => {
60             let a = Error::BadFirstPacket;
61             assert_eq!(
62                 Error::BadFirstPacket,
63                 err,
64                 "Unmarshal(badcompound) err={err:?}, want {a:?}",
65             );
66         }
67     };
68 
69     let compound_len = compound.0.len();
70     assert_eq!(
71         compound_len, 2,
72         "Unmarshal(badcompound) len={}, want {}",
73         compound_len, 2
74     );
75 
76     if compound.0[0].as_any().downcast_ref::<Goodbye>().is_none() {
77         panic!("Unmarshal(badcompound), want Goodbye")
78     }
79 
80     if compound.0[1]
81         .as_any()
82         .downcast_ref::<PictureLossIndication>()
83         .is_none()
84     {
85         panic!("Unmarshal(badcompound), want PictureLossIndication")
86     }
87 }
88 
89 #[test]
test_valid_packet()90 fn test_valid_packet() {
91     let cname = SourceDescription {
92         chunks: vec![SourceDescriptionChunk {
93             source: 1234,
94             items: vec![SourceDescriptionItem {
95                 sdes_type: SdesType::SdesCname,
96                 text: Bytes::from_static(b"cname"),
97             }],
98         }],
99     };
100 
101     let tests: Vec<(&str, CompoundPacket, Option<Error>)> = vec![
102         (
103             "no cname",
104             CompoundPacket(vec![Box::<SenderReport>::default()]),
105             Some(Error::MissingCname),
106         ),
107         (
108             "SDES / no cname",
109             CompoundPacket(vec![
110                 Box::<SenderReport>::default(),
111                 Box::<SourceDescription>::default(),
112             ]),
113             Some(Error::MissingCname),
114         ),
115         (
116             "just SR",
117             CompoundPacket(vec![
118                 Box::<SenderReport>::default(),
119                 Box::new(cname.to_owned()),
120             ]),
121             None,
122         ),
123         (
124             "multiple SRs",
125             CompoundPacket(vec![
126                 Box::<SenderReport>::default(),
127                 Box::<SenderReport>::default(),
128                 Box::new(cname.clone()),
129             ]),
130             Some(Error::PacketBeforeCname),
131         ),
132         (
133             "just RR",
134             CompoundPacket(vec![
135                 Box::<ReceiverReport>::default(),
136                 Box::new(cname.clone()),
137             ]),
138             None,
139         ),
140         (
141             "multiple RRs",
142             CompoundPacket(vec![
143                 Box::<ReceiverReport>::default(),
144                 Box::new(cname.clone()),
145                 Box::<ReceiverReport>::default(),
146             ]),
147             None,
148         ),
149         (
150             "goodbye",
151             CompoundPacket(vec![
152                 Box::<ReceiverReport>::default(),
153                 Box::new(cname),
154                 Box::<Goodbye>::default(),
155             ]),
156             None,
157         ),
158     ];
159 
160     for (name, packet, error) in tests {
161         let result = packet.validate();
162         assert_eq!(result.is_ok(), error.is_none());
163         if let (Some(err), Err(got)) = (error, result) {
164             assert_eq!(err, got, "Valid({name}) = {got:?}, want {err:?}");
165         }
166     }
167 }
168 
169 #[test]
test_cname()170 fn test_cname() {
171     let cname = SourceDescription {
172         chunks: vec![SourceDescriptionChunk {
173             source: 1234,
174             items: vec![SourceDescriptionItem {
175                 sdes_type: SdesType::SdesCname,
176                 text: Bytes::from_static(b"cname"),
177             }],
178         }],
179     };
180 
181     let tests: Vec<(&str, CompoundPacket, Option<Error>, &str)> = vec![
182         (
183             "no cname",
184             CompoundPacket(vec![Box::<SenderReport>::default()]),
185             Some(Error::MissingCname),
186             "",
187         ),
188         (
189             "SDES / no cname",
190             CompoundPacket(vec![
191                 Box::<SenderReport>::default(),
192                 Box::<SourceDescription>::default(),
193             ]),
194             Some(Error::MissingCname),
195             "",
196         ),
197         (
198             "just SR",
199             CompoundPacket(vec![
200                 Box::<SenderReport>::default(),
201                 Box::new(cname.clone()),
202             ]),
203             None,
204             "cname",
205         ),
206         (
207             "multiple SRs",
208             CompoundPacket(vec![
209                 Box::<SenderReport>::default(),
210                 Box::<SenderReport>::default(),
211                 Box::new(cname.clone()),
212             ]),
213             Some(Error::PacketBeforeCname),
214             "",
215         ),
216         (
217             "just RR",
218             CompoundPacket(vec![
219                 Box::<ReceiverReport>::default(),
220                 Box::new(cname.clone()),
221             ]),
222             None,
223             "cname",
224         ),
225         (
226             "multiple RRs",
227             CompoundPacket(vec![
228                 Box::<ReceiverReport>::default(),
229                 Box::<ReceiverReport>::default(),
230                 Box::new(cname.clone()),
231             ]),
232             None,
233             "cname",
234         ),
235         (
236             "goodbye",
237             CompoundPacket(vec![
238                 Box::<ReceiverReport>::default(),
239                 Box::new(cname),
240                 Box::<Goodbye>::default(),
241             ]),
242             None,
243             "cname",
244         ),
245     ];
246 
247     for (name, compound_packet, want_error, text) in tests {
248         let err = compound_packet.validate();
249         assert_eq!(err.is_err(), want_error.is_some());
250         if let (Some(want), Err(err)) = (&want_error, err) {
251             assert_eq!(*want, err, "Valid({name}) = {err:?}, want {want:?}");
252         }
253 
254         let name_result = compound_packet.cname();
255         assert_eq!(name_result.is_err(), want_error.is_some());
256 
257         match name_result {
258             Ok(e) => {
259                 assert_eq!(e, text, "CNAME({name}) = {e:?}, want {text}",);
260             }
261 
262             Err(err) => {
263                 if let Some(want) = &want_error {
264                     assert_eq!(*want, err, "CNAME({name}) = {err:?}, want {want:?}");
265                 }
266             }
267         }
268     }
269 }
270 
271 #[test]
test_compound_packet_roundtrip()272 fn test_compound_packet_roundtrip() {
273     let cname = SourceDescription {
274         chunks: vec![SourceDescriptionChunk {
275             source: 1234,
276             items: vec![SourceDescriptionItem {
277                 sdes_type: SdesType::SdesCname,
278                 text: Bytes::from_static(b"cname"),
279             }],
280         }],
281     };
282 
283     let tests = vec![
284         (
285             "goodbye",
286             CompoundPacket(vec![
287                 Box::<ReceiverReport>::default(),
288                 Box::new(cname),
289                 Box::new(Goodbye {
290                     sources: vec![1234],
291                     ..Default::default()
292                 }),
293             ]),
294             None,
295         ),
296         (
297             "no cname",
298             CompoundPacket(vec![Box::<ReceiverReport>::default()]),
299             Some(Error::MissingCname),
300         ),
301     ];
302 
303     for (name, packet, marshal_error) in tests {
304         let result = packet.marshal();
305         if let Some(err) = marshal_error {
306             if let Err(got) = result {
307                 assert_eq!(err, got, "marshal {name} header: err = {got}, want {err}");
308             } else {
309                 panic!("want error in test {name}");
310             }
311             continue;
312         } else {
313             assert!(result.is_ok(), "must no error in test {name}");
314         }
315 
316         let data1 = result.unwrap();
317         let c = CompoundPacket::unmarshal(&mut data1.clone())
318             .unwrap_or_else(|_| panic!("unmarshal {name} error"));
319 
320         let data2 = c
321             .marshal()
322             .unwrap_or_else(|_| panic!("marshal {name} error"));
323 
324         assert_eq!(
325             data1, data2,
326             "Unmarshal(Marshal({name:?})) = {data1:?}, want {data2:?}"
327         )
328     }
329 }
330