1use crate::*;
2use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
3use std::time::Duration;
4
5pub struct UdpMulticastSocket {
6 socket: UdpSocket,
7 port: u16,
8}
9
10impl UdpMulticastSocket {
11 pub fn bind(port: u16) -> Result<Self> {
12 let addr = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, port);
13 let socket = UdpSocket::bind(addr).map_err(|_| SigNetError::Network)?;
14 socket.set_read_timeout(Some(Duration::from_millis(100))).ok();
15 Ok(UdpMulticastSocket { socket, port })
16 }
17
18 pub fn set_multicast_ttl(&self, ttl: u8) -> Result<()> {
19 self.socket
20 .set_multicast_ttl_v4(ttl as u32)
21 .map_err(|_| SigNetError::Network)
22 }
23
24 pub fn set_multicast_loopback(&self, enabled: bool) -> Result<()> {
25 self.socket
26 .set_multicast_loop_v4(enabled)
27 .map_err(|_| SigNetError::Network)
28 }
29
30 pub fn join_multicast_group(&self, multicast_addr: Ipv4Addr, interface: Option<Ipv4Addr>) -> Result<()> {
31 let iface = interface.unwrap_or(Ipv4Addr::UNSPECIFIED);
32 self.socket
33 .join_multicast_v4(&multicast_addr, &iface)
34 .map_err(|_| SigNetError::Network)
35 }
36
37 pub fn leave_multicast_group(&self, multicast_addr: Ipv4Addr, interface: Option<Ipv4Addr>) -> Result<()> {
38 let iface = interface.unwrap_or(Ipv4Addr::UNSPECIFIED);
39 self.socket
40 .leave_multicast_v4(&multicast_addr, &iface)
41 .map_err(|_| SigNetError::Network)
42 }
43
44 pub fn send_to(&self, data: &[u8], dest: SocketAddrV4) -> Result<usize> {
45 self.socket.send_to(data, dest).map_err(|_| SigNetError::Network)
46 }
47
48 pub fn send_multicast(&self, data: &[u8], universe: u16) -> Result<usize> {
49 let octets = calculate_multicast_address(universe)?;
50 let addr = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]);
51 let dest = SocketAddrV4::new(addr, self.port);
52 self.send_to(data, dest)
53 }
54
55 pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddrV4)> {
56 self.socket
57 .recv_from(buf)
58 .map_err(|_| SigNetError::Network)
59 .and_then(|(n, addr)| match addr {
60 std::net::SocketAddr::V4(v4) => Ok((n, v4)),
61 _ => Err(SigNetError::Network),
62 })
63 }
64}