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