1#![deny(missing_docs)]
10
11use packet_dissector_core::dissector::{DispatchHint, DissectResult, Dissector};
12use packet_dissector_core::error::PacketError;
13use packet_dissector_core::field::{FieldDescriptor, FieldType, FieldValue};
14use packet_dissector_core::packet::DissectBuffer;
15use packet_dissector_core::util::{read_be_u16, read_be_u32};
16
17const MIN_HEADER_SIZE: usize = 12;
21
22const RTP_VERSION: u8 = 2;
26
27const FD_VERSION: usize = 0;
29const FD_PADDING: usize = 1;
30const FD_EXTENSION: usize = 2;
31const FD_CSRC_COUNT: usize = 3;
32const FD_MARKER: usize = 4;
33const FD_PAYLOAD_TYPE: usize = 5;
34const FD_SEQUENCE_NUMBER: usize = 6;
35const FD_TIMESTAMP: usize = 7;
36const FD_SSRC: usize = 8;
37const FD_CSRC_LIST: usize = 9;
38const FD_PAYLOAD: usize = 10;
39const FD_PADDING_LENGTH: usize = 11;
40const FD_EXT_PROFILE: usize = 12;
41const FD_EXT_LENGTH: usize = 13;
42const FD_EXT_DATA: usize = 14;
43
44static FIELD_DESCRIPTORS: &[FieldDescriptor] = &[
45 FieldDescriptor::new("version", "Version", FieldType::U8),
46 FieldDescriptor::new("padding", "Padding", FieldType::U8),
47 FieldDescriptor::new("extension", "Extension", FieldType::U8),
48 FieldDescriptor::new("csrc_count", "CSRC Count", FieldType::U8),
49 FieldDescriptor::new("marker", "Marker", FieldType::U8),
50 FieldDescriptor::new("payload_type", "Payload Type", FieldType::U8),
51 FieldDescriptor::new("sequence_number", "Sequence Number", FieldType::U16),
52 FieldDescriptor::new("timestamp", "Timestamp", FieldType::U32),
53 FieldDescriptor::new("ssrc", "SSRC", FieldType::U32),
54 FieldDescriptor::new("csrc_list", "CSRC List", FieldType::Array).optional(),
55 FieldDescriptor::new("payload", "Payload", FieldType::Bytes).optional(),
56 FieldDescriptor::new("padding_length", "Padding Length", FieldType::U8).optional(),
57 FieldDescriptor::new("ext_profile", "Extension Profile", FieldType::U16).optional(),
58 FieldDescriptor::new("ext_length", "Extension Length", FieldType::U16).optional(),
59 FieldDescriptor::new("ext_data", "Extension Data", FieldType::Bytes).optional(),
60];
61
62pub struct RtpDissector;
64
65impl Dissector for RtpDissector {
66 fn name(&self) -> &'static str {
67 "Real-time Transport Protocol"
68 }
69
70 fn short_name(&self) -> &'static str {
71 "RTP"
72 }
73
74 fn field_descriptors(&self) -> &'static [FieldDescriptor] {
75 FIELD_DESCRIPTORS
76 }
77
78 fn dissect<'pkt>(
79 &self,
80 data: &'pkt [u8],
81 buf: &mut DissectBuffer<'pkt>,
82 offset: usize,
83 ) -> Result<DissectResult, PacketError> {
84 if data.len() < MIN_HEADER_SIZE {
87 return Err(PacketError::Truncated {
88 expected: MIN_HEADER_SIZE,
89 actual: data.len(),
90 });
91 }
92
93 let byte0 = data[0];
96 let version = (byte0 >> 6) & 0x03;
97 let padding = (byte0 >> 5) & 0x01;
98 let extension_bit = (byte0 >> 4) & 0x01;
99 let cc = byte0 & 0x0F;
100
101 if version != RTP_VERSION {
104 return Err(PacketError::InvalidFieldValue {
105 field: "version",
106 value: version as u32,
107 });
108 }
109
110 let byte1 = data[1];
111 let marker = (byte1 >> 7) & 0x01;
112 let payload_type = byte1 & 0x7F;
113 let sequence_number = read_be_u16(data, 2)?;
114 let timestamp = read_be_u32(data, 4)?;
115 let ssrc = read_be_u32(data, 8)?;
116
117 let csrc_end = MIN_HEADER_SIZE + (cc as usize) * 4;
118 if data.len() < csrc_end {
119 return Err(PacketError::Truncated {
120 expected: csrc_end,
121 actual: data.len(),
122 });
123 }
124
125 let mut header_end = csrc_end;
128
129 let ext_info = if extension_bit == 1 {
132 let ext_header_start = csrc_end;
133
134 if data.len() < ext_header_start + 4 {
136 return Err(PacketError::Truncated {
137 expected: ext_header_start + 4,
138 actual: data.len(),
139 });
140 }
141
142 let ext_profile = read_be_u16(data, ext_header_start)?;
143
144 let ext_length = read_be_u16(data, ext_header_start + 2)?;
148
149 let ext_data_bytes = (ext_length as usize) * 4;
150 let ext_total = 4 + ext_data_bytes;
151
152 if data.len() < ext_header_start + ext_total {
153 return Err(PacketError::Truncated {
154 expected: ext_header_start + ext_total,
155 actual: data.len(),
156 });
157 }
158
159 header_end = ext_header_start + ext_total;
160 Some((
161 ext_header_start,
162 ext_profile,
163 ext_length,
164 ext_data_bytes,
165 ext_total,
166 ))
167 } else {
168 None
169 };
170
171 let pad_count = if padding == 1 {
177 if data.len() <= header_end {
178 return Err(PacketError::InvalidHeader(
179 "RTP padding bit set but no payload/padding bytes present",
180 ));
181 }
182 let pc = data[data.len() - 1];
183 if pc == 0 {
184 return Err(PacketError::InvalidHeader(
185 "RTP padding count must be >= 1 (includes the count byte itself)",
186 ));
187 }
188 if (pc as usize) > data.len() - header_end {
189 return Err(PacketError::InvalidHeader(
190 "RTP padding count exceeds available payload bytes",
191 ));
192 }
193 Some(pc)
194 } else {
195 None
196 };
197
198 buf.begin_layer(
204 self.short_name(),
205 None,
206 FIELD_DESCRIPTORS,
207 offset..offset + data.len(),
208 );
209
210 buf.push_field(
211 &FIELD_DESCRIPTORS[FD_VERSION],
212 FieldValue::U8(version),
213 offset..offset + 1,
214 );
215 buf.push_field(
216 &FIELD_DESCRIPTORS[FD_PADDING],
217 FieldValue::U8(padding),
218 offset..offset + 1,
219 );
220 buf.push_field(
221 &FIELD_DESCRIPTORS[FD_EXTENSION],
222 FieldValue::U8(extension_bit),
223 offset..offset + 1,
224 );
225 buf.push_field(
226 &FIELD_DESCRIPTORS[FD_CSRC_COUNT],
227 FieldValue::U8(cc),
228 offset..offset + 1,
229 );
230 buf.push_field(
231 &FIELD_DESCRIPTORS[FD_MARKER],
232 FieldValue::U8(marker),
233 offset + 1..offset + 2,
234 );
235 buf.push_field(
236 &FIELD_DESCRIPTORS[FD_PAYLOAD_TYPE],
237 FieldValue::U8(payload_type),
238 offset + 1..offset + 2,
239 );
240 buf.push_field(
241 &FIELD_DESCRIPTORS[FD_SEQUENCE_NUMBER],
242 FieldValue::U16(sequence_number),
243 offset + 2..offset + 4,
244 );
245 buf.push_field(
246 &FIELD_DESCRIPTORS[FD_TIMESTAMP],
247 FieldValue::U32(timestamp),
248 offset + 4..offset + 8,
249 );
250 buf.push_field(
251 &FIELD_DESCRIPTORS[FD_SSRC],
252 FieldValue::U32(ssrc),
253 offset + 8..offset + 12,
254 );
255
256 if cc > 0 {
257 let array_idx = buf.begin_container(
258 &FIELD_DESCRIPTORS[FD_CSRC_LIST],
259 FieldValue::Array(0..0),
260 (offset + MIN_HEADER_SIZE)..(offset + csrc_end),
261 );
262 for i in 0..cc as usize {
263 let csrc_offset = MIN_HEADER_SIZE + i * 4;
264 let csrc_val = read_be_u32(data, csrc_offset)?;
265 buf.push_field(
266 &FIELD_DESCRIPTORS[FD_CSRC_LIST],
267 FieldValue::U32(csrc_val),
268 (offset + csrc_offset)..(offset + csrc_offset + 4),
269 );
270 }
271 buf.end_container(array_idx);
272 }
273
274 if let Some((ext_header_start, ext_profile, ext_length, ext_data_bytes, ext_total)) =
275 ext_info
276 {
277 buf.push_field(
278 &FIELD_DESCRIPTORS[FD_EXT_PROFILE],
279 FieldValue::U16(ext_profile),
280 (offset + ext_header_start)..(offset + ext_header_start + 2),
281 );
282
283 buf.push_field(
284 &FIELD_DESCRIPTORS[FD_EXT_LENGTH],
285 FieldValue::U16(ext_length),
286 (offset + ext_header_start + 2)..(offset + ext_header_start + 4),
287 );
288
289 if ext_data_bytes > 0 {
290 buf.push_field(
291 &FIELD_DESCRIPTORS[FD_EXT_DATA],
292 FieldValue::Bytes(&data[ext_header_start + 4..ext_header_start + ext_total]),
293 (offset + ext_header_start + 4)..(offset + ext_header_start + ext_total),
294 );
295 }
296 }
297
298 let payload_end = data.len() - pad_count.map(|pc| pc as usize).unwrap_or(0);
303 if payload_end > header_end {
304 buf.push_field(
305 &FIELD_DESCRIPTORS[FD_PAYLOAD],
306 FieldValue::Bytes(&data[header_end..payload_end]),
307 (offset + header_end)..(offset + payload_end),
308 );
309 }
310
311 if let Some(pc) = pad_count {
312 buf.push_field(
313 &FIELD_DESCRIPTORS[FD_PADDING_LENGTH],
314 FieldValue::U8(pc),
315 (offset + data.len() - 1)..(offset + data.len()),
316 );
317 }
318
319 buf.end_layer();
320
321 Ok(DissectResult::new(data.len(), DispatchHint::End))
324 }
325}
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330
331 fn minimal_rtp_header(pt: u8, seq: u16, ts: u32, ssrc: u32) -> Vec<u8> {
356 let mut buf = Vec::with_capacity(12);
357 buf.push(0x80);
359 buf.push(pt & 0x7F);
361 buf.extend_from_slice(&seq.to_be_bytes());
362 buf.extend_from_slice(&ts.to_be_bytes());
363 buf.extend_from_slice(&ssrc.to_be_bytes());
364 buf
365 }
366
367 #[test]
368 fn parse_rtp_basic() {
369 let data = minimal_rtp_header(111, 1000, 160_000, 0x12345678);
370 let mut buf = DissectBuffer::new();
371 let result = RtpDissector.dissect(&data, &mut buf, 0).unwrap();
372
373 assert_eq!(result.bytes_consumed, 12);
376 assert_eq!(result.next, DispatchHint::End);
377 assert_eq!(buf.layers().len(), 1);
378
379 let layer = &buf.layers()[0];
380 assert_eq!(layer.name, "RTP");
381 assert_eq!(layer.range, 0..12);
382 assert_eq!(
383 buf.field_by_name(layer, "version").unwrap().value,
384 FieldValue::U8(2)
385 );
386 assert_eq!(
387 buf.field_by_name(layer, "padding").unwrap().value,
388 FieldValue::U8(0)
389 );
390 assert_eq!(
391 buf.field_by_name(layer, "extension").unwrap().value,
392 FieldValue::U8(0)
393 );
394 assert_eq!(
395 buf.field_by_name(layer, "csrc_count").unwrap().value,
396 FieldValue::U8(0)
397 );
398 assert_eq!(
399 buf.field_by_name(layer, "marker").unwrap().value,
400 FieldValue::U8(0)
401 );
402 assert_eq!(
403 buf.field_by_name(layer, "payload_type").unwrap().value,
404 FieldValue::U8(111)
405 );
406 assert_eq!(
407 buf.field_by_name(layer, "sequence_number").unwrap().value,
408 FieldValue::U16(1000)
409 );
410 assert_eq!(
411 buf.field_by_name(layer, "timestamp").unwrap().value,
412 FieldValue::U32(160_000)
413 );
414 assert_eq!(
415 buf.field_by_name(layer, "ssrc").unwrap().value,
416 FieldValue::U32(0x12345678)
417 );
418 assert!(buf.field_by_name(layer, "csrc_list").is_none());
419 }
420
421 #[test]
422 fn parse_rtp_with_padding() {
423 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
424 data[0] |= 0x20;
426 data.extend_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD]); data.extend_from_slice(&[0x00, 0x00, 0x00, 0x04]); let mut buf = DissectBuffer::new();
431 let result = RtpDissector.dissect(&data, &mut buf, 0).unwrap();
432
433 assert_eq!(result.bytes_consumed, 20);
436 let layer = &buf.layers()[0];
437 assert_eq!(layer.range, 0..20);
438 assert_eq!(
439 buf.field_by_name(layer, "padding").unwrap().value,
440 FieldValue::U8(1)
441 );
442 assert_eq!(
443 buf.field_by_name(layer, "payload").unwrap().value,
444 FieldValue::Bytes(&[0xAA, 0xBB, 0xCC, 0xDD])
445 );
446 assert_eq!(buf.field_by_name(layer, "payload").unwrap().range, 12..16);
447 assert_eq!(
448 buf.field_by_name(layer, "padding_length").unwrap().value,
449 FieldValue::U8(4)
450 );
451 assert_eq!(
452 buf.field_by_name(layer, "padding_length").unwrap().range,
453 19..20
454 );
455 }
456
457 #[test]
458 fn parse_rtp_with_payload() {
459 let mut data = minimal_rtp_header(96, 1, 100, 0xDEADBEEF);
461 data.extend_from_slice(&[0x01, 0x02, 0x03, 0x04, 0x05]);
462
463 let mut buf = DissectBuffer::new();
464 let result = RtpDissector.dissect(&data, &mut buf, 0).unwrap();
465
466 assert_eq!(result.bytes_consumed, 17);
469 let layer = &buf.layers()[0];
470 assert_eq!(layer.range, 0..17);
471 assert_eq!(
472 buf.field_by_name(layer, "payload").unwrap().value,
473 FieldValue::Bytes(&[0x01, 0x02, 0x03, 0x04, 0x05])
474 );
475 assert_eq!(buf.field_by_name(layer, "payload").unwrap().range, 12..17);
476 assert!(buf.field_by_name(layer, "padding_length").is_none());
477 }
478
479 #[test]
480 fn parse_rtp_padding_only_no_payload_data() {
481 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
483 data[0] |= 0x20;
484 data.extend_from_slice(&[0x00, 0x00, 0x00, 0x04]); let mut buf = DissectBuffer::new();
487 let result = RtpDissector.dissect(&data, &mut buf, 0).unwrap();
488
489 assert_eq!(result.bytes_consumed, 16);
490 let layer = &buf.layers()[0];
491 assert_eq!(layer.range, 0..16);
492 assert!(buf.field_by_name(layer, "payload").is_none());
494 assert_eq!(
495 buf.field_by_name(layer, "padding_length").unwrap().value,
496 FieldValue::U8(4)
497 );
498 }
499
500 #[test]
501 fn parse_rtp_padding_no_payload() {
502 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
503 data[0] |= 0x20;
505 let mut buf = DissectBuffer::new();
506 let err = RtpDissector.dissect(&data, &mut buf, 0).unwrap_err();
507 assert!(
508 matches!(err, PacketError::InvalidHeader(_)),
509 "expected InvalidHeader for P=1 with no payload, got {err:?}"
510 );
511 }
512
513 #[test]
514 fn parse_rtp_padding_count_zero() {
515 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
516 data[0] |= 0x20;
517 data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
519 let mut buf = DissectBuffer::new();
520 let err = RtpDissector.dissect(&data, &mut buf, 0).unwrap_err();
521 assert!(
522 matches!(err, PacketError::InvalidHeader(_)),
523 "expected InvalidHeader for padding count 0, got {err:?}"
524 );
525 }
526
527 #[test]
528 fn parse_rtp_padding_count_exceeds_payload() {
529 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
530 data[0] |= 0x20;
531 data.extend_from_slice(&[0x00, 0x0A]);
533 let mut buf = DissectBuffer::new();
534 let err = RtpDissector.dissect(&data, &mut buf, 0).unwrap_err();
535 assert!(
536 matches!(err, PacketError::InvalidHeader(_)),
537 "expected InvalidHeader for excessive padding count, got {err:?}"
538 );
539 }
540
541 #[test]
542 fn parse_rtp_marker_set() {
543 let mut data = minimal_rtp_header(96, 500, 8000, 0x11223344);
544 data[1] |= 0x80;
546 let mut buf = DissectBuffer::new();
547 RtpDissector.dissect(&data, &mut buf, 0).unwrap();
548
549 let layer = &buf.layers()[0];
550 assert_eq!(
551 buf.field_by_name(layer, "marker").unwrap().value,
552 FieldValue::U8(1)
553 );
554 assert_eq!(
555 buf.field_by_name(layer, "payload_type").unwrap().value,
556 FieldValue::U8(96)
557 );
558 }
559
560 #[test]
561 fn parse_rtp_with_csrc() {
562 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
563 data[0] = (data[0] & 0xF0) | 0x02;
565 data.extend_from_slice(&0x11111111u32.to_be_bytes());
567 data.extend_from_slice(&0x22222222u32.to_be_bytes());
568
569 let mut buf = DissectBuffer::new();
570 let result = RtpDissector.dissect(&data, &mut buf, 0).unwrap();
571
572 assert_eq!(result.bytes_consumed, 20); let layer = &buf.layers()[0];
574 assert_eq!(layer.range, 0..20);
575 assert_eq!(
576 buf.field_by_name(layer, "csrc_count").unwrap().value,
577 FieldValue::U8(2)
578 );
579
580 let csrc_list = buf.field_by_name(layer, "csrc_list").unwrap();
581 let range = match &csrc_list.value {
582 FieldValue::Array(r) => r.clone(),
583 _ => panic!("expected Array"),
584 };
585 let elements = buf.nested_fields(&range);
586 assert_eq!(elements.len(), 2);
587 assert_eq!(elements[0].value, FieldValue::U32(0x11111111));
588 assert_eq!(elements[1].value, FieldValue::U32(0x22222222));
589 }
590
591 #[test]
592 fn parse_rtp_with_extension() {
593 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
594 data[0] |= 0x10;
596 data.extend_from_slice(&0xBEDEu16.to_be_bytes());
598 data.extend_from_slice(&1u16.to_be_bytes());
599 data.extend_from_slice(&[0x01, 0x02, 0x03, 0x04]);
601
602 let mut buf = DissectBuffer::new();
603 let result = RtpDissector.dissect(&data, &mut buf, 0).unwrap();
604
605 assert_eq!(result.bytes_consumed, 20); let layer = &buf.layers()[0];
607 assert_eq!(layer.range, 0..20);
608 assert_eq!(
609 buf.field_by_name(layer, "extension").unwrap().value,
610 FieldValue::U8(1)
611 );
612 assert_eq!(
613 buf.field_by_name(layer, "ext_profile").unwrap().value,
614 FieldValue::U16(0xBEDE)
615 );
616 assert_eq!(
617 buf.field_by_name(layer, "ext_length").unwrap().value,
618 FieldValue::U16(1)
619 );
620 assert_eq!(
621 buf.field_by_name(layer, "ext_data").unwrap().value,
622 FieldValue::Bytes(&[0x01, 0x02, 0x03, 0x04])
623 );
624 }
625
626 #[test]
627 fn parse_rtp_zero_length_extension() {
628 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
629 data[0] |= 0x10;
631 data.extend_from_slice(&0x1234u16.to_be_bytes());
633 data.extend_from_slice(&0u16.to_be_bytes());
634
635 let mut buf = DissectBuffer::new();
636 let result = RtpDissector.dissect(&data, &mut buf, 0).unwrap();
637
638 assert_eq!(result.bytes_consumed, 16); let layer = &buf.layers()[0];
640 assert_eq!(
641 buf.field_by_name(layer, "ext_profile").unwrap().value,
642 FieldValue::U16(0x1234)
643 );
644 assert_eq!(
645 buf.field_by_name(layer, "ext_length").unwrap().value,
646 FieldValue::U16(0)
647 );
648 assert!(buf.field_by_name(layer, "ext_data").is_none());
649 }
650
651 #[test]
652 fn parse_rtp_with_csrc_and_extension() {
653 let mut data = minimal_rtp_header(8, 42, 320_000, 0xDEADBEEF);
654 data[0] = (data[0] & 0xE0) | 0x11; data.extend_from_slice(&0xCAFEBABEu32.to_be_bytes());
658 data.extend_from_slice(&0xABCDu16.to_be_bytes());
660 data.extend_from_slice(&2u16.to_be_bytes());
661 data.extend_from_slice(&[0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80]);
663
664 let mut buf = DissectBuffer::new();
665 let result = RtpDissector.dissect(&data, &mut buf, 0).unwrap();
666
667 assert_eq!(result.bytes_consumed, 28);
669
670 let layer = &buf.layers()[0];
671 assert_eq!(layer.range, 0..28);
672 assert_eq!(
673 buf.field_by_name(layer, "csrc_count").unwrap().value,
674 FieldValue::U8(1)
675 );
676 let csrc_list = buf.field_by_name(layer, "csrc_list").unwrap();
677 let range = match &csrc_list.value {
678 FieldValue::Array(r) => r.clone(),
679 _ => panic!("expected Array"),
680 };
681 let elements = buf.nested_fields(&range);
682 assert_eq!(elements.len(), 1);
683 assert_eq!(elements[0].value, FieldValue::U32(0xCAFEBABE));
684
685 assert_eq!(
686 buf.field_by_name(layer, "ext_profile").unwrap().value,
687 FieldValue::U16(0xABCD)
688 );
689 assert_eq!(
690 buf.field_by_name(layer, "ext_length").unwrap().value,
691 FieldValue::U16(2)
692 );
693 assert_eq!(
694 buf.field_by_name(layer, "ext_data").unwrap().value,
695 FieldValue::Bytes(&[0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80])
696 );
697 }
698
699 #[test]
700 fn parse_rtp_truncated() {
701 let data = [0x80, 0x00, 0x00]; let mut buf = DissectBuffer::new();
703 let err = RtpDissector.dissect(&data, &mut buf, 0).unwrap_err();
704 assert!(
705 matches!(
706 err,
707 PacketError::Truncated {
708 expected: 12,
709 actual: 3
710 }
711 ),
712 "expected Truncated, got {err:?}"
713 );
714 }
715
716 #[test]
717 fn parse_rtp_invalid_version() {
718 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
719 data[0] = (3 << 6) | (data[0] & 0x3F);
721 let mut buf = DissectBuffer::new();
722 let err = RtpDissector.dissect(&data, &mut buf, 0).unwrap_err();
723 assert!(
724 matches!(
725 err,
726 PacketError::InvalidFieldValue {
727 field: "version",
728 value: 3
729 }
730 ),
731 "expected InvalidFieldValue for version, got {err:?}"
732 );
733 }
734
735 #[test]
736 fn parse_rtp_truncated_csrc() {
737 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
738 data[0] = (data[0] & 0xF0) | 0x03;
740 let mut buf = DissectBuffer::new();
741 let err = RtpDissector.dissect(&data, &mut buf, 0).unwrap_err();
742 assert!(
743 matches!(
744 err,
745 PacketError::Truncated {
746 expected: 24,
747 actual: 12
748 }
749 ),
750 "expected Truncated(24, 12), got {err:?}"
751 );
752 }
753
754 #[test]
755 fn parse_rtp_truncated_extension_header() {
756 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
757 data[0] |= 0x10;
759 let mut buf = DissectBuffer::new();
760 let err = RtpDissector.dissect(&data, &mut buf, 0).unwrap_err();
761 assert!(
762 matches!(
763 err,
764 PacketError::Truncated {
765 expected: 16,
766 actual: 12
767 }
768 ),
769 "expected Truncated(16, 12), got {err:?}"
770 );
771 }
772
773 #[test]
774 fn parse_rtp_truncated_extension_data() {
775 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
776 data[0] |= 0x10;
778 data.extend_from_slice(&0u16.to_be_bytes());
780 data.extend_from_slice(&2u16.to_be_bytes());
781 data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
783
784 let mut buf = DissectBuffer::new();
785 let err = RtpDissector.dissect(&data, &mut buf, 0).unwrap_err();
786 assert!(
787 matches!(
788 err,
789 PacketError::Truncated {
790 expected: 24,
791 actual: 20
792 }
793 ),
794 "expected Truncated(24, 20), got {err:?}"
795 );
796 }
797
798 #[test]
799 fn parse_rtp_with_offset() {
800 let mut data = vec![0xFF; 10]; data.extend_from_slice(&minimal_rtp_header(96, 100, 3200, 0xABCDEF01));
802 let mut buf = DissectBuffer::new();
803 let result = RtpDissector.dissect(&data[10..], &mut buf, 10).unwrap();
804
805 assert_eq!(result.bytes_consumed, 12);
806 let layer = &buf.layers()[0];
807 assert_eq!(layer.range, 10..22);
808 assert_eq!(buf.field_by_name(layer, "ssrc").unwrap().range, 18..22);
809 }
810
811 #[test]
812 fn parse_rtp_with_max_csrc() {
813 let mut data = minimal_rtp_header(0, 1, 100, 0xAABBCCDD);
815 data[0] = (data[0] & 0xF0) | 0x0F; for i in 0..15u32 {
817 data.extend_from_slice(&(0x10_00_00_00 + i).to_be_bytes());
818 }
819
820 let mut buf = DissectBuffer::new();
821 let result = RtpDissector.dissect(&data, &mut buf, 0).unwrap();
822 assert_eq!(result.bytes_consumed, 12 + 15 * 4);
823
824 let layer = &buf.layers()[0];
825 let csrc_list = buf.field_by_name(layer, "csrc_list").unwrap();
826 let range = match &csrc_list.value {
827 FieldValue::Array(r) => r.clone(),
828 _ => panic!("expected Array"),
829 };
830 assert_eq!(buf.nested_fields(&range).len(), 15);
831 }
832
833 #[test]
834 fn field_descriptors_complete() {
835 let descriptors = RtpDissector.field_descriptors();
836 assert_eq!(descriptors.len(), 15);
837 assert_eq!(descriptors[0].name, "version");
838 assert_eq!(descriptors[9].name, "csrc_list");
839 assert!(descriptors[9].optional);
840 assert_eq!(descriptors[10].name, "payload");
841 assert!(descriptors[10].optional);
842 assert_eq!(descriptors[11].name, "padding_length");
843 assert!(descriptors[11].optional);
844 assert_eq!(descriptors[12].name, "ext_profile");
845 assert!(descriptors[12].optional);
846 }
847
848 #[test]
849 fn name_and_short_name() {
850 assert_eq!(RtpDissector.name(), "Real-time Transport Protocol");
851 assert_eq!(RtpDissector.short_name(), "RTP");
852 }
853}