use libc::{in_addr, sockaddr_storage};
use crate::{cerr, control_message::empty_msghdr, raw_socket::sockaddr_len};
use super::{control_message, RawSocket};
impl RawSocket {
pub(crate) fn so_timestamp(&self, options: u32) -> std::io::Result<()> {
#[expect(
clippy::cast_possible_truncation,
reason = "options is small enough that its size always fits."
)]
unsafe {
cerr(libc::setsockopt(
self.fd,
libc::SOL_SOCKET,
libc::SO_TIMESTAMP,
(&raw const options).cast::<libc::c_void>(),
std::mem::size_of_val(&options) as libc::socklen_t,
))
}?;
Ok(())
}
#[expect(
clippy::cast_possible_truncation,
reason = "enabled is small enough that its size always fits."
)]
pub(crate) fn enable_destination_ipv4(&self) -> std::io::Result<()> {
let enabled: libc::c_int = 1;
unsafe {
cerr(libc::setsockopt(
self.fd,
libc::IPPROTO_IP,
libc::IP_RECVDSTADDR,
(&raw const enabled).cast::<libc::c_void>(),
std::mem::size_of_val(&enabled) as libc::socklen_t,
))?;
}
Ok(())
}
#[expect(
clippy::cast_possible_truncation,
reason = "control message length is small enough that its size always fits."
)]
pub(crate) fn send_from_v4(&self, msg: &[u8], addr: in_addr) -> std::io::Result<()> {
let mut control_message = control_message(
libc::IPPROTO_IP,
libc::IP_PKTINFO,
libc::in_pktinfo {
ipi_ifindex: 0,
ipi_spec_dst: addr,
ipi_addr: libc::in_addr { s_addr: 0 },
},
);
let mut iov = libc::iovec {
iov_base: msg.as_ptr() as *mut libc::c_void,
iov_len: msg.len(),
};
let mut msghdr = empty_msghdr();
msghdr.msg_iov = &raw mut iov;
msghdr.msg_iovlen = 1;
msghdr.msg_control = control_message.as_mut_ptr().cast();
msghdr.msg_controllen = control_message.len() as _;
cerr(unsafe { libc::sendmsg(self.fd, &raw const msghdr, 0) } as _).map(|_| {})
}
#[expect(
clippy::cast_possible_truncation,
reason = "control message length is small enough that its size always fits."
)]
pub(crate) fn send_from_to_v4(
&self,
msg: &[u8],
from: in_addr,
mut to: sockaddr_storage,
) -> std::io::Result<()> {
let to_len = sockaddr_len(to);
let mut control_message = control_message(
libc::IPPROTO_IP,
libc::IP_PKTINFO,
libc::in_pktinfo {
ipi_ifindex: 0,
ipi_spec_dst: from,
ipi_addr: libc::in_addr { s_addr: 0 },
},
);
let mut iov = libc::iovec {
iov_base: msg.as_ptr() as *mut libc::c_void,
iov_len: msg.len(),
};
let mut msghdr = empty_msghdr();
msghdr.msg_name = (&raw mut to).cast();
msghdr.msg_namelen = to_len;
msghdr.msg_iov = &raw mut iov;
msghdr.msg_iovlen = 1;
msghdr.msg_control = control_message.as_mut_ptr().cast();
msghdr.msg_controllen = control_message.len() as _;
cerr(unsafe { libc::sendmsg(self.fd, &raw const msghdr, 0) } as _).map(|_| {})
}
}