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