use std::io::{self, IoSlice};
use std::net::TcpStream;
use std::os::fd::{AsRawFd, RawFd};
use std::time::Duration;
pub(crate) struct Interest {
pub fd: Option<RawFd>,
pub events: libc::c_short,
}
pub(crate) const READABLE: libc::c_short = libc::POLLIN;
pub(crate) const WRITABLE: libc::c_short = libc::POLLOUT;
pub(crate) fn wait<const N: usize>(interests: [Interest; N], timeout: Duration) -> io::Result<()> {
let mut fds = interests.map(|interest| libc::pollfd {
fd: interest.fd.unwrap_or(-1),
events: interest.events,
revents: 0,
});
let millis = timeout.as_nanos().div_ceil(1_000_000).min(libc::c_int::MAX as u128) as libc::c_int;
let ready = unsafe { libc::poll(fds.as_mut_ptr(), N as libc::nfds_t, millis) };
if ready >= 0 {
return Ok(());
}
let error = io::Error::last_os_error();
if error.kind() == io::ErrorKind::Interrupted {
Ok(())
} else {
Err(error)
}
}
#[cfg(not(target_vendor = "apple"))]
pub(crate) fn send_vectored(stream: &TcpStream, slices: &[IoSlice<'_>]) -> io::Result<usize> {
let mut header: libc::msghdr = unsafe { std::mem::zeroed() };
header.msg_iov = slices.as_ptr() as *mut libc::iovec;
header.msg_iovlen = slices.len() as _;
let sent = unsafe { libc::sendmsg(stream.as_raw_fd(), &header, libc::MSG_NOSIGNAL) };
if sent < 0 {
Err(io::Error::last_os_error())
} else {
Ok(sent as usize)
}
}
#[cfg(target_vendor = "apple")]
pub(crate) fn send_vectored(stream: &TcpStream, slices: &[IoSlice<'_>]) -> io::Result<usize> {
use std::io::Write;
let mut writer = stream;
writer.write_vectored(slices)
}
#[cfg(target_vendor = "apple")]
pub(crate) fn suppress_sigpipe(stream: &TcpStream) -> io::Result<()> {
let enabled: libc::c_int = 1;
let status = unsafe {
libc::setsockopt(
stream.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_NOSIGPIPE,
(&enabled as *const libc::c_int).cast(),
std::mem::size_of::<libc::c_int>() as libc::socklen_t,
)
};
if status == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
#[cfg(not(target_vendor = "apple"))]
pub(crate) fn suppress_sigpipe(_stream: &TcpStream) -> io::Result<()> {
Ok(())
}