1 #[cfg(test)] 2 mod source_description_test; 3 4 use crate::{error::Error, header::*, packet::*, util::*}; 5 use util::marshal::{Marshal, MarshalSize, Unmarshal}; 6 7 use bytes::{Buf, BufMut, Bytes}; 8 use std::any::Any; 9 use std::fmt; 10 11 type Result<T> = std::result::Result<T, util::Error>; 12 13 const SDES_SOURCE_LEN: usize = 4; 14 const SDES_TYPE_LEN: usize = 1; 15 const SDES_TYPE_OFFSET: usize = 0; 16 const SDES_OCTET_COUNT_LEN: usize = 1; 17 const SDES_OCTET_COUNT_OFFSET: usize = 1; 18 const SDES_MAX_OCTET_COUNT: usize = (1 << 8) - 1; 19 const SDES_TEXT_OFFSET: usize = 2; 20 21 /// SDESType is the item type used in the RTCP SDES control packet. 22 /// RTP SDES item types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-5 23 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] 24 #[repr(u8)] 25 pub enum SdesType { 26 #[default] 27 SdesEnd = 0, // end of SDES list RFC 3550, 6.5 28 SdesCname = 1, // canonical name RFC 3550, 6.5.1 29 SdesName = 2, // user name RFC 3550, 6.5.2 30 SdesEmail = 3, // user's electronic mail address RFC 3550, 6.5.3 31 SdesPhone = 4, // user's phone number RFC 3550, 6.5.4 32 SdesLocation = 5, // geographic user location RFC 3550, 6.5.5 33 SdesTool = 6, // name of application or tool RFC 3550, 6.5.6 34 SdesNote = 7, // notice about the source RFC 3550, 6.5.7 35 SdesPrivate = 8, // private extensions RFC 3550, 6.5.8 (not implemented) 36 } 37 38 impl fmt::Display for SdesType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 40 let s = match self { 41 SdesType::SdesEnd => "END", 42 SdesType::SdesCname => "CNAME", 43 SdesType::SdesName => "NAME", 44 SdesType::SdesEmail => "EMAIL", 45 SdesType::SdesPhone => "PHONE", 46 SdesType::SdesLocation => "LOC", 47 SdesType::SdesTool => "TOOL", 48 SdesType::SdesNote => "NOTE", 49 SdesType::SdesPrivate => "PRIV", 50 }; 51 write!(f, "{s}") 52 } 53 } 54 55 impl From<u8> for SdesType { from(b: u8) -> Self56 fn from(b: u8) -> Self { 57 match b { 58 1 => SdesType::SdesCname, 59 2 => SdesType::SdesName, 60 3 => SdesType::SdesEmail, 61 4 => SdesType::SdesPhone, 62 5 => SdesType::SdesLocation, 63 6 => SdesType::SdesTool, 64 7 => SdesType::SdesNote, 65 8 => SdesType::SdesPrivate, 66 _ => SdesType::SdesEnd, 67 } 68 } 69 } 70 71 /// A SourceDescriptionChunk contains items describing a single RTP source 72 #[derive(Debug, PartialEq, Eq, Default, Clone)] 73 pub struct SourceDescriptionChunk { 74 /// The source (ssrc) or contributing source (csrc) identifier this packet describes 75 pub source: u32, 76 pub items: Vec<SourceDescriptionItem>, 77 } 78 79 impl SourceDescriptionChunk { raw_size(&self) -> usize80 fn raw_size(&self) -> usize { 81 let mut len = SDES_SOURCE_LEN; 82 for it in &self.items { 83 len += it.marshal_size(); 84 } 85 len += SDES_TYPE_LEN; // for terminating null octet 86 len 87 } 88 } 89 90 impl MarshalSize for SourceDescriptionChunk { marshal_size(&self) -> usize91 fn marshal_size(&self) -> usize { 92 let l = self.raw_size(); 93 // align to 32-bit boundary 94 l + get_padding_size(l) 95 } 96 } 97 98 impl Marshal for SourceDescriptionChunk { 99 /// Marshal encodes the SourceDescriptionChunk in binary marshal_to(&self, mut buf: &mut [u8]) -> Result<usize>100 fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> { 101 if buf.remaining_mut() < self.marshal_size() { 102 return Err(Error::BufferTooShort.into()); 103 } 104 /* 105 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 106 * | SSRC/CSRC_1 | 107 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 108 * | SDES items | 109 * | ... | 110 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 111 */ 112 113 buf.put_u32(self.source); 114 115 for it in &self.items { 116 let n = it.marshal_to(buf)?; 117 buf = &mut buf[n..]; 118 } 119 120 // The list of items in each chunk MUST be terminated by one or more null octets 121 buf.put_u8(SdesType::SdesEnd as u8); 122 123 // additional null octets MUST be included if needed to pad until the next 32-bit boundary 124 put_padding(buf, self.raw_size()); 125 Ok(self.marshal_size()) 126 } 127 } 128 129 impl Unmarshal for SourceDescriptionChunk { 130 /// Unmarshal decodes the SourceDescriptionChunk from binary unmarshal<B>(raw_packet: &mut B) -> Result<Self> where Self: Sized, B: Buf,131 fn unmarshal<B>(raw_packet: &mut B) -> Result<Self> 132 where 133 Self: Sized, 134 B: Buf, 135 { 136 /* 137 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 138 * | SSRC/CSRC_1 | 139 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 140 * | SDES items | 141 * | ... | 142 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 143 */ 144 let raw_packet_len = raw_packet.remaining(); 145 if raw_packet_len < (SDES_SOURCE_LEN + SDES_TYPE_LEN) { 146 return Err(Error::PacketTooShort.into()); 147 } 148 149 let source = raw_packet.get_u32(); 150 151 let mut offset = SDES_SOURCE_LEN; 152 let mut items = vec![]; 153 while offset < raw_packet_len { 154 let item = SourceDescriptionItem::unmarshal(raw_packet)?; 155 if item.sdes_type == SdesType::SdesEnd { 156 // offset + 1 (one byte for SdesEnd) 157 let padding_len = get_padding_size(offset + 1); 158 if raw_packet.remaining() >= padding_len { 159 raw_packet.advance(padding_len); 160 return Ok(SourceDescriptionChunk { source, items }); 161 } else { 162 return Err(Error::PacketTooShort.into()); 163 } 164 } 165 offset += item.marshal_size(); 166 items.push(item); 167 } 168 169 Err(Error::PacketTooShort.into()) 170 } 171 } 172 173 /// A SourceDescriptionItem is a part of a SourceDescription that describes a stream. 174 #[derive(Debug, PartialEq, Eq, Default, Clone)] 175 pub struct SourceDescriptionItem { 176 /// The type identifier for this item. eg, SDESCNAME for canonical name description. 177 /// 178 /// Type zero or SDESEnd is interpreted as the end of an item list and cannot be used. 179 pub sdes_type: SdesType, 180 /// Text is a unicode text blob associated with the item. Its meaning varies based on the item's Type. 181 pub text: Bytes, 182 } 183 184 impl MarshalSize for SourceDescriptionItem { marshal_size(&self) -> usize185 fn marshal_size(&self) -> usize { 186 /* 187 * 0 1 2 3 188 * 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 189 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 190 * | CNAME=1 | length | user and domain name ... 191 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 192 */ 193 SDES_TYPE_LEN + SDES_OCTET_COUNT_LEN + self.text.len() 194 } 195 } 196 197 impl Marshal for SourceDescriptionItem { 198 /// Marshal encodes the SourceDescriptionItem in binary marshal_to(&self, mut buf: &mut [u8]) -> Result<usize>199 fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> { 200 /* 201 * 0 1 2 3 202 * 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 203 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 204 * | CNAME=1 | length | user and domain name ... 205 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 206 */ 207 208 if self.sdes_type == SdesType::SdesEnd { 209 return Err(Error::SdesMissingType.into()); 210 } 211 212 if buf.remaining_mut() < self.marshal_size() { 213 return Err(Error::BufferTooShort.into()); 214 } 215 216 buf.put_u8(self.sdes_type as u8); 217 218 if self.text.len() > SDES_MAX_OCTET_COUNT { 219 return Err(Error::SdesTextTooLong.into()); 220 } 221 buf.put_u8(self.text.len() as u8); 222 buf.put(self.text.clone()); 223 224 //no padding for each SourceDescriptionItem 225 Ok(self.marshal_size()) 226 } 227 } 228 229 impl Unmarshal for SourceDescriptionItem { 230 /// Unmarshal decodes the SourceDescriptionItem from binary unmarshal<B>(raw_packet: &mut B) -> Result<Self> where Self: Sized, B: Buf,231 fn unmarshal<B>(raw_packet: &mut B) -> Result<Self> 232 where 233 Self: Sized, 234 B: Buf, 235 { 236 /* 237 * 0 1 2 3 238 * 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 239 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 240 * | CNAME=1 | length | user and domain name ... 241 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 242 */ 243 let raw_packet_len = raw_packet.remaining(); 244 if raw_packet_len < SDES_TYPE_LEN { 245 return Err(Error::PacketTooShort.into()); 246 } 247 248 let sdes_type = SdesType::from(raw_packet.get_u8()); 249 if sdes_type == SdesType::SdesEnd { 250 return Ok(SourceDescriptionItem { 251 sdes_type, 252 text: Bytes::new(), 253 }); 254 } 255 256 if raw_packet_len < (SDES_TYPE_LEN + SDES_OCTET_COUNT_LEN) { 257 return Err(Error::PacketTooShort.into()); 258 } 259 260 let octet_count = raw_packet.get_u8() as usize; 261 if SDES_TEXT_OFFSET + octet_count > raw_packet_len { 262 return Err(Error::PacketTooShort.into()); 263 } 264 265 let text = raw_packet.copy_to_bytes(octet_count); 266 267 Ok(SourceDescriptionItem { sdes_type, text }) 268 } 269 } 270 271 /// A SourceDescription (SDES) packet describes the sources in an RTP stream. 272 #[derive(Debug, Default, PartialEq, Eq, Clone)] 273 pub struct SourceDescription { 274 pub chunks: Vec<SourceDescriptionChunk>, 275 } 276 277 impl fmt::Display for SourceDescription { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result278 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 279 let mut out = "Source Description:\n".to_string(); 280 for c in &self.chunks { 281 out += format!("\t{:x}\n", c.source).as_str(); 282 for it in &c.items { 283 out += format!("\t\t{it:?}\n").as_str(); 284 } 285 } 286 write!(f, "{out}") 287 } 288 } 289 290 impl Packet for SourceDescription { 291 /// Header returns the Header associated with this packet. header(&self) -> Header292 fn header(&self) -> Header { 293 Header { 294 padding: get_padding_size(self.raw_size()) != 0, 295 count: self.chunks.len() as u8, 296 packet_type: PacketType::SourceDescription, 297 length: ((self.marshal_size() / 4) - 1) as u16, 298 } 299 } 300 301 /// destination_ssrc returns an array of SSRC values that this packet refers to. destination_ssrc(&self) -> Vec<u32>302 fn destination_ssrc(&self) -> Vec<u32> { 303 self.chunks.iter().map(|x| x.source).collect() 304 } 305 raw_size(&self) -> usize306 fn raw_size(&self) -> usize { 307 let mut chunks_length = 0; 308 for c in &self.chunks { 309 chunks_length += c.marshal_size(); 310 } 311 312 HEADER_LENGTH + chunks_length 313 } 314 as_any(&self) -> &(dyn Any + Send + Sync)315 fn as_any(&self) -> &(dyn Any + Send + Sync) { 316 self 317 } 318 equal(&self, other: &(dyn Packet + Send + Sync)) -> bool319 fn equal(&self, other: &(dyn Packet + Send + Sync)) -> bool { 320 other 321 .as_any() 322 .downcast_ref::<SourceDescription>() 323 .map_or(false, |a| self == a) 324 } 325 cloned(&self) -> Box<dyn Packet + Send + Sync>326 fn cloned(&self) -> Box<dyn Packet + Send + Sync> { 327 Box::new(self.clone()) 328 } 329 } 330 331 impl MarshalSize for SourceDescription { marshal_size(&self) -> usize332 fn marshal_size(&self) -> usize { 333 let l = self.raw_size(); 334 // align to 32-bit boundary 335 l + get_padding_size(l) 336 } 337 } 338 339 impl Marshal for SourceDescription { 340 /// Marshal encodes the SourceDescription in binary marshal_to(&self, mut buf: &mut [u8]) -> Result<usize>341 fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> { 342 if self.chunks.len() > COUNT_MAX { 343 return Err(Error::TooManyChunks.into()); 344 } 345 346 if buf.remaining_mut() < self.marshal_size() { 347 return Err(Error::BufferTooShort.into()); 348 } 349 350 /* 351 * 0 1 2 3 352 * 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 353 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 354 * header |V=2|P| SC | PT=SDES=202 | length | 355 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 356 * chunk | SSRC/CSRC_1 | 357 * 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 358 * | SDES items | 359 * | ... | 360 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 361 * chunk | SSRC/CSRC_2 | 362 * 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 363 * | SDES items | 364 * | ... | 365 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 366 */ 367 368 let h = self.header(); 369 let n = h.marshal_to(buf)?; 370 buf = &mut buf[n..]; 371 372 for c in &self.chunks { 373 let n = c.marshal_to(buf)?; 374 buf = &mut buf[n..]; 375 } 376 377 if h.padding { 378 put_padding(buf, self.raw_size()); 379 } 380 381 Ok(self.marshal_size()) 382 } 383 } 384 385 impl Unmarshal for SourceDescription { 386 /// Unmarshal decodes the SourceDescription from binary unmarshal<B>(raw_packet: &mut B) -> Result<Self> where Self: Sized, B: Buf,387 fn unmarshal<B>(raw_packet: &mut B) -> Result<Self> 388 where 389 Self: Sized, 390 B: Buf, 391 { 392 /* 393 * 0 1 2 3 394 * 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 395 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 396 * header |V=2|P| SC | PT=SDES=202 | length | 397 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 398 * chunk | SSRC/CSRC_1 | 399 * 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 400 * | SDES items | 401 * | ... | 402 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 403 * chunk | SSRC/CSRC_2 | 404 * 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 405 * | SDES items | 406 * | ... | 407 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 408 */ 409 let raw_packet_len = raw_packet.remaining(); 410 411 let h = Header::unmarshal(raw_packet)?; 412 if h.packet_type != PacketType::SourceDescription { 413 return Err(Error::WrongType.into()); 414 } 415 416 let mut offset = HEADER_LENGTH; 417 let mut chunks = vec![]; 418 while offset < raw_packet_len { 419 let chunk = SourceDescriptionChunk::unmarshal(raw_packet)?; 420 offset += chunk.marshal_size(); 421 chunks.push(chunk); 422 } 423 424 if chunks.len() != h.count as usize { 425 return Err(Error::InvalidHeader.into()); 426 } 427 428 if 429 /*h.padding &&*/ 430 raw_packet.has_remaining() { 431 raw_packet.advance(raw_packet.remaining()); 432 } 433 434 Ok(SourceDescription { chunks }) 435 } 436 } 437