1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};

pub const MULTICAST_PORT: u16 = 5353;
pub const MULTICAST_ADDR_IPV4: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 251);
pub const MULTICAST_ADDR_IPV6: Ipv6Addr = Ipv6Addr::new(0xFF02, 0, 0, 0, 0, 0, 0, 0xFB);

/// Network scope to be used by service discovery
/// Default scope for services is to use IPV4 protocol
#[derive(Debug, Copy, Clone)]
pub enum NetworkScope {
    /// Uses IPV4 protocol with UNSPECIFIED network interface (0.0.0.0)
    V4,
    /// Uses IPV4 protocol and provided network interface
    V4WithInterface(Ipv4Addr),
    /// Uses IPV6 protocol with UNSPECIFIED network interface (0)
    V6,
    /// Uses IPV6 protocol with provided network interface
    V6WithInterface(u32),
}

impl NetworkScope {
    /// Returns `true` if the network scope is [`V4`] or [`V4WithInterface`].
    ///
    /// [`V4`]: NetworkScope::V4
    /// [`V4WithInterface`]: NetworkScope::V4WithInterface
    #[must_use]
    pub fn is_v4(&self) -> bool {
        matches!(&self, Self::V4 | Self::V4WithInterface(..))
    }

    /// Gets de socket address for the network scope.
    pub fn socket_address(&self) -> SocketAddr {
        if self.is_v4() {
            SocketAddr::new(IpAddr::V4(MULTICAST_ADDR_IPV4), MULTICAST_PORT)
        } else {
            SocketAddr::new(IpAddr::V6(MULTICAST_ADDR_IPV6), MULTICAST_PORT)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ipv4_multicast() {
        assert!(MULTICAST_ADDR_IPV4.is_multicast());
    }

    #[test]
    fn test_ipv6_multicast() {
        assert!(MULTICAST_ADDR_IPV6.is_multicast());
    }
}