use std::convert::TryFrom;
use byteorder::{BigEndian, ByteOrder};
use crate::message::StunParseError;
use super::{Attribute, AttributeType, RawAttribute};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Priority {
priority: u32,
}
impl Attribute for Priority {
const TYPE: AttributeType = AttributeType(0x0024);
fn length(&self) -> u16 {
4
}
}
impl<'a> From<&Priority> for RawAttribute<'a> {
fn from(value: &Priority) -> RawAttribute<'a> {
let mut buf = [0; 4];
BigEndian::write_u32(&mut buf[0..4], value.priority);
RawAttribute::new(Priority::TYPE, &buf).into_owned()
}
}
impl<'a> TryFrom<&RawAttribute<'a>> for Priority {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
raw.check_type_and_len(Self::TYPE, 4..=4)?;
Ok(Self {
priority: BigEndian::read_u32(&raw.value[..4]),
})
}
}
impl Priority {
pub fn new(priority: u32) -> Self {
Self { priority }
}
pub fn priority(&self) -> u32 {
self.priority
}
}
impl std::fmt::Display for Priority {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", Self::TYPE, self.priority)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UseCandidate {}
impl Attribute for UseCandidate {
const TYPE: AttributeType = AttributeType(0x0025);
fn length(&self) -> u16 {
0
}
}
impl<'a> From<&UseCandidate> for RawAttribute<'a> {
fn from(_value: &UseCandidate) -> RawAttribute<'a> {
static BUF: [u8; 0] = [0; 0];
RawAttribute::new(UseCandidate::TYPE, &BUF)
}
}
impl<'a> TryFrom<&RawAttribute<'a>> for UseCandidate {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
raw.check_type_and_len(Self::TYPE, 0..=0)?;
Ok(Self {})
}
}
impl Default for UseCandidate {
fn default() -> Self {
UseCandidate::new()
}
}
impl UseCandidate {
pub fn new() -> Self {
Self {}
}
}
impl std::fmt::Display for UseCandidate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::TYPE)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IceControlled {
tie_breaker: u64,
}
impl Attribute for IceControlled {
const TYPE: AttributeType = AttributeType(0x8029);
fn length(&self) -> u16 {
8
}
}
impl<'a> From<&IceControlled> for RawAttribute<'a> {
fn from(value: &IceControlled) -> RawAttribute<'a> {
let mut buf = [0; 8];
BigEndian::write_u64(&mut buf[..8], value.tie_breaker);
RawAttribute::new(IceControlled::TYPE, &buf).into_owned()
}
}
impl<'a> TryFrom<&RawAttribute<'a>> for IceControlled {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
raw.check_type_and_len(Self::TYPE, 8..=8)?;
Ok(Self {
tie_breaker: BigEndian::read_u64(&raw.value),
})
}
}
impl IceControlled {
pub fn new(tie_breaker: u64) -> Self {
Self { tie_breaker }
}
pub fn tie_breaker(&self) -> u64 {
self.tie_breaker
}
}
impl std::fmt::Display for IceControlled {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::TYPE)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IceControlling {
tie_breaker: u64,
}
impl Attribute for IceControlling {
const TYPE: AttributeType = AttributeType(0x802A);
fn length(&self) -> u16 {
8
}
}
impl<'a> From<&IceControlling> for RawAttribute<'a> {
fn from(value: &IceControlling) -> RawAttribute<'a> {
let mut buf = [0; 8];
BigEndian::write_u64(&mut buf[..8], value.tie_breaker);
RawAttribute::new(IceControlling::TYPE, &buf).into_owned()
}
}
impl<'a> TryFrom<&RawAttribute<'a>> for IceControlling {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
raw.check_type_and_len(Self::TYPE, 8..=8)?;
Ok(Self {
tie_breaker: BigEndian::read_u64(&raw.value),
})
}
}
impl IceControlling {
pub fn new(tie_breaker: u64) -> Self {
Self { tie_breaker }
}
pub fn tie_breaker(&self) -> u64 {
self.tie_breaker
}
}
impl std::fmt::Display for IceControlling {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::TYPE)
}
}
#[cfg(test)]
mod tests {
use super::*;
use tracing::trace;
#[test]
fn priority() {
let _log = crate::tests::test_init_log();
let val = 100;
let priority = Priority::new(val);
trace!("{priority}");
assert_eq!(priority.priority(), val);
assert_eq!(priority.length(), 4);
let raw = RawAttribute::from(&priority);
trace!("{raw}");
assert_eq!(raw.get_type(), Priority::TYPE);
let mapped2 = Priority::try_from(&raw).unwrap();
assert_eq!(mapped2.priority(), val);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
Priority::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
Err(StunParseError::Truncated {
expected: 4,
actual: 3
})
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
Priority::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongAttributeImplementation)
));
}
#[test]
fn use_candidate() {
let _log = crate::tests::test_init_log();
let use_candidate = UseCandidate::default();
trace!("{use_candidate}");
assert_eq!(use_candidate.length(), 0);
let raw = RawAttribute::from(&use_candidate);
trace!("{raw}");
assert_eq!(raw.get_type(), UseCandidate::TYPE);
let _mapped2 = UseCandidate::try_from(&raw).unwrap();
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
UseCandidate::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongAttributeImplementation)
));
}
#[test]
fn ice_controlling() {
let _log = crate::tests::test_init_log();
let tb = 100;
let attr = IceControlling::new(tb);
trace!("{attr}");
assert_eq!(attr.tie_breaker(), tb);
assert_eq!(attr.length(), 8);
let raw = RawAttribute::from(&attr);
trace!("{raw}");
assert_eq!(raw.get_type(), IceControlling::TYPE);
let mapped2 = IceControlling::try_from(&raw).unwrap();
assert_eq!(mapped2.tie_breaker(), tb);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
IceControlling::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
Err(StunParseError::Truncated {
expected: 8,
actual: 7
})
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
IceControlling::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongAttributeImplementation)
));
}
#[test]
fn ice_controlled() {
let _log = crate::tests::test_init_log();
let tb = 100;
let attr = IceControlled::new(tb);
trace!("{attr}");
assert_eq!(attr.tie_breaker(), tb);
assert_eq!(attr.length(), 8);
let raw = RawAttribute::from(&attr);
trace!("{raw}");
assert_eq!(raw.get_type(), IceControlled::TYPE);
let mapped2 = IceControlled::try_from(&raw).unwrap();
assert_eq!(mapped2.tie_breaker(), tb);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
IceControlled::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
Err(StunParseError::Truncated {
expected: 8,
actual: 7
})
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
IceControlled::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongAttributeImplementation)
));
}
}