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