#![warn(missing_docs)]
use crate::error::errors::{Result, SacnError};
use crate::sacn_parse_pack_error::ParsePacketError;
use core::hash::{self, Hash};
use core::str;
use std::borrow::Cow;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::vec::Vec;
use std::{time, time::Duration};
use socket2::SockAddr;
use byteorder::{ByteOrder, NetworkEndian};
use uuid::Uuid;
pub const DISCOVERY_UNI_PER_PAGE: usize = 512;
pub const E131_DISCOVERY_UNIVERSE: u16 = 64214;
pub const E131_DEFAULT_PRIORITY: u8 = 100;
pub const E131_MAX_PRIORITY: u8 = 200;
pub const E131_MULTICAST_IPV4_HIGHEST_BYTE: u8 = 239;
pub const E131_MULTICAST_IPV4_SECOND_BYTE: u8 = 255;
pub const E131_MAX_MULTICAST_UNIVERSE: u16 = 63999;
pub const E131_MIN_MULTICAST_UNIVERSE: u16 = 1;
pub const E131_NO_SYNC_ADDR: u16 = 0;
pub const E131_UNIVERSE_DISCOVERY_INTERVAL: Duration = time::Duration::from_secs(10);
pub const E131_SEQ_DIFF_DISCARD_LOWER_BOUND: isize = -20;
pub const E131_SEQ_DIFF_DISCARD_UPPER_BOUND: isize = 0;
pub const E131_PREVIEW_DATA_OPTION_BIT_MASK: u8 = 0b1000_0000;
pub const E131_STREAM_TERMINATION_OPTION_BIT_MASK: u8 = 0b0100_0000;
pub const E131_FORCE_SYNCHRONISATION_OPTION_BIT_MASK: u8 = 0b0010_0000;
pub const E131_UNIVERSE_DISCOVERY_LAYER_MIN_LENGTH: usize = 8;
pub const E131_UNIVERSE_DISCOVERY_LAYER_MAX_LENGTH: usize = 1032;
pub const E131_UNIVERSE_SYNC_PACKET_ROOT_LENGTH: usize = 33;
pub const E131_UNIVERSE_SYNC_PACKET_FRAMING_LAYER_LENGTH: usize = 11;
pub const E131_UNIVERSE_DISCOVERY_FRAMING_LAYER_MIN_LENGTH: usize = 82;
pub const E131_TERMINATE_STREAM_PACKET_COUNT: usize = 3;
pub const E131_PDU_LENGTH_FLAGS_LENGTH: usize = 2;
pub const E131_PDU_FLAGS: u8 = 0x70;
pub const E131_ROOT_LAYER_VECTOR_LENGTH: usize = 4;
pub const E131_FRAMING_LAYER_VECTOR_LENGTH: usize = 4;
const E131_PRIORITY_FIELD_LENGTH: usize = 1;
const E131_SEQ_NUM_FIELD_LENGTH: usize = 1;
const E131_OPTIONS_FIELD_LENGTH: usize = 1;
const E131_UNIVERSE_FIELD_LENGTH: usize = 2;
const E131_DATA_PACKET_DMP_LAYER_VECTOR_FIELD_LENGTH: usize = 1;
const E131_DATA_PACKET_DMP_LAYER_ADDRESS_DATA_FIELD_LENGTH: usize = 1;
const E131_DATA_PACKET_DMP_LAYER_FIRST_PROPERTY_ADDRESS_FIELD_LENGTH: usize = 2;
const E131_DATA_PACKET_DMP_LAYER_ADDRESS_INCREMENT_FIELD_LENGTH: usize = 2;
const E131_DATA_PACKET_DMP_LAYER_PROPERTY_VALUE_COUNT_FIELD_LENGTH: usize = 2;
const E131_DISCOVERY_LAYER_VECTOR_FIELD_LENGTH: usize = 4;
const E131_DISCOVERY_LAYER_PAGE_FIELD_LENGTH: usize = 1;
const E131_DISCOVERY_LAYER_LAST_PAGE_FIELD_LENGTH: usize = 1;
const E131_DMP_LAYER_ADDRESS_DATA_FIELD: u8 = 0xa1;
const E131_DATA_PACKET_DMP_LAYER_FIRST_PROPERTY_FIELD: u16 = 0x0000;
const E131_DATA_PACKET_DMP_LAYER_ADDRESS_INCREMENT: u16 = 0x0001;
const E131_PREAMBLE_SIZE: u16 = 0x0010;
const E131_POSTAMBLE_SIZE: u16 = 0x0;
const E131_ACN_PACKET_IDENTIFIER: [u8; 12] = [
0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00,
];
pub const E131_CID_FIELD_LENGTH: usize = 16;
const E131_CID_END_INDEX: usize =
E131_PDU_LENGTH_FLAGS_LENGTH + E131_ROOT_LAYER_VECTOR_LENGTH + E131_CID_FIELD_LENGTH;
pub const E131_SOURCE_NAME_FIELD_LENGTH: usize = 64;
pub const E131_SYNC_ADDR_FIELD_LENGTH: usize = 2;
const E131_SYNC_FRAMING_LAYER_SEQ_NUM_FIELD_LENGTH: usize = 1;
const E131_SYNC_FRAMING_LAYER_RESERVE_FIELD_LENGTH: usize = 2;
const E131_DISCOVERY_FRAMING_LAYER_RESERVE_FIELD_LENGTH: usize = 4;
pub const STARTING_SEQUENCE_NUMBER: u8 = 0;
pub const VECTOR_ROOT_E131_DATA: u32 = 0x0000_0004;
pub const VECTOR_ROOT_E131_EXTENDED: u32 = 0x0000_0008;
pub const VECTOR_E131_EXTENDED_SYNCHRONIZATION: u32 = 0x0000_0001;
pub const VECTOR_E131_EXTENDED_DISCOVERY: u32 = 0x0000_0002;
pub const VECTOR_E131_DATA_PACKET: u32 = 0x0000_0002;
pub const VECTOR_DMP_SET_PROPERTY: u8 = 0x02;
pub const VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST: u32 = 0x0000_0001;
pub const ACN_SDT_MULTICAST_PORT: u16 = 5568;
pub const UNIVERSE_CHANNEL_CAPACITY: usize = 513;
pub const NO_SYNC_UNIVERSE: u16 = 0;
pub const E131_NETWORK_DATA_LOSS_TIMEOUT: Duration = Duration::from_millis(2500);
pub const UNIVERSE_DISCOVERY_SOURCE_TIMEOUT: Duration = E131_NETWORK_DATA_LOSS_TIMEOUT;
pub fn universe_to_ipv4_multicast_addr(universe: u16) -> Result<SockAddr> {
is_universe_in_range(universe)?;
let high_byte: u8 = ((universe >> 8) & 0xff) as u8;
let low_byte: u8 = (universe & 0xff) as u8;
Ok(SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(239, 255, high_byte, low_byte)),
ACN_SDT_MULTICAST_PORT,
)
.into())
}
pub fn universe_to_ipv6_multicast_addr(universe: u16) -> Result<SockAddr> {
is_universe_in_range(universe)?;
Ok(SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(0xFF18, 0, 0, 0, 0, 0, 0x8300, universe)),
ACN_SDT_MULTICAST_PORT,
)
.into())
}
pub fn is_universe_in_range(universe: u16) -> Result<()> {
if (universe != E131_DISCOVERY_UNIVERSE)
&& !(E131_MIN_MULTICAST_UNIVERSE..=E131_MAX_MULTICAST_UNIVERSE).contains(&universe)
{
return Err(SacnError::IllegalUniverse(universe));
}
Ok(())
}
#[inline]
fn zeros(buf: &mut [u8], n: usize) {
for b in buf.iter_mut().take(n) {
*b = 0;
}
}
#[inline]
fn parse_source_name_str(buf: &[u8]) -> Result<&str> {
let mut source_name_length = buf.len();
for (i, b) in buf.iter().enumerate() {
if *b == 0 {
source_name_length = i;
break;
}
}
if source_name_length == buf.len() && buf[buf.len() - 1] != 0 {
return Err(SacnError::SacnParsePackError(
ParsePacketError::SourceNameNotNullTerminated(),
));
}
Ok(str::from_utf8(&buf[..source_name_length])?)
}
macro_rules! impl_acn_root_layer_protocol {
( $( $lt:tt )* ) => {
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct AcnRootLayerProtocol$( $lt )* {
pub pdu: E131RootLayer$( $lt )*,
}
impl$( $lt )* AcnRootLayerProtocol$( $lt )* {
pub fn parse(buf: &[u8]) -> Result<AcnRootLayerProtocol<'_>> {
if buf.len() < (E131_PREAMBLE_SIZE as usize) {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInsufficientData(
"Insufficient data for ACN root layer preamble".to_string(),
),
));
}
if NetworkEndian::read_u16(&buf[0..2]) != E131_PREAMBLE_SIZE {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInvalidData("invalid Preamble Size".to_string()),
));
}
if NetworkEndian::read_u16(&buf[2..4]) != E131_POSTAMBLE_SIZE {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInvalidData("invalid Post-amble Size".to_string()),
));
}
if &buf[4 .. (E131_PREAMBLE_SIZE as usize)] != E131_ACN_PACKET_IDENTIFIER {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInvalidData("invalid ACN packet identifier".to_string()),
));
}
Ok(AcnRootLayerProtocol {
pdu: E131RootLayer::parse(&buf[(E131_PREAMBLE_SIZE as usize) ..])?,
})
}
pub fn pack_alloc(&self) -> Result<Vec<u8>> {
let mut buf = Vec::with_capacity(self.len());
self.pack_vec(&mut buf)?;
Ok(buf)
}
pub fn pack_vec(&self, buf: &mut Vec<u8>) -> Result<()> {
buf.clear();
buf.resize(self.len(), 0);
self.pack(buf)
}
pub fn pack(&self, buf: &mut [u8]) -> Result<()> {
if buf.len() < self.len() {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInvalidData("Invalid ACN packet identifier".to_string())
));
}
NetworkEndian::write_u16(&mut buf[0..2], 0x0010);
zeros(&mut buf[2..4], 2);
buf[4..16].copy_from_slice(b"ASC-E1.17\x00\x00\x00");
self.pdu.pack(&mut buf[16..])
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
2 +
2 +
E131_ACN_PACKET_IDENTIFIER.len() +
self.pdu.len()
}
}
};
}
impl_acn_root_layer_protocol!(<'a>);
struct PduInfo {
length: usize,
vector: u32,
}
fn pdu_info(buf: &[u8], vector_length: usize) -> Result<PduInfo> {
if buf.len() < E131_PDU_LENGTH_FLAGS_LENGTH + vector_length {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInsufficientData(
"Insufficient data when parsing pdu_info, no flags or length field".to_string(),
),
));
}
let flags = buf[0] & 0xf0; if flags != E131_PDU_FLAGS {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParsePduInvalidFlags(flags),
));
}
let length = (NetworkEndian::read_u16(&buf[0..E131_PDU_LENGTH_FLAGS_LENGTH]) & 0x0fff) as usize;
let vector =
NetworkEndian::read_uint(&buf[E131_PDU_LENGTH_FLAGS_LENGTH..], vector_length) as u32;
Ok(PduInfo { length, vector })
}
trait Pdu: Sized {
fn parse(buf: &[u8]) -> Result<Self>;
fn pack(&self, buf: &mut [u8]) -> Result<()>;
fn len(&self) -> usize;
}
macro_rules! impl_e131_root_layer {
( $( $lt:tt )* ) => {
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub enum E131RootLayerData$( $lt )* {
DataPacket(DataPacketFramingLayer$( $lt )*),
SynchronizationPacket(SynchronizationPacketFramingLayer),
UniverseDiscoveryPacket(UniverseDiscoveryPacketFramingLayer$( $lt )*),
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct E131RootLayer$( $lt )* {
pub cid: Uuid,
pub data: E131RootLayerData$( $lt )*,
}
impl$( $lt )* Pdu for E131RootLayer$( $lt )* {
fn parse(buf: &[u8]) -> Result<E131RootLayer$( $lt )*> {
let PduInfo { length, vector } = pdu_info(&buf, E131_ROOT_LAYER_VECTOR_LENGTH)?;
if buf.len() < length {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInsufficientData(
"Buffer contains insufficient data based on ACN root layer pdu length field".to_string(),
),
));
}
if vector != VECTOR_ROOT_E131_DATA && vector != VECTOR_ROOT_E131_EXTENDED {
return Err(SacnError::SacnParsePackError(
ParsePacketError::PduInvalidVector(vector),
));
}
let cid = Uuid::from_slice(&buf[E131_PDU_LENGTH_FLAGS_LENGTH + E131_ROOT_LAYER_VECTOR_LENGTH .. E131_CID_END_INDEX])?;
let data = match vector {
VECTOR_ROOT_E131_DATA => {
E131RootLayerData::DataPacket(DataPacketFramingLayer::parse(&buf[E131_CID_END_INDEX .. length])?)
}
VECTOR_ROOT_E131_EXTENDED => {
let data_buf = &buf[E131_CID_END_INDEX .. length];
let PduInfo { length, vector} = pdu_info(&data_buf, E131_FRAMING_LAYER_VECTOR_LENGTH)?;
if buf.len() < length {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInsufficientData(
"Buffer contains insufficient data based on E131 framing layer pdu length field".to_string(),
),
));
}
match vector {
VECTOR_E131_EXTENDED_SYNCHRONIZATION => {
E131RootLayerData::SynchronizationPacket(
SynchronizationPacketFramingLayer::parse(data_buf)?,
)
}
VECTOR_E131_EXTENDED_DISCOVERY => {
E131RootLayerData::UniverseDiscoveryPacket(
UniverseDiscoveryPacketFramingLayer::parse(data_buf)?,
)
}
vector => return Err(SacnError::SacnParsePackError(
ParsePacketError::PduInvalidVector(vector),
)),
}
}
vector => return Err(SacnError::SacnParsePackError(
ParsePacketError::PduInvalidVector(vector),
)),
};
Ok(E131RootLayer {
cid,
data,
})
}
fn pack(&self, buf: &mut [u8]) -> Result<()> {
if buf.len() < self.len() {
return Err(SacnError::SacnParsePackError(
ParsePacketError::PackBufferInsufficient("".to_string())
));
}
let flags_and_length = NetworkEndian::read_u16(&[E131_PDU_FLAGS, 0x0]) | (self.len() as u16) & 0x0fff;
NetworkEndian::write_u16(&mut buf[0 .. E131_PDU_LENGTH_FLAGS_LENGTH], flags_and_length);
match self.data {
E131RootLayerData::DataPacket(_) => {
NetworkEndian::write_u32(&mut buf[E131_PDU_LENGTH_FLAGS_LENGTH .. E131_PDU_LENGTH_FLAGS_LENGTH + E131_ROOT_LAYER_VECTOR_LENGTH], VECTOR_ROOT_E131_DATA)
}
E131RootLayerData::SynchronizationPacket(_)
| E131RootLayerData::UniverseDiscoveryPacket(_) => {
NetworkEndian::write_u32(&mut buf[E131_PDU_LENGTH_FLAGS_LENGTH .. E131_PDU_LENGTH_FLAGS_LENGTH + E131_ROOT_LAYER_VECTOR_LENGTH], VECTOR_ROOT_E131_EXTENDED)
}
}
buf[E131_PDU_LENGTH_FLAGS_LENGTH + E131_ROOT_LAYER_VECTOR_LENGTH .. E131_CID_END_INDEX].copy_from_slice(self.cid.as_bytes());
match self.data {
E131RootLayerData::DataPacket(ref data) => Ok(data.pack(&mut buf[E131_CID_END_INDEX .. ])?),
E131RootLayerData::SynchronizationPacket(ref data) => Ok(data.pack(&mut buf[E131_CID_END_INDEX .. ])?),
E131RootLayerData::UniverseDiscoveryPacket(ref data) => Ok(data.pack(&mut buf[E131_CID_END_INDEX .. ])?),
}
}
fn len(&self) -> usize {
E131_PDU_LENGTH_FLAGS_LENGTH +
E131_ROOT_LAYER_VECTOR_LENGTH +
E131_CID_FIELD_LENGTH +
match self.data {
E131RootLayerData::DataPacket(ref data) => data.len(),
E131RootLayerData::SynchronizationPacket(ref data) => data.len(),
E131RootLayerData::UniverseDiscoveryPacket(ref data) => data.len(),
}
}
}
};
}
impl_e131_root_layer!(<'a>);
macro_rules! impl_data_packet_framing_layer {
( $( $lt:tt )* ) => {
#[derive(Eq, PartialEq, Debug)]
pub struct DataPacketFramingLayer$( $lt )* {
pub source_name: Cow<'a, str>,
pub priority: u8,
pub synchronization_address: u16,
pub sequence_number: u8,
pub preview_data: bool,
pub stream_terminated: bool,
pub force_synchronization: bool,
pub universe: u16,
pub data: DataPacketDmpLayer$( $lt )*,
}
const SOURCE_NAME_INDEX: usize = E131_PDU_LENGTH_FLAGS_LENGTH + E131_FRAMING_LAYER_VECTOR_LENGTH;
const PRIORITY_INDEX: usize = SOURCE_NAME_INDEX + E131_SOURCE_NAME_FIELD_LENGTH;
const SYNC_ADDR_INDEX: usize = PRIORITY_INDEX + E131_PRIORITY_FIELD_LENGTH;
const SEQ_NUM_INDEX: usize = SYNC_ADDR_INDEX + E131_SYNC_ADDR_FIELD_LENGTH;
const OPTIONS_FIELD_INDEX: usize = SEQ_NUM_INDEX + E131_SEQ_NUM_FIELD_LENGTH;
const UNIVERSE_INDEX: usize = OPTIONS_FIELD_INDEX + E131_OPTIONS_FIELD_LENGTH;
const DATA_INDEX: usize = UNIVERSE_INDEX + E131_UNIVERSE_FIELD_LENGTH;
impl$( $lt )* Pdu for DataPacketFramingLayer$( $lt )* {
fn parse(buf: &[u8]) -> Result<DataPacketFramingLayer$( $lt )*> {
let PduInfo { length, vector } = pdu_info(&buf, E131_FRAMING_LAYER_VECTOR_LENGTH)?;
if buf.len() < length {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInsufficientData("Buffer contains insufficient data based on data packet framing layer pdu length field".to_string())));
}
if vector != VECTOR_E131_DATA_PACKET {
return Err(SacnError::SacnParsePackError(ParsePacketError::PduInvalidVector(vector)));
}
let source_name = String::from(
parse_source_name_str(
&buf[SOURCE_NAME_INDEX .. PRIORITY_INDEX]
)?
);
let priority = buf[PRIORITY_INDEX];
if priority > E131_MAX_PRIORITY {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInvalidPriority(priority),
));
}
let synchronization_address = NetworkEndian::read_u16(&buf[SYNC_ADDR_INDEX .. SEQ_NUM_INDEX]);
if synchronization_address > E131_MAX_MULTICAST_UNIVERSE {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInvalidSyncAddr(synchronization_address),
));
}
let sequence_number = buf[SEQ_NUM_INDEX];
let preview_data = buf[OPTIONS_FIELD_INDEX] & E131_PREVIEW_DATA_OPTION_BIT_MASK != 0;
let stream_terminated = buf[OPTIONS_FIELD_INDEX] & E131_STREAM_TERMINATION_OPTION_BIT_MASK != 0;
let force_synchronization = buf[OPTIONS_FIELD_INDEX] & E131_FORCE_SYNCHRONISATION_OPTION_BIT_MASK != 0;
let universe = NetworkEndian::read_u16(&buf[UNIVERSE_INDEX .. DATA_INDEX]);
if !(E131_MIN_MULTICAST_UNIVERSE..=E131_MAX_MULTICAST_UNIVERSE).contains(&universe) {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInvalidUniverse(universe),
));
}
let data = DataPacketDmpLayer::parse(&buf[DATA_INDEX .. length])?;
Ok(DataPacketFramingLayer {
source_name: source_name.into(),
priority,
synchronization_address,
sequence_number,
preview_data,
stream_terminated,
force_synchronization,
universe,
data,
})
}
fn pack(&self, buf: &mut [u8]) -> Result<()> {
if buf.len() < self.len() {
return Err(SacnError::SacnParsePackError(ParsePacketError::PackBufferInsufficient("".to_string())));
}
let flags_and_length = NetworkEndian::read_u16(&[E131_PDU_FLAGS, 0x0]) | (self.len() as u16) & 0x0fff;
NetworkEndian::write_u16(&mut buf[0.. E131_PDU_LENGTH_FLAGS_LENGTH], flags_and_length);
NetworkEndian::write_u32(&mut buf[E131_PDU_LENGTH_FLAGS_LENGTH .. SOURCE_NAME_INDEX], VECTOR_E131_DATA_PACKET);
zeros(&mut buf[SOURCE_NAME_INDEX .. PRIORITY_INDEX], E131_SOURCE_NAME_FIELD_LENGTH);
buf[SOURCE_NAME_INDEX .. SOURCE_NAME_INDEX + self.source_name.len()].copy_from_slice(self.source_name.as_bytes());
buf[PRIORITY_INDEX] = self.priority;
NetworkEndian::write_u16(&mut buf[SYNC_ADDR_INDEX .. SEQ_NUM_INDEX], self.synchronization_address);
buf[SEQ_NUM_INDEX] = self.sequence_number;
buf[OPTIONS_FIELD_INDEX] = 0;
if self.preview_data {
buf[OPTIONS_FIELD_INDEX] = E131_PREVIEW_DATA_OPTION_BIT_MASK;
}
if self.stream_terminated {
buf[OPTIONS_FIELD_INDEX] |= E131_STREAM_TERMINATION_OPTION_BIT_MASK;
}
if self.force_synchronization {
buf[OPTIONS_FIELD_INDEX] |= E131_FORCE_SYNCHRONISATION_OPTION_BIT_MASK;
}
NetworkEndian::write_u16(&mut buf[UNIVERSE_INDEX .. DATA_INDEX], self.universe);
self.data.pack(&mut buf[DATA_INDEX .. ])
}
fn len(&self) -> usize {
E131_PDU_LENGTH_FLAGS_LENGTH +
E131_FRAMING_LAYER_VECTOR_LENGTH +
E131_SOURCE_NAME_FIELD_LENGTH +
E131_PRIORITY_FIELD_LENGTH +
E131_SYNC_ADDR_FIELD_LENGTH +
E131_SEQ_NUM_FIELD_LENGTH +
E131_OPTIONS_FIELD_LENGTH +
E131_UNIVERSE_FIELD_LENGTH +
self.data.len()
}
}
impl$( $lt )* Clone for DataPacketFramingLayer$( $lt )* {
fn clone(&self) -> Self {
DataPacketFramingLayer {
source_name: self.source_name.clone(),
priority: self.priority,
synchronization_address: self.synchronization_address,
sequence_number: self.sequence_number,
preview_data: self.preview_data,
stream_terminated: self.stream_terminated,
force_synchronization: self.force_synchronization,
universe: self.universe,
data: self.data.clone(),
}
}
}
impl$( $lt )* Hash for DataPacketFramingLayer$( $lt )* {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
(&*self.source_name).hash(state);
self.priority.hash(state);
self.synchronization_address.hash(state);
self.sequence_number.hash(state);
self.preview_data.hash(state);
self.stream_terminated.hash(state);
self.force_synchronization.hash(state);
self.universe.hash(state);
self.data.hash(state);
}
}
};
}
impl_data_packet_framing_layer!(<'a>);
macro_rules! impl_data_packet_dmp_layer {
( $( $lt:tt )* ) => {
#[derive(Eq, PartialEq, Debug)]
pub struct DataPacketDmpLayer$( $lt )* {
pub property_values: Cow<'a, [u8]>,
}
const VECTOR_FIELD_INDEX: usize = E131_PDU_LENGTH_FLAGS_LENGTH;
const ADDRESS_DATA_FIELD_INDEX: usize = VECTOR_FIELD_INDEX + E131_DATA_PACKET_DMP_LAYER_VECTOR_FIELD_LENGTH;
const FIRST_PRIORITY_FIELD_INDEX: usize = ADDRESS_DATA_FIELD_INDEX + E131_DATA_PACKET_DMP_LAYER_ADDRESS_DATA_FIELD_LENGTH;
const ADDRESS_INCREMENT_FIELD_INDEX: usize = FIRST_PRIORITY_FIELD_INDEX + E131_DATA_PACKET_DMP_LAYER_FIRST_PROPERTY_ADDRESS_FIELD_LENGTH;
const PROPERTY_VALUE_COUNT_FIELD_INDEX: usize = ADDRESS_INCREMENT_FIELD_INDEX + E131_DATA_PACKET_DMP_LAYER_ADDRESS_INCREMENT_FIELD_LENGTH;
const PROPERTY_VALUES_FIELD_INDEX: usize = PROPERTY_VALUE_COUNT_FIELD_INDEX + E131_DATA_PACKET_DMP_LAYER_PROPERTY_VALUE_COUNT_FIELD_LENGTH;
impl$( $lt )* Pdu for DataPacketDmpLayer$( $lt )* {
fn parse(buf: &[u8]) -> Result<DataPacketDmpLayer$( $lt )*> {
let PduInfo { length, vector } = pdu_info(&buf, E131_DATA_PACKET_DMP_LAYER_VECTOR_FIELD_LENGTH)?;
if buf.len() < length {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInsufficientData("Buffer contains insufficient data based on data packet dmp layer pdu length field".to_string())));
}
if vector != u32::from(VECTOR_DMP_SET_PROPERTY) {
return Err(SacnError::SacnParsePackError(ParsePacketError::PduInvalidVector(vector)));
}
if buf[ADDRESS_DATA_FIELD_INDEX] != E131_DMP_LAYER_ADDRESS_DATA_FIELD {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInvalidData("invalid Address and Data Type".to_string())));
}
if NetworkEndian::read_u16(&buf[FIRST_PRIORITY_FIELD_INDEX .. ADDRESS_INCREMENT_FIELD_INDEX]) != E131_DATA_PACKET_DMP_LAYER_FIRST_PROPERTY_FIELD {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInvalidData("invalid First Property Address".to_string())));
}
if NetworkEndian::read_u16(&buf[ADDRESS_INCREMENT_FIELD_INDEX .. PROPERTY_VALUE_COUNT_FIELD_INDEX]) != E131_DATA_PACKET_DMP_LAYER_ADDRESS_INCREMENT {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInvalidData("invalid Address Increment".to_string())));
}
let property_value_count = NetworkEndian::read_u16(&buf[PROPERTY_VALUE_COUNT_FIELD_INDEX .. PROPERTY_VALUES_FIELD_INDEX]);
if property_value_count as usize + PROPERTY_VALUES_FIELD_INDEX != length {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInsufficientData(
format!("Invalid data packet dmp layer property value count, pdu length indicates {} property values, property value count field indicates {} property values",
length , property_value_count)
.to_string()
)
));
}
let property_values_length = length - PROPERTY_VALUES_FIELD_INDEX;
if property_values_length > UNIVERSE_CHANNEL_CAPACITY {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInvalidData("only 512 DMX slots allowed".to_string())));
}
let mut property_values = Vec::with_capacity(property_values_length);
property_values.extend_from_slice(&buf[PROPERTY_VALUES_FIELD_INDEX .. length]);
Ok(DataPacketDmpLayer {
property_values: property_values.into(),
})
}
fn pack(&self, buf: &mut [u8]) -> Result<()> {
if self.property_values.len() > UNIVERSE_CHANNEL_CAPACITY {
return Err(SacnError::SacnParsePackError(ParsePacketError::PackInvalidData("only 512 DMX values allowed".to_string())));
}
if buf.len() < self.len() {
return Err(SacnError::SacnParsePackError(ParsePacketError::PackBufferInsufficient("DataPacketDmpLayer pack buffer length insufficient".to_string())));
}
let flags_and_length = NetworkEndian::read_u16(&[E131_PDU_FLAGS, 0x0]) | (self.len() as u16) & 0x0fff;
NetworkEndian::write_u16(&mut buf[0.. E131_PDU_LENGTH_FLAGS_LENGTH], flags_and_length);
buf[VECTOR_FIELD_INDEX] = VECTOR_DMP_SET_PROPERTY;
buf[ADDRESS_DATA_FIELD_INDEX] = E131_DMP_LAYER_ADDRESS_DATA_FIELD;
zeros(&mut buf[FIRST_PRIORITY_FIELD_INDEX .. ADDRESS_INCREMENT_FIELD_INDEX], E131_DATA_PACKET_DMP_LAYER_FIRST_PROPERTY_ADDRESS_FIELD_LENGTH);
NetworkEndian::write_u16(&mut buf[ADDRESS_INCREMENT_FIELD_INDEX .. PROPERTY_VALUE_COUNT_FIELD_INDEX], E131_DATA_PACKET_DMP_LAYER_ADDRESS_INCREMENT);
NetworkEndian::write_u16(&mut buf[PROPERTY_VALUE_COUNT_FIELD_INDEX .. PROPERTY_VALUES_FIELD_INDEX], self.property_values.len() as u16);
buf[PROPERTY_VALUES_FIELD_INDEX .. PROPERTY_VALUES_FIELD_INDEX + self.property_values.len()].copy_from_slice(&self.property_values);
Ok(())
}
fn len(&self) -> usize {
E131_PDU_LENGTH_FLAGS_LENGTH +
E131_DATA_PACKET_DMP_LAYER_VECTOR_FIELD_LENGTH +
E131_DATA_PACKET_DMP_LAYER_ADDRESS_DATA_FIELD_LENGTH +
E131_DATA_PACKET_DMP_LAYER_FIRST_PROPERTY_ADDRESS_FIELD_LENGTH +
E131_DATA_PACKET_DMP_LAYER_ADDRESS_INCREMENT_FIELD_LENGTH +
E131_DATA_PACKET_DMP_LAYER_PROPERTY_VALUE_COUNT_FIELD_LENGTH +
self.property_values.len()
}
}
impl$( $lt )* Clone for DataPacketDmpLayer$( $lt )* {
fn clone(&self) -> Self {
DataPacketDmpLayer {
property_values: self.property_values.clone(),
}
}
}
impl$( $lt )* Hash for DataPacketDmpLayer$( $lt )* {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
(&*self.property_values).hash(state);
}
}
};
}
impl_data_packet_dmp_layer!(<'a>);
#[derive(Clone, Eq, PartialEq, Hash, Debug, Copy)]
pub struct SynchronizationPacketFramingLayer {
pub sequence_number: u8,
pub synchronization_address: u16,
}
const E131_SYNC_FRAMING_LAYER_VECTOR_FIELD_INDEX: usize = E131_PDU_LENGTH_FLAGS_LENGTH;
const E131_SYNC_FRAMING_LAYER_SEQ_NUM_FIELD_INDEX: usize =
E131_SYNC_FRAMING_LAYER_VECTOR_FIELD_INDEX + E131_FRAMING_LAYER_VECTOR_LENGTH;
const E131_SYNC_FRAMING_LAYER_SYNC_ADDRESS_FIELD_INDEX: usize =
E131_SYNC_FRAMING_LAYER_SEQ_NUM_FIELD_INDEX + E131_SYNC_FRAMING_LAYER_SEQ_NUM_FIELD_LENGTH;
const E131_SYNC_FRAMING_LAYER_RESERVE_FIELD_INDEX: usize =
E131_SYNC_FRAMING_LAYER_SYNC_ADDRESS_FIELD_INDEX + E131_SYNC_ADDR_FIELD_LENGTH;
const E131_SYNC_FRAMING_LAYER_END_INDEX: usize =
E131_SYNC_FRAMING_LAYER_RESERVE_FIELD_INDEX + E131_SYNC_FRAMING_LAYER_RESERVE_FIELD_LENGTH;
impl Pdu for SynchronizationPacketFramingLayer {
fn parse(buf: &[u8]) -> Result<SynchronizationPacketFramingLayer> {
let PduInfo { length, vector } = pdu_info(buf, E131_FRAMING_LAYER_VECTOR_LENGTH)?;
if buf.len() < length {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInsufficientData("Buffer contains insufficient data based on synchronisation packet framing layer pdu length field".to_string())));
}
if vector != VECTOR_E131_EXTENDED_SYNCHRONIZATION {
return Err(SacnError::SacnParsePackError(
ParsePacketError::PduInvalidVector(vector),
));
}
if length != E131_UNIVERSE_SYNC_PACKET_FRAMING_LAYER_LENGTH {
return Err(SacnError::SacnParsePackError(
ParsePacketError::PduInvalidLength(length),
));
}
let sequence_number = buf[E131_SYNC_FRAMING_LAYER_SEQ_NUM_FIELD_INDEX];
let synchronization_address = NetworkEndian::read_u16(
&buf[E131_SYNC_FRAMING_LAYER_SYNC_ADDRESS_FIELD_INDEX
..E131_SYNC_FRAMING_LAYER_RESERVE_FIELD_INDEX],
);
if !(E131_MIN_MULTICAST_UNIVERSE..=E131_MAX_MULTICAST_UNIVERSE)
.contains(&synchronization_address)
{
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInvalidSyncAddr(synchronization_address),
));
}
Ok(SynchronizationPacketFramingLayer {
sequence_number,
synchronization_address,
})
}
fn pack(&self, buf: &mut [u8]) -> Result<()> {
if buf.len() < self.len() {
return Err(SacnError::SacnParsePackError(
ParsePacketError::PackBufferInsufficient(
"SynchronizationPacketFramingLayer pack buffer length insufficient".to_string(),
),
));
}
let flags_and_length =
NetworkEndian::read_u16(&[E131_PDU_FLAGS, 0x0]) | (self.len() as u16) & 0x0fff;
NetworkEndian::write_u16(&mut buf[0..E131_PDU_LENGTH_FLAGS_LENGTH], flags_and_length);
NetworkEndian::write_u32(
&mut buf[E131_SYNC_FRAMING_LAYER_VECTOR_FIELD_INDEX
..E131_SYNC_FRAMING_LAYER_SEQ_NUM_FIELD_INDEX],
VECTOR_E131_EXTENDED_SYNCHRONIZATION,
);
buf[E131_SYNC_FRAMING_LAYER_SEQ_NUM_FIELD_INDEX] = self.sequence_number;
NetworkEndian::write_u16(
&mut buf[E131_SYNC_FRAMING_LAYER_SYNC_ADDRESS_FIELD_INDEX
..E131_SYNC_FRAMING_LAYER_RESERVE_FIELD_INDEX],
self.synchronization_address,
);
zeros(
&mut buf
[E131_SYNC_FRAMING_LAYER_RESERVE_FIELD_INDEX..E131_SYNC_FRAMING_LAYER_END_INDEX],
E131_SYNC_FRAMING_LAYER_RESERVE_FIELD_LENGTH,
);
Ok(())
}
fn len(&self) -> usize {
E131_PDU_LENGTH_FLAGS_LENGTH +
E131_FRAMING_LAYER_VECTOR_LENGTH +
E131_SYNC_FRAMING_LAYER_SEQ_NUM_FIELD_LENGTH +
E131_SYNC_ADDR_FIELD_LENGTH +
E131_SYNC_FRAMING_LAYER_RESERVE_FIELD_LENGTH
}
}
macro_rules! impl_universe_discovery_packet_framing_layer {
( $( $lt:tt )* ) => {
#[derive(Eq, PartialEq, Debug)]
pub struct UniverseDiscoveryPacketFramingLayer$( $lt )* {
pub source_name: Cow<'a, str>,
pub data: UniverseDiscoveryPacketUniverseDiscoveryLayer$( $lt )*,
}
const E131_DISCOVERY_FRAMING_LAYER_VECTOR_FIELD_INDEX: usize = E131_PDU_LENGTH_FLAGS_LENGTH;
const E131_DISCOVERY_FRAMING_LAYER_SOURCE_NAME_FIELD_INDEX: usize = E131_DISCOVERY_FRAMING_LAYER_VECTOR_FIELD_INDEX + E131_FRAMING_LAYER_VECTOR_LENGTH;
const E131_DISCOVERY_FRAMING_LAYER_RESERVE_FIELD_INDEX: usize = E131_DISCOVERY_FRAMING_LAYER_SOURCE_NAME_FIELD_INDEX + E131_SOURCE_NAME_FIELD_LENGTH;
const E131_DISCOVERY_FRAMING_LAYER_DATA_INDEX: usize = E131_DISCOVERY_FRAMING_LAYER_RESERVE_FIELD_INDEX + E131_DISCOVERY_FRAMING_LAYER_RESERVE_FIELD_LENGTH;
impl$( $lt )* Pdu for UniverseDiscoveryPacketFramingLayer$( $lt )* {
fn parse(buf: &[u8]) -> Result<UniverseDiscoveryPacketFramingLayer$( $lt )*> {
let PduInfo { length, vector } = pdu_info(&buf, E131_FRAMING_LAYER_VECTOR_LENGTH)?;
if buf.len() < length {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInsufficientData("Buffer contains insufficient data based on universe discovery packet framing layer pdu length field".to_string())));
}
if vector != VECTOR_E131_EXTENDED_DISCOVERY {
return Err(SacnError::SacnParsePackError(ParsePacketError::PduInvalidVector(vector)));
}
if length < E131_UNIVERSE_DISCOVERY_FRAMING_LAYER_MIN_LENGTH {
return Err(SacnError::SacnParsePackError(ParsePacketError::PduInvalidLength(length)));
}
let source_name = String::from(parse_source_name_str(&buf[E131_DISCOVERY_FRAMING_LAYER_SOURCE_NAME_FIELD_INDEX .. E131_DISCOVERY_FRAMING_LAYER_RESERVE_FIELD_INDEX])?);
let data = UniverseDiscoveryPacketUniverseDiscoveryLayer::parse(&buf[E131_DISCOVERY_FRAMING_LAYER_DATA_INDEX .. length])?;
Ok(UniverseDiscoveryPacketFramingLayer {
source_name: source_name.into(),
data,
})
}
fn pack(&self, buf: &mut [u8]) -> Result<()> {
if buf.len() < self.len() {
return Err(SacnError::SacnParsePackError(ParsePacketError::PackBufferInsufficient("UniverseDiscoveryPacketFramingLayer pack buffer length insufficient".to_string())));
}
let flags_and_length = NetworkEndian::read_u16(&[E131_PDU_FLAGS, 0x0]) | (self.len() as u16) & 0x0fff;
NetworkEndian::write_u16(&mut buf[0 .. E131_DISCOVERY_FRAMING_LAYER_VECTOR_FIELD_INDEX], flags_and_length);
NetworkEndian::write_u32(&mut buf[E131_DISCOVERY_FRAMING_LAYER_VECTOR_FIELD_INDEX .. E131_DISCOVERY_FRAMING_LAYER_SOURCE_NAME_FIELD_INDEX], VECTOR_E131_EXTENDED_DISCOVERY);
zeros(&mut buf[E131_DISCOVERY_FRAMING_LAYER_SOURCE_NAME_FIELD_INDEX .. E131_DISCOVERY_FRAMING_LAYER_RESERVE_FIELD_INDEX], E131_SOURCE_NAME_FIELD_LENGTH);
buf[E131_DISCOVERY_FRAMING_LAYER_SOURCE_NAME_FIELD_INDEX .. E131_DISCOVERY_FRAMING_LAYER_SOURCE_NAME_FIELD_INDEX + self.source_name.len()].copy_from_slice(self.source_name.as_bytes());
zeros(&mut buf[E131_DISCOVERY_FRAMING_LAYER_RESERVE_FIELD_INDEX .. E131_DISCOVERY_FRAMING_LAYER_DATA_INDEX], E131_DISCOVERY_FRAMING_LAYER_RESERVE_FIELD_LENGTH);
self.data.pack(&mut buf[E131_DISCOVERY_FRAMING_LAYER_DATA_INDEX .. ])
}
fn len(&self) -> usize {
E131_PDU_LENGTH_FLAGS_LENGTH +
E131_FRAMING_LAYER_VECTOR_LENGTH +
E131_SOURCE_NAME_FIELD_LENGTH +
E131_DISCOVERY_FRAMING_LAYER_RESERVE_FIELD_LENGTH +
self.data.len()
}
}
impl$( $lt )* Clone for UniverseDiscoveryPacketFramingLayer$( $lt )* {
fn clone(&self) -> Self {
UniverseDiscoveryPacketFramingLayer {
source_name: self.source_name.clone(),
data: self.data.clone(),
}
}
}
impl$( $lt )* Hash for UniverseDiscoveryPacketFramingLayer$( $lt )* {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
(&*self.source_name).hash(state);
self.data.hash(state);
}
}
};
}
impl_universe_discovery_packet_framing_layer!(<'a>);
macro_rules! impl_universe_discovery_packet_universe_discovery_layer {
( $( $lt:tt )* ) => {
#[derive(Eq, PartialEq, Debug)]
pub struct UniverseDiscoveryPacketUniverseDiscoveryLayer$( $lt )* {
pub page: u8,
pub last_page: u8,
pub universes: Cow<'a, [u16]>,
}
const E131_DISCOVERY_LAYER_VECTOR_FIELD_INDEX: usize = E131_PDU_LENGTH_FLAGS_LENGTH;
const E131_DISCOVERY_LAYER_PAGE_FIELD_INDEX: usize = E131_DISCOVERY_LAYER_VECTOR_FIELD_INDEX + E131_DISCOVERY_LAYER_VECTOR_FIELD_LENGTH;
const E131_DISCOVERY_LAYER_LAST_PAGE_FIELD_INDEX: usize = E131_DISCOVERY_LAYER_PAGE_FIELD_INDEX + E131_DISCOVERY_LAYER_PAGE_FIELD_LENGTH;
const E131_DISCOVERY_LAYER_UNIVERSE_LIST_FIELD_INDEX: usize = E131_DISCOVERY_LAYER_LAST_PAGE_FIELD_INDEX + E131_DISCOVERY_LAYER_LAST_PAGE_FIELD_LENGTH;
impl$( $lt )* Pdu for UniverseDiscoveryPacketUniverseDiscoveryLayer$( $lt )* {
fn parse(buf: &[u8]) -> Result<UniverseDiscoveryPacketUniverseDiscoveryLayer$( $lt )*> {
let PduInfo { length, vector } = pdu_info(&buf, E131_DISCOVERY_LAYER_VECTOR_FIELD_LENGTH)?;
if buf.len() != length {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInsufficientData(
format!("Buffer contains incorrect amount of data ({} bytes) based on universe discovery packet universe discovery layer pdu length field ({} bytes)"
, buf.len() ,length).to_string())));
}
if vector != VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST {
return Err(SacnError::SacnParsePackError(ParsePacketError::PduInvalidVector(vector)));
}
if !(E131_UNIVERSE_DISCOVERY_LAYER_MIN_LENGTH..=E131_UNIVERSE_DISCOVERY_LAYER_MAX_LENGTH).contains(&length) {
return Err(SacnError::SacnParsePackError(ParsePacketError::PduInvalidLength(length)));
}
let page = buf[E131_DISCOVERY_LAYER_PAGE_FIELD_INDEX];
let last_page = buf[E131_DISCOVERY_LAYER_LAST_PAGE_FIELD_INDEX];
if page > last_page {
return Err(SacnError::SacnParsePackError(ParsePacketError::ParseInvalidPage("Page value higher than last_page".to_string())));
}
let universes_length = (length - E131_DISCOVERY_LAYER_UNIVERSE_LIST_FIELD_INDEX) / E131_UNIVERSE_FIELD_LENGTH;
let universes: Cow<'a, [u16]> = parse_universe_list(&buf[E131_DISCOVERY_LAYER_UNIVERSE_LIST_FIELD_INDEX ..], universes_length)?;
Ok(UniverseDiscoveryPacketUniverseDiscoveryLayer {
page,
last_page,
universes,
})
}
fn pack(&self, buf: &mut [u8]) -> Result<()> {
if self.universes.len() > DISCOVERY_UNI_PER_PAGE {
return Err(SacnError::SacnParsePackError(
ParsePacketError::PackInvalidData(
format!("Maximum {} universes allowed per discovery page", DISCOVERY_UNI_PER_PAGE).to_string())));
}
if buf.len() < self.len() {
return Err(SacnError::SacnParsePackError(
ParsePacketError::PackBufferInsufficient("UniverseDiscoveryPacketUniverseDiscoveryLayer pack buffer insufficient".to_string())));
}
let flags_and_length = NetworkEndian::read_u16(&[E131_PDU_FLAGS, 0x0]) | (self.len() as u16) & 0x0fff;
NetworkEndian::write_u16(&mut buf[0 .. E131_DISCOVERY_FRAMING_LAYER_VECTOR_FIELD_INDEX], flags_and_length);
NetworkEndian::write_u32(&mut buf[E131_DISCOVERY_LAYER_VECTOR_FIELD_INDEX .. E131_DISCOVERY_LAYER_PAGE_FIELD_INDEX], VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST);
buf[E131_DISCOVERY_LAYER_PAGE_FIELD_INDEX] = self.page;
buf[E131_DISCOVERY_LAYER_LAST_PAGE_FIELD_INDEX] = self.last_page;
for i in 1..self.universes.len() {
if self.universes[i] == self.universes[i - 1] {
return Err(SacnError::SacnParsePackError(ParsePacketError::PackInvalidData("Universes are not unique".to_string())));
}
if self.universes[i] <= self.universes[i - 1] {
return Err(SacnError::SacnParsePackError(ParsePacketError::PackInvalidData("Universes are not sorted".to_string())));
}
}
NetworkEndian::write_u16_into(
&self.universes[..self.universes.len()],
&mut buf[E131_DISCOVERY_LAYER_UNIVERSE_LIST_FIELD_INDEX .. E131_DISCOVERY_LAYER_UNIVERSE_LIST_FIELD_INDEX + self.universes.len() * E131_UNIVERSE_FIELD_LENGTH],
);
Ok(())
}
fn len(&self) -> usize {
E131_PDU_LENGTH_FLAGS_LENGTH +
E131_DISCOVERY_LAYER_VECTOR_FIELD_LENGTH +
E131_DISCOVERY_LAYER_PAGE_FIELD_LENGTH +
E131_DISCOVERY_LAYER_LAST_PAGE_FIELD_LENGTH +
self.universes.len() * E131_UNIVERSE_FIELD_LENGTH
}
}
impl$( $lt )* Clone for UniverseDiscoveryPacketUniverseDiscoveryLayer$( $lt )* {
fn clone(&self) -> Self {
UniverseDiscoveryPacketUniverseDiscoveryLayer {
page: self.page,
last_page: self.last_page,
universes: self.universes.clone(),
}
}
}
impl$( $lt )* Hash for UniverseDiscoveryPacketUniverseDiscoveryLayer$( $lt )* {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.page.hash(state);
self.last_page.hash(state);
(&*self.universes).hash(state);
}
}
};
}
fn parse_universe_list<'a>(buf: &[u8], length: usize) -> Result<Cow<'a, [u16]>> {
let mut universes: Vec<u16> = Vec::with_capacity(length);
let mut i = 0;
let mut last_universe: i32 = -1;
if buf.len() < length * E131_UNIVERSE_FIELD_LENGTH {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInsufficientData(
format!("The given buffer of length {} bytes cannot be parsed into the given number of universes {}", buf.len(), length).to_string())));
}
while i < (length * E131_UNIVERSE_FIELD_LENGTH) {
let u = NetworkEndian::read_u16(&buf[i..i + E131_UNIVERSE_FIELD_LENGTH]);
if (u as i32) > last_universe {
universes.push(u);
last_universe = u as i32;
i += E131_UNIVERSE_FIELD_LENGTH; } else {
return Err(SacnError::SacnParsePackError(
ParsePacketError::ParseInvalidUniverseOrder(
format!("Universe {u} is out of order, discovery packet universe list must be in accending order!").to_string())));
}
}
Ok(universes.into())
}
impl_universe_discovery_packet_universe_discovery_layer!(<'a>);
#[cfg(test)]
mod test {
use super::*;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
#[test]
fn test_universe_to_ipv4_lowest_byte_normal() {
let val: u16 = 119;
let res = universe_to_ipv4_multicast_addr(val).unwrap();
assert!(res.as_socket_ipv4().unwrap().ip().is_multicast());
assert_eq!(
res.as_socket_ipv4().unwrap(),
SocketAddrV4::new(
Ipv4Addr::new(239, 255, (val / 256) as u8, (val % 256) as u8),
ACN_SDT_MULTICAST_PORT
)
);
}
#[test]
fn test_universe_to_ip_ipv4_both_bytes_normal() {
let val: u16 = 300;
let res = universe_to_ipv4_multicast_addr(val).unwrap();
assert!(res.as_socket_ipv4().unwrap().ip().is_multicast());
assert_eq!(
res.as_socket_ipv4().unwrap(),
SocketAddrV4::new(
Ipv4Addr::new(239, 255, (val / 256) as u8, (val % 256) as u8),
ACN_SDT_MULTICAST_PORT
)
);
}
#[test]
fn test_universe_to_ip_ipv4_limit_high() {
let res = universe_to_ipv4_multicast_addr(E131_MAX_MULTICAST_UNIVERSE).unwrap();
assert!(res.as_socket_ipv4().unwrap().ip().is_multicast());
assert_eq!(
res.as_socket_ipv4().unwrap(),
SocketAddrV4::new(
Ipv4Addr::new(
239,
255,
(E131_MAX_MULTICAST_UNIVERSE / 256) as u8,
(E131_MAX_MULTICAST_UNIVERSE % 256) as u8
),
ACN_SDT_MULTICAST_PORT
)
);
}
#[test]
fn test_universe_to_ip_ipv4_limit_low() {
let res = universe_to_ipv4_multicast_addr(E131_MIN_MULTICAST_UNIVERSE).unwrap();
assert!(res.as_socket_ipv4().unwrap().ip().is_multicast());
assert_eq!(
res.as_socket_ipv4().unwrap(),
SocketAddrV4::new(
Ipv4Addr::new(
239,
255,
(E131_MIN_MULTICAST_UNIVERSE / 256) as u8,
(E131_MIN_MULTICAST_UNIVERSE % 256) as u8
),
ACN_SDT_MULTICAST_PORT
)
);
}
#[test]
fn test_universe_to_ip_ipv4_out_range_low() {
match universe_to_ipv4_multicast_addr(0) {
Ok(_) => assert!(
false,
"Universe to ipv4 multicast allowed below minimum allowed universe"
),
Err(e) => match e {
SacnError::IllegalUniverse(_) => assert!(true),
_ => assert!(false, "Unexpected error type returned"),
},
}
}
#[test]
fn test_universe_to_ip_ipv4_out_range_high() {
match universe_to_ipv4_multicast_addr(E131_MAX_MULTICAST_UNIVERSE + 10) {
Ok(_) => assert!(
false,
"Universe to ipv4 multicast allowed above maximum allowed universe"
),
Err(e) => match e {
SacnError::IllegalUniverse(_) => assert!(true),
_ => assert!(false, "Unexpected error type returned"),
},
}
}
#[test]
fn test_universe_to_ipv6_lowest_byte_normal() {
let val: u16 = 119;
let res = universe_to_ipv6_multicast_addr(val).unwrap();
assert!(res.as_socket_ipv6().unwrap().ip().is_multicast());
let low_16: u16 = (((val / 256) as u16) << 8) | ((val % 256) as u16);
assert_eq!(
res.as_socket_ipv6().unwrap(),
SocketAddrV6::new(
Ipv6Addr::new(0xFF18, 0, 0, 0, 0, 0, 0x8300, low_16),
ACN_SDT_MULTICAST_PORT,
0,
0
)
);
}
#[test]
fn test_universe_to_ip_ipv6_both_bytes_normal() {
let val: u16 = 300;
let res = universe_to_ipv6_multicast_addr(val).unwrap();
assert!(res.as_socket_ipv6().unwrap().ip().is_multicast());
let low_16: u16 = (((val / 256) as u16) << 8) | ((val % 256) as u16);
assert_eq!(
res.as_socket_ipv6().unwrap(),
SocketAddrV6::new(
Ipv6Addr::new(0xFF18, 0, 0, 0, 0, 0, 0x8300, low_16),
ACN_SDT_MULTICAST_PORT,
0,
0
)
);
}
#[test]
fn test_universe_to_ip_ipv6_limit_high() {
let res = universe_to_ipv6_multicast_addr(E131_MAX_MULTICAST_UNIVERSE).unwrap();
assert!(res.as_socket_ipv6().unwrap().ip().is_multicast());
let low_16: u16 = (((E131_MAX_MULTICAST_UNIVERSE / 256) as u16) << 8)
| ((E131_MAX_MULTICAST_UNIVERSE % 256) as u16);
assert_eq!(
res.as_socket_ipv6().unwrap(),
SocketAddrV6::new(
Ipv6Addr::new(0xFF18, 0, 0, 0, 0, 0, 0x8300, low_16),
ACN_SDT_MULTICAST_PORT,
0,
0
)
);
}
#[test]
fn test_universe_to_ip_ipv6_limit_low() {
let res = universe_to_ipv6_multicast_addr(E131_MIN_MULTICAST_UNIVERSE).unwrap();
assert!(res.as_socket_ipv6().unwrap().ip().is_multicast());
let low_16: u16 = (((E131_MIN_MULTICAST_UNIVERSE / 256) as u16) << 8)
| ((E131_MIN_MULTICAST_UNIVERSE % 256) as u16);
assert_eq!(
res.as_socket_ipv6().unwrap(),
SocketAddrV6::new(
Ipv6Addr::new(0xFF18, 0, 0, 0, 0, 0, 0x8300, low_16),
ACN_SDT_MULTICAST_PORT,
0,
0
)
);
}
#[test]
fn test_universe_to_ip_ipv6_out_range_low() {
match universe_to_ipv6_multicast_addr(0) {
Ok(_) => assert!(
false,
"Universe to ipv4 multicast allowed below minimum allowed universe"
),
Err(e) => match e {
SacnError::IllegalUniverse(_) => assert!(true),
_ => assert!(false, "Unexpected error type returned"),
},
}
}
#[test]
fn test_universe_to_ip_ipv6_out_range_high() {
match universe_to_ipv6_multicast_addr(E131_MAX_MULTICAST_UNIVERSE + 10) {
Ok(_) => assert!(
false,
"Universe to ipv4 multicast allowed above maximum allowed universe"
),
Err(e) => match e {
SacnError::IllegalUniverse(_) => assert!(true),
_ => assert!(false, "Unexpected error type returned"),
},
}
}
#[test]
fn check_ansi_e131_2018_parameter_values() {
assert_eq!(VECTOR_ROOT_E131_DATA, 0x0000_0004);
assert_eq!(VECTOR_ROOT_E131_EXTENDED, 0x0000_0008);
assert_eq!(VECTOR_DMP_SET_PROPERTY, 0x02);
assert_eq!(VECTOR_E131_DATA_PACKET, 0x0000_0002);
assert_eq!(VECTOR_E131_EXTENDED_SYNCHRONIZATION, 0x0000_0001);
assert_eq!(VECTOR_E131_EXTENDED_DISCOVERY, 0x0000_0002);
assert_eq!(VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST, 0x0000_0001);
assert_eq!(E131_UNIVERSE_DISCOVERY_INTERVAL, Duration::from_secs(10));
assert_eq!(E131_NETWORK_DATA_LOSS_TIMEOUT, Duration::from_millis(2500));
assert_eq!(E131_DISCOVERY_UNIVERSE, 64214);
assert_eq!(ACN_SDT_MULTICAST_PORT, 5568);
}
}