#[cfg(any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
))]
mod inner {
use std::io;
pub(crate) const RECV_FLAGS: libc::c_int = libc::MSG_CMSG_CLOEXEC;
#[inline]
pub(crate) fn cloexec_received(_buf: &[u8]) -> io::Result<()> {
Ok(())
}
#[inline]
pub(crate) fn max_recv_fds() -> usize {
253
}
}
#[cfg(not(any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
)))]
mod inner {
use std::io;
use std::mem;
use std::os::unix::io::RawFd;
pub(crate) const RECV_FLAGS: libc::c_int = 0;
fn set_cloexec(fd: RawFd) -> io::Result<()> {
unsafe {
let flags = libc::fcntl(fd, libc::F_GETFD);
if flags < 0 {
return Err(io::Error::last_os_error());
}
let ret = libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC);
if ret < 0 {
return Err(io::Error::last_os_error());
}
}
Ok(())
}
fn raw_fds_in_buffer(buf: &[u8]) -> Vec<RawFd> {
let mut out = Vec::new();
if buf.is_empty() {
return out;
}
let mut msg: libc::msghdr = unsafe { mem::zeroed() };
msg.msg_control = buf.as_ptr() as *mut libc::c_void;
msg.msg_controllen = buf.len() as _;
let mut cur = unsafe { libc::CMSG_FIRSTHDR(&msg) };
while !cur.is_null() {
#[allow(clippy::unnecessary_cast)]
unsafe {
let cmsg = &*cur;
if cmsg.cmsg_level == libc::SOL_SOCKET && cmsg.cmsg_type == libc::SCM_RIGHTS {
let data_ptr = libc::CMSG_DATA(cur as *mut _);
let header_len = (data_ptr as usize).saturating_sub(cur as usize);
let total = cmsg.cmsg_len as usize;
let data_len = total.saturating_sub(header_len);
let n = data_len / mem::size_of::<RawFd>();
let fd_ptr = data_ptr as *const RawFd;
for i in 0..n {
out.push(std::ptr::read_unaligned(fd_ptr.add(i)));
}
}
cur = libc::CMSG_NXTHDR(&msg, cur);
}
}
out
}
pub(crate) fn cloexec_received(buf: &[u8]) -> io::Result<()> {
let fds = raw_fds_in_buffer(buf);
for &raw in &fds {
if let Err(e) = set_cloexec(raw) {
for &all in &fds {
unsafe {
libc::close(all);
}
}
return Err(e);
}
}
Ok(())
}
const HARD_CEILING: usize = 1 << 20;
const HARD_FLOOR: usize = 253;
pub(crate) fn max_recv_fds() -> usize {
let mut rlim: libc::rlimit = unsafe { mem::zeroed() };
let rc = unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) };
if rc < 0 {
return HARD_CEILING;
}
let cur = rlim.rlim_cur;
let n: usize = if cur == libc::RLIM_INFINITY {
HARD_CEILING
} else {
usize::try_from(cur).unwrap_or(HARD_CEILING)
};
n.clamp(HARD_FLOOR, HARD_CEILING)
}
}
pub(crate) use inner::*;