use std::io;
#[cfg(any(feature = "_egress", feature = "_sender-qwp-ws"))]
use std::io::{Read, Write};
use std::net::TcpStream;
#[cfg(any(
target_os = "macos",
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
all(
any(feature = "_egress", feature = "_sender-qwp-ws"),
any(target_os = "linux", target_os = "android"),
),
))]
use std::os::fd::AsRawFd;
pub(crate) fn apply_so_nosigpipe(_tcp: &TcpStream) -> io::Result<()> {
#[cfg(any(
target_os = "macos",
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
))]
{
let enable: libc::c_int = 1;
let ret = unsafe {
libc::setsockopt(
_tcp.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_NOSIGPIPE,
&enable as *const libc::c_int as *const libc::c_void,
std::mem::size_of_val(&enable) as libc::socklen_t,
)
};
if ret != 0 {
return Err(io::Error::last_os_error());
}
}
Ok(())
}
#[cfg(any(feature = "_egress", feature = "_sender-qwp-ws"))]
pub(crate) struct NoSigpipeTcp(TcpStream);
#[cfg(any(feature = "_egress", feature = "_sender-qwp-ws"))]
impl NoSigpipeTcp {
pub(crate) fn new(tcp: TcpStream) -> io::Result<Self> {
apply_so_nosigpipe(&tcp)?;
Ok(Self(tcp))
}
pub(crate) fn tcp(&self) -> &TcpStream {
&self.0
}
#[cfg(feature = "_egress")]
pub(crate) fn tcp_mut(&mut self) -> &mut TcpStream {
&mut self.0
}
#[cfg(feature = "_egress")]
pub(crate) fn try_clone(&self) -> io::Result<Self> {
Ok(Self(self.0.try_clone()?))
}
}
#[cfg(any(feature = "_egress", feature = "_sender-qwp-ws"))]
impl Read for NoSigpipeTcp {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
#[cfg(any(feature = "_egress", feature = "_sender-qwp-ws"))]
impl Write for NoSigpipeTcp {
#[cfg(any(target_os = "linux", target_os = "android"))]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let ret = unsafe {
libc::send(
self.0.as_raw_fd(),
buf.as_ptr() as *const libc::c_void,
buf.len(),
libc::MSG_NOSIGNAL,
)
};
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret as usize)
}
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}