Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,10 @@ pub fn universe_to_ipv6_multicast_addr(universe: u16) -> Result<SockAddr> {
.into())
}

/// Checks if the given universe is a valid universe to send on (within allowed range).
/// Checks if the given universe is a valid universe to send on or listen to (within allowed range).
///
/// This includes `E131_DISCOVERY_UNIVERSE`, which carries universe discovery packets. Use
/// [`is_data_universe_in_range`] for universes that carry DMX data or synchronisation packets.
///
/// # Errors
/// `IllegalUniverse`: Returned if the universe is outwith the allowed range of universes
Expand All @@ -378,6 +381,20 @@ pub fn is_universe_in_range(universe: u16) -> Result<()> {
Ok(())
}

/// Checks if the given universe can carry DMX data or synchronisation packets.
///
/// As per ANSI E1.31-2016 Section 6.2.7 data universes are limited to the range 1 to 63999, so unlike
/// [`is_universe_in_range`] this excludes `E131_DISCOVERY_UNIVERSE` (64214), which is reserved for universe discovery.
///
/// # Errors
/// `IllegalUniverse`: Returned if the universe is outwith [`E131_MIN_MULTICAST_UNIVERSE`, `E131_MAX_MULTICAST_UNIVERSE`].
pub fn is_data_universe_in_range(universe: u16) -> Result<()> {
if !(E131_MIN_MULTICAST_UNIVERSE..=E131_MAX_MULTICAST_UNIVERSE).contains(&universe) {
return Err(SacnError::IllegalUniverse(universe));
}
Ok(())
}

/// Fills the given array of bytes with the given length n with bytes of value 0.
#[inline]
fn zeros(buf: &mut [u8], n: usize) {
Expand Down
12 changes: 6 additions & 6 deletions src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,9 @@ impl SacnSourceInternal {
/// If a universe is already registered then this method has no effect.
///
/// # Errors
/// `IllegalUniverse`: Returned if the universe is outwith the allowed range, see (`is_universe_in_range`)[`fn.is_universe_in_range.packet`].
/// `IllegalUniverse`: Returned if the universe can't carry data, see (`is_data_universe_in_range`)[`fn.is_data_universe_in_range.packet`].
fn register_universe(&mut self, universe: u16) -> Result<()> {
is_universe_in_range(universe)?;
is_data_universe_in_range(universe)?;

if self.universes.is_empty() {
self.universes.push(universe);
Expand Down Expand Up @@ -672,11 +672,11 @@ impl SacnSourceInternal {
/// Checks if the given universe is a valid universe to send on (within allowed range) and that it is registered with this `SacnSourceInternal`.
///
/// # Errors
/// `IllegalUniverse`: Returned if the universe is outwith the allowed range, see (`is_universe_in_range`)[`fn.is_universe_in_range.packet`].
/// `IllegalUniverse`: Returned if the universe can't carry data, see (`is_data_universe_in_range`)[`fn.is_data_universe_in_range.packet`].
///
/// `UniverseNotRegistered`: Returned if the universe is not registered on the given `SacnSourceInternal`.
fn universe_allowed(&self, u: &u16) -> Result<()> {
is_universe_in_range(*u)?;
is_data_universe_in_range(*u)?;

if !self.universes.contains(u) {
return Err(SacnError::UniverseNotRegistered(*u));
Expand Down Expand Up @@ -751,7 +751,7 @@ impl SacnSourceInternal {
// Check that the synchronisation universe is a valid universe. It doesn't need to be registered: a synchronisation
// universe carries no data, so it isn't advertised in universe discovery.
if let Some(sync_addr) = synchronisation_addr {
is_universe_in_range(sync_addr)
is_data_universe_in_range(sync_addr)
.map_err(|_e| SacnError::IllegalSyncUniverse(sync_addr))?;
}

Expand Down Expand Up @@ -894,7 +894,7 @@ impl SacnSourceInternal {
///
/// `SacnParsePackError`: Returned if the sync packet fails to be packed.
fn send_sync_packet(&self, universe: u16, dst_ip: Option<SocketAddr>) -> Result<()> {
is_universe_in_range(universe)?;
is_data_universe_in_range(universe)?;

let ip = if let Some(dst) = dst_ip {
dst.into()
Expand Down
50 changes: 39 additions & 11 deletions tests/src_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,24 +488,52 @@ fn test_register_above_max_universe() {
}
}

/// Attempt to register the discovery universe. Even though this is higher than the maximum allowed universe this should succeed as per ANSI E1.31-2018 Section 6.2.7.
/// Attempt to register the discovery universe. This should fail: as per ANSI E1.31-2016 Section 6.2.7 data universes are
/// limited to 1 to 63999, and universe 64214 is reserved for universe discovery packets.
/// Extreme test.
#[test]
#[serial]
fn test_register_discovery_universe() {
let mut src = SacnSource::new_v4("Controller").unwrap();
match src.register_universes(&[E131_DISCOVERY_UNIVERSE]) {
Err(e) => {
assert!(
false,
"Unexpected error returned when attempting to register discovery universe, {:?}",
e
);
}
_ => {
assert!(true, "Registration successful");
}
Err(SacnError::IllegalUniverse(_)) => {}
other => panic!("Expected IllegalUniverse when registering the discovery universe, got {other:?}"),
}
assert!(src.universes().unwrap().is_empty());
}

/// Data and sync packets can't be sent on the discovery universe, even without registering it.
#[test]
#[serial]
fn test_send_on_discovery_universe_rejected() {
let mut src = SacnSource::new_v4("Controller").unwrap();
src.register_universe(1).unwrap();

match src.send(&[E131_DISCOVERY_UNIVERSE], &[0u8; 513], None, None, None) {
Err(SacnError::IllegalUniverse(_)) => {}
other => panic!("Expected IllegalUniverse for data on the discovery universe, got {other:?}"),
}

match src.send(&[1], &[0u8; 513], None, None, Some(E131_DISCOVERY_UNIVERSE)) {
Err(SacnError::IllegalSyncUniverse(_)) => {}
other => panic!("Expected IllegalSyncUniverse for the discovery universe as sync address, got {other:?}"),
}

match src.send_sync_packet(E131_DISCOVERY_UNIVERSE, None) {
Err(SacnError::IllegalUniverse(_)) => {}
other => panic!("Expected IllegalUniverse for a sync packet on the discovery universe, got {other:?}"),
}
}

#[test]
fn test_is_data_universe_in_range() {
assert!(is_data_universe_in_range(E131_MIN_MULTICAST_UNIVERSE).is_ok());
assert!(is_data_universe_in_range(E131_MAX_MULTICAST_UNIVERSE).is_ok());
assert!(is_data_universe_in_range(0).is_err());
assert!(is_data_universe_in_range(E131_MAX_MULTICAST_UNIVERSE + 1).is_err());
assert!(is_data_universe_in_range(E131_DISCOVERY_UNIVERSE).is_err());
// The discovery universe is still a valid universe to send discovery packets on and listen to.
assert!(is_universe_in_range(E131_DISCOVERY_UNIVERSE).is_ok());
}

/// Attempt to register the maximum allowed universe, this should succeed as the allowed range is inclusive of this universe.
Expand Down
Loading