use crate::error::McrxError;
use std::net::Ipv4Addr;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SourceFilter {
Any,
Source(Ipv4Addr),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SubscriptionConfig {
pub group: Ipv4Addr,
pub source: SourceFilter,
pub dst_port: u16,
pub interface: Option<Ipv4Addr>,
}
impl SubscriptionConfig {
pub fn validate(&self) -> Result<(), McrxError> {
if self.dst_port == 0 {
return Err(McrxError::InvalidDestinationPort);
}
if !self.group.is_multicast() {
return Err(McrxError::InvalidMulticastGroup);
}
if let SourceFilter::Source(source) = self.source
&& source.is_multicast()
{
return Err(McrxError::InvalidSourceAddress);
}
Ok(())
}
pub fn asm(group: Ipv4Addr, port: u16) -> Self {
Self {
group,
source: SourceFilter::Any,
dst_port: port,
interface: None,
}
}
pub fn ssm(group: Ipv4Addr, source: Ipv4Addr, port: u16) -> Self {
Self {
group,
source: SourceFilter::Source(source),
dst_port: port,
interface: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_multicast_config_passes_validation() {
let cfg = SubscriptionConfig {
group: Ipv4Addr::new(239, 1, 2, 3),
source: SourceFilter::Any,
dst_port: 5000,
interface: None,
};
assert!(cfg.validate().is_ok());
}
#[test]
fn port_zero_fails_validation() {
let cfg = SubscriptionConfig {
group: Ipv4Addr::new(239, 1, 2, 3),
source: SourceFilter::Any,
dst_port: 0,
interface: None,
};
let result = cfg.validate();
assert!(matches!(result, Err(McrxError::InvalidDestinationPort)));
}
#[test]
fn non_multicast_group_fails_validation() {
let cfg = SubscriptionConfig {
group: Ipv4Addr::new(192, 168, 1, 10),
source: SourceFilter::Any,
dst_port: 5000,
interface: None,
};
let result = cfg.validate();
assert!(matches!(result, Err(McrxError::InvalidMulticastGroup)));
}
#[test]
fn multicast_source_fails_validation() {
let cfg = SubscriptionConfig {
group: Ipv4Addr::new(232, 1, 2, 3),
source: SourceFilter::Source(Ipv4Addr::new(239, 1, 1, 1)),
dst_port: 5000,
interface: None,
};
let result = cfg.validate();
assert!(matches!(result, Err(McrxError::InvalidSourceAddress)));
}
}