Skip to content

Commit 2638437

Browse files
committed
Added Socket::set_multicast_if_v4_n to set interface by index (#458)
1 parent 9a30f4f commit 2638437

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ pub use sockaddr::{sa_family_t, socklen_t, SockAddr, SockAddrStorage};
189189
#[cfg(not(any(
190190
target_os = "haiku",
191191
target_os = "illumos",
192-
target_os = "netbsd",
193192
target_os = "redox",
194193
target_os = "solaris",
195194
)))]

src/socket.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,6 @@ fn set_common_accept_flags(socket: Socket) -> io::Result<Socket> {
845845
#[cfg(not(any(
846846
target_os = "haiku",
847847
target_os = "illumos",
848-
target_os = "netbsd",
849848
target_os = "redox",
850849
target_os = "solaris",
851850
)))]
@@ -1520,6 +1519,66 @@ impl Socket {
15201519
}
15211520
}
15221521

1522+
/// Set the value of the `IP_MULTICAST_IF` option for this socket.
1523+
///
1524+
/// Specifies the interface to use for routing multicast packets.
1525+
/// See [`InterfaceIndexOrAddress`].
1526+
#[cfg(all(
1527+
feature = "all",
1528+
any(
1529+
target_os = "freebsd",
1530+
target_os = "netbsd",
1531+
target_os = "linux",
1532+
target_os = "android",
1533+
target_os = "fuchsia",
1534+
)
1535+
))]
1536+
pub fn set_multicast_if_v4_n(&self, interface: &InterfaceIndexOrAddress) -> io::Result<()> {
1537+
#[cfg(any(
1538+
target_os = "freebsd",
1539+
target_os = "linux",
1540+
target_os = "android",
1541+
target_os = "fuchsia"
1542+
))]
1543+
{
1544+
// IP_MULTICAST_IF supports struct mreqn to set the interface
1545+
let mreqn = sys::to_mreqn(&Ipv4Addr::UNSPECIFIED, interface);
1546+
unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF, mreqn) }
1547+
}
1548+
1549+
#[cfg(target_os = "netbsd")]
1550+
{
1551+
// IP_MULTICAST_IF only supports struct in_addr to set the interface, but passing an
1552+
// address in the 0.0.0.0/8 range is interpreted as an interface index (in network
1553+
// byte order), see ip_multicast_if() in
1554+
// https://github.com/NetBSD/src/blob/trunk/sys/netinet/ip_output.c; alternatively, as
1555+
// shown in the example code in https://man.netbsd.org/NetBSD-7.0/ip.4, the interface
1556+
// index can be passed as uint32_t in network byte order
1557+
match interface {
1558+
InterfaceIndexOrAddress::Index(index) => {
1559+
if *index >= 0x0100_0000 {
1560+
return Err(io::Error::new(
1561+
io::ErrorKind::AddrNotAvailable,
1562+
"Interface index out of bounds",
1563+
));
1564+
}
1565+
let index_be = (*index as u32).to_be();
1566+
unsafe {
1567+
setsockopt(
1568+
self.as_raw(),
1569+
sys::IPPROTO_IP,
1570+
sys::IP_MULTICAST_IF,
1571+
index_be,
1572+
)
1573+
}
1574+
}
1575+
InterfaceIndexOrAddress::Address(a) => unsafe {
1576+
setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF, *a)
1577+
},
1578+
}
1579+
}
1580+
}
1581+
15231582
/// Get the value of the `IP_MULTICAST_LOOP` option for this socket.
15241583
///
15251584
/// For more information about this option, see [`set_multicast_loop_v4`].

0 commit comments

Comments
 (0)