#[cfg(test)]
mod source_description_test;
use std::any::Any;
use std::fmt;
use bytes::{Buf, BufMut, Bytes};
use util::marshal::{Marshal, MarshalSize, Unmarshal};
use crate::error::Error;
use crate::header::*;
use crate::packet::*;
use crate::util::*;
type Result<T> = std::result::Result<T, util::Error>;
const SDES_SOURCE_LEN: usize = 4;
const SDES_TYPE_LEN: usize = 1;
const SDES_TYPE_OFFSET: usize = 0;
const SDES_OCTET_COUNT_LEN: usize = 1;
const SDES_OCTET_COUNT_OFFSET: usize = 1;
const SDES_MAX_OCTET_COUNT: usize = (1 << 8) - 1;
const SDES_TEXT_OFFSET: usize = 2;
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum SdesType {
#[default]
SdesEnd = 0, SdesCname = 1, SdesName = 2, SdesEmail = 3, SdesPhone = 4, SdesLocation = 5, SdesTool = 6, SdesNote = 7, SdesPrivate = 8, }
impl fmt::Display for SdesType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
SdesType::SdesEnd => "END",
SdesType::SdesCname => "CNAME",
SdesType::SdesName => "NAME",
SdesType::SdesEmail => "EMAIL",
SdesType::SdesPhone => "PHONE",
SdesType::SdesLocation => "LOC",
SdesType::SdesTool => "TOOL",
SdesType::SdesNote => "NOTE",
SdesType::SdesPrivate => "PRIV",
};
write!(f, "{s}")
}
}
impl From<u8> for SdesType {
fn from(b: u8) -> Self {
match b {
1 => SdesType::SdesCname,
2 => SdesType::SdesName,
3 => SdesType::SdesEmail,
4 => SdesType::SdesPhone,
5 => SdesType::SdesLocation,
6 => SdesType::SdesTool,
7 => SdesType::SdesNote,
8 => SdesType::SdesPrivate,
_ => SdesType::SdesEnd,
}
}
}
#[derive(Debug, PartialEq, Eq, Default, Clone)]
pub struct SourceDescriptionChunk {
pub source: u32,
pub items: Vec<SourceDescriptionItem>,
}
impl SourceDescriptionChunk {
fn raw_size(&self) -> usize {
let mut len = SDES_SOURCE_LEN;
for it in &self.items {
len += it.marshal_size();
}
len += SDES_TYPE_LEN; len
}
}
impl MarshalSize for SourceDescriptionChunk {
fn marshal_size(&self) -> usize {
let l = self.raw_size();
l + get_padding_size(l)
}
}
impl Marshal for SourceDescriptionChunk {
fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
if buf.remaining_mut() < self.marshal_size() {
return Err(Error::BufferTooShort.into());
}
buf.put_u32(self.source);
for it in &self.items {
let n = it.marshal_to(buf)?;
buf = &mut buf[n..];
}
buf.put_u8(SdesType::SdesEnd as u8);
put_padding(buf, self.raw_size());
Ok(self.marshal_size())
}
}
impl Unmarshal for SourceDescriptionChunk {
fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
where
Self: Sized,
B: Buf,
{
let raw_packet_len = raw_packet.remaining();
if raw_packet_len < (SDES_SOURCE_LEN + SDES_TYPE_LEN) {
return Err(Error::PacketTooShort.into());
}
let source = raw_packet.get_u32();
let mut offset = SDES_SOURCE_LEN;
let mut items = vec![];
while offset < raw_packet_len {
let item = SourceDescriptionItem::unmarshal(raw_packet)?;
if item.sdes_type == SdesType::SdesEnd {
let padding_len = get_padding_size(offset + 1);
if raw_packet.remaining() >= padding_len {
raw_packet.advance(padding_len);
return Ok(SourceDescriptionChunk { source, items });
} else {
return Err(Error::PacketTooShort.into());
}
}
offset += item.marshal_size();
items.push(item);
}
Err(Error::PacketTooShort.into())
}
}
#[derive(Debug, PartialEq, Eq, Default, Clone)]
pub struct SourceDescriptionItem {
pub sdes_type: SdesType,
pub text: Bytes,
}
impl MarshalSize for SourceDescriptionItem {
fn marshal_size(&self) -> usize {
SDES_TYPE_LEN + SDES_OCTET_COUNT_LEN + self.text.len()
}
}
impl Marshal for SourceDescriptionItem {
fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
if self.sdes_type == SdesType::SdesEnd {
return Err(Error::SdesMissingType.into());
}
if buf.remaining_mut() < self.marshal_size() {
return Err(Error::BufferTooShort.into());
}
buf.put_u8(self.sdes_type as u8);
if self.text.len() > SDES_MAX_OCTET_COUNT {
return Err(Error::SdesTextTooLong.into());
}
buf.put_u8(self.text.len() as u8);
buf.put(self.text.clone());
Ok(self.marshal_size())
}
}
impl Unmarshal for SourceDescriptionItem {
fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
where
Self: Sized,
B: Buf,
{
let raw_packet_len = raw_packet.remaining();
if raw_packet_len < SDES_TYPE_LEN {
return Err(Error::PacketTooShort.into());
}
let sdes_type = SdesType::from(raw_packet.get_u8());
if sdes_type == SdesType::SdesEnd {
return Ok(SourceDescriptionItem {
sdes_type,
text: Bytes::new(),
});
}
if raw_packet_len < (SDES_TYPE_LEN + SDES_OCTET_COUNT_LEN) {
return Err(Error::PacketTooShort.into());
}
let octet_count = raw_packet.get_u8() as usize;
if SDES_TEXT_OFFSET + octet_count > raw_packet_len {
return Err(Error::PacketTooShort.into());
}
let text = raw_packet.copy_to_bytes(octet_count);
Ok(SourceDescriptionItem { sdes_type, text })
}
}
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct SourceDescription {
pub chunks: Vec<SourceDescriptionChunk>,
}
impl fmt::Display for SourceDescription {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut out = "Source Description:\n".to_string();
for c in &self.chunks {
out += format!("\t{:x}\n", c.source).as_str();
for it in &c.items {
out += format!("\t\t{it:?}\n").as_str();
}
}
write!(f, "{out}")
}
}
impl Packet for SourceDescription {
fn header(&self) -> Header {
Header {
padding: get_padding_size(self.raw_size()) != 0,
count: self.chunks.len() as u8,
packet_type: PacketType::SourceDescription,
length: ((self.marshal_size() / 4) - 1) as u16,
}
}
fn destination_ssrc(&self) -> Vec<u32> {
self.chunks.iter().map(|x| x.source).collect()
}
fn raw_size(&self) -> usize {
let mut chunks_length = 0;
for c in &self.chunks {
chunks_length += c.marshal_size();
}
HEADER_LENGTH + chunks_length
}
fn as_any(&self) -> &(dyn Any + Send + Sync) {
self
}
fn equal(&self, other: &(dyn Packet + Send + Sync)) -> bool {
other.as_any().downcast_ref::<SourceDescription>() == Some(self)
}
fn cloned(&self) -> Box<dyn Packet + Send + Sync> {
Box::new(self.clone())
}
}
impl MarshalSize for SourceDescription {
fn marshal_size(&self) -> usize {
let l = self.raw_size();
l + get_padding_size(l)
}
}
impl Marshal for SourceDescription {
fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
if self.chunks.len() > COUNT_MAX {
return Err(Error::TooManyChunks.into());
}
if buf.remaining_mut() < self.marshal_size() {
return Err(Error::BufferTooShort.into());
}
let h = self.header();
let n = h.marshal_to(buf)?;
buf = &mut buf[n..];
for c in &self.chunks {
let n = c.marshal_to(buf)?;
buf = &mut buf[n..];
}
if h.padding {
put_padding(buf, self.raw_size());
}
Ok(self.marshal_size())
}
}
impl Unmarshal for SourceDescription {
fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
where
Self: Sized,
B: Buf,
{
let raw_packet_len = raw_packet.remaining();
let h = Header::unmarshal(raw_packet)?;
if h.packet_type != PacketType::SourceDescription {
return Err(Error::WrongType.into());
}
let mut offset = HEADER_LENGTH;
let mut chunks = vec![];
while offset < raw_packet_len {
let chunk = SourceDescriptionChunk::unmarshal(raw_packet)?;
offset += chunk.marshal_size();
chunks.push(chunk);
}
if chunks.len() != h.count as usize {
return Err(Error::InvalidHeader.into());
}
if
raw_packet.has_remaining() {
raw_packet.advance(raw_packet.remaining());
}
Ok(SourceDescription { chunks })
}
}