use std::net::IpAddr;
use std::os::fd::AsRawFd;
use socket2::Socket;
use crate::{raw, Interface, Membership, MulticastError, Result};
pub(crate) fn set_reuse_port(socket: &Socket, enabled: bool) -> Result<()> {
let value: libc::c_int = enabled.into();
let result = unsafe {
libc::setsockopt(
socket.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_REUSEPORT,
(&value as *const libc::c_int).cast(),
std::mem::size_of_val(&value) as libc::socklen_t,
)
};
if result == -1 {
return Err(std::io::Error::last_os_error().into());
}
Ok(())
}
pub(crate) fn join_membership(
socket: &Socket,
membership: &Membership,
inbound_interface: Option<&Interface>,
) -> Result<()> {
match membership {
Membership::AnySource {
group: IpAddr::V4(group),
} => {
let interface = raw::default_interface_v4(inbound_interface)?;
raw::membership_target(membership)?;
socket.join_multicast_v4(group, &interface)?;
Ok(())
}
Membership::AnySource {
group: IpAddr::V6(group),
} => {
let index = raw::default_interface_v6(inbound_interface)?;
raw::membership_target(membership)?;
socket.join_multicast_v6(group, index)?;
Ok(())
}
Membership::SourceSpecific { .. } => Err(MulticastError::UnsupportedOption(
"source-specific multicast",
)),
}
}
pub(crate) fn loopback_interface_v6() -> Option<u32> {
let name = std::ffi::CString::new("lo").ok()?;
let index = unsafe { libc::if_nametoindex(name.as_ptr()) };
(index != 0).then_some(index)
}