use std::{
io,
mem::MaybeUninit,
net::Shutdown,
os::fd::AsRawFd,
path::{Path, PathBuf},
time::Duration,
};
use socket2::{Domain, SockAddr, Socket, Type};
use crate::buf::{BufResult, IoBuf, IoBufMut};
#[cfg(nexio_poll)]
use super::sock::Io as Sock;
#[cfg(nexio_uring)]
struct Sock {
sock: Socket,
}
#[cfg(nexio_uring)]
impl Drop for Sock {
fn drop(&mut self) {
let _ = crate::reactor::REACTOR.try_with(|r| {
if let Ok(mut r) = r.try_borrow_mut() {
r.flush_queued();
}
});
}
}
#[cfg(nexio_uring)]
impl Sock {
fn new(sock: Socket) -> io::Result<Self> {
sock.set_nonblocking(true)?;
Ok(Self { sock })
}
async fn ready(&self, write: bool) -> io::Result<()> {
let fd = self.sock.as_raw_fd();
let op = crate::reactor::REACTOR.with(|r| {
let mut r = r.borrow_mut();
if write {
r.poll_writable(fd)
} else {
r.poll_readable(fd)
}
})?;
op.await.map(|_| ())
}
}
fn path_of(addr: &SockAddr) -> Option<PathBuf> {
addr.as_pathname().map(Path::to_path_buf)
}
fn would_block(e: &io::Error) -> bool {
e.kind() == io::ErrorKind::WouldBlock
}
fn send_nosig(sock: &Socket, data: &[u8]) -> io::Result<usize> {
#[cfg(not(target_vendor = "apple"))]
{
sock.send_with_flags(data, libc::MSG_NOSIGNAL)
}
#[cfg(target_vendor = "apple")]
{
sock.send(data)
}
}
pub struct UnixListener {
io: Sock,
}
impl UnixListener {
pub fn bind(path: impl AsRef<Path>) -> io::Result<Self> {
let sock = Socket::new(Domain::UNIX, Type::STREAM, None)?;
sock.bind(&SockAddr::unix(path)?)?;
sock.listen(1024)?;
Ok(Self {
io: Sock::new(sock)?,
})
}
pub fn from_std(listener: std::os::unix::net::UnixListener) -> io::Result<Self> {
Ok(Self {
io: Sock::new(Socket::from(listener))?,
})
}
pub fn local_path(&self) -> io::Result<Option<PathBuf>> {
Ok(path_of(&self.io.sock.local_addr()?))
}
pub async fn accept(&self) -> io::Result<UnixStream> {
loop {
match self.io.sock.accept() {
Ok((sock, _)) => {
return Ok(UnixStream {
io: Sock::new(sock)?,
})
}
Err(e) if would_block(&e) => self.io.ready(false).await?,
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.io.sock.take_error()
}
pub fn as_raw_fd(&self) -> std::os::fd::RawFd {
self.io.sock.as_raw_fd()
}
}
pub struct UnixStream {
io: Sock,
}
impl UnixStream {
pub async fn connect(path: impl AsRef<Path>) -> io::Result<Self> {
let addr = SockAddr::unix(path)?;
let io = Sock::new(Socket::new(Domain::UNIX, Type::STREAM, None)?)?;
let mut delay = Duration::from_micros(200);
let mut refused_retries = 0u32;
loop {
match io.sock.connect(&addr) {
Ok(()) => return Ok(Self { io }),
Err(e)
if cfg!(target_vendor = "apple")
&& e.kind() == io::ErrorKind::ConnectionRefused
&& refused_retries < 300 =>
{
refused_retries += 1;
crate::time::sleep(delay).await;
delay = (delay * 2).min(Duration::from_millis(10));
}
Err(e) if would_block(&e) => {
crate::time::sleep(delay).await;
delay = (delay * 2).min(Duration::from_millis(10));
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
}
pub fn pair() -> io::Result<(Self, Self)> {
let (a, b) = Socket::pair(Domain::UNIX, Type::STREAM, None)?;
Ok((Self { io: Sock::new(a)? }, Self { io: Sock::new(b)? }))
}
pub fn from_std(stream: std::os::unix::net::UnixStream) -> io::Result<Self> {
Ok(Self {
io: Sock::new(Socket::from(stream))?,
})
}
pub fn local_path(&self) -> io::Result<Option<PathBuf>> {
Ok(path_of(&self.io.sock.local_addr()?))
}
pub fn peer_path(&self) -> io::Result<Option<PathBuf>> {
Ok(path_of(&self.io.sock.peer_addr()?))
}
pub async fn read<B>(&self, mut buf: B) -> BufResult<usize, B>
where
B: IoBufMut + Send + 'static,
{
loop {
let total = buf.bytes_total();
let ptr = buf.stable_ptr_mut() as *mut MaybeUninit<u8>;
let spare = unsafe { std::slice::from_raw_parts_mut(ptr, total) };
match self.io.sock.recv(spare) {
Ok(n) => {
unsafe { buf.set_init(n) };
return (Ok(n), buf);
}
Err(e) if would_block(&e) => {
if let Err(e) = self.io.ready(false).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), buf),
}
}
}
pub async fn read_exact<B>(&self, mut buf: B) -> BufResult<(), B>
where
B: IoBufMut + Send + 'static,
{
let total = buf.bytes_total();
let mut got = 0usize;
while got < total {
let ptr = unsafe { buf.stable_ptr_mut().add(got) } as *mut MaybeUninit<u8>;
let spare = unsafe { std::slice::from_raw_parts_mut(ptr, total - got) };
match self.io.sock.recv(spare) {
Ok(0) => {
let e =
io::Error::new(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer");
return (Err(e), buf);
}
Ok(n) => got += n,
Err(e) if would_block(&e) => {
if let Err(e) = self.io.ready(false).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), buf),
}
}
unsafe { buf.set_init(total) };
(Ok(()), buf)
}
pub async fn write<B>(&self, buf: B) -> BufResult<usize, B>
where
B: IoBuf + Send + 'static,
{
loop {
let data = unsafe { std::slice::from_raw_parts(buf.stable_ptr(), buf.bytes_init()) };
match send_nosig(&self.io.sock, data) {
Ok(n) => return (Ok(n), buf),
Err(e) if would_block(&e) => {
if let Err(e) = self.io.ready(true).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), buf),
}
}
}
pub async fn write_all<B>(&self, buf: B) -> BufResult<(), B>
where
B: IoBuf + Send + 'static,
{
let total = buf.bytes_init();
let mut sent = 0usize;
while sent < total {
let data =
unsafe { std::slice::from_raw_parts(buf.stable_ptr().add(sent), total - sent) };
match send_nosig(&self.io.sock, data) {
Ok(0) => {
let e =
io::Error::new(io::ErrorKind::WriteZero, "failed to write whole buffer");
return (Err(e), buf);
}
Ok(n) => sent += n,
Err(e) if would_block(&e) => {
if let Err(e) = self.io.ready(true).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), buf),
}
}
(Ok(()), buf)
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.io.sock.shutdown(how)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.io.sock.take_error()
}
pub fn as_raw_fd(&self) -> std::os::fd::RawFd {
self.io.sock.as_raw_fd()
}
}
pub struct UnixDatagram {
io: Sock,
}
impl UnixDatagram {
pub fn bind(path: impl AsRef<Path>) -> io::Result<Self> {
let sock = Socket::new(Domain::UNIX, Type::DGRAM, None)?;
sock.bind(&SockAddr::unix(path)?)?;
Ok(Self {
io: Sock::new(sock)?,
})
}
pub fn unbound() -> io::Result<Self> {
Ok(Self {
io: Sock::new(Socket::new(Domain::UNIX, Type::DGRAM, None)?)?,
})
}
pub fn pair() -> io::Result<(Self, Self)> {
let (a, b) = Socket::pair(Domain::UNIX, Type::DGRAM, None)?;
Ok((Self { io: Sock::new(a)? }, Self { io: Sock::new(b)? }))
}
pub fn connect(&self, path: impl AsRef<Path>) -> io::Result<()> {
self.io.sock.connect(&SockAddr::unix(path)?)
}
pub fn local_path(&self) -> io::Result<Option<PathBuf>> {
Ok(path_of(&self.io.sock.local_addr()?))
}
pub async fn send_to<B>(&self, buf: B, path: impl AsRef<Path>) -> BufResult<usize, B>
where
B: IoBuf + Send + 'static,
{
let addr = match SockAddr::unix(path) {
Ok(a) => a,
Err(e) => return (Err(e), buf),
};
loop {
let data = unsafe { std::slice::from_raw_parts(buf.stable_ptr(), buf.bytes_init()) };
match self.io.sock.send_to(data, &addr) {
Ok(n) => return (Ok(n), buf),
Err(e) if would_block(&e) => {
if let Err(e) = self.io.ready(true).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), buf),
}
}
}
pub async fn send<B>(&self, buf: B) -> BufResult<usize, B>
where
B: IoBuf + Send + 'static,
{
loop {
let data = unsafe { std::slice::from_raw_parts(buf.stable_ptr(), buf.bytes_init()) };
match self.io.sock.send(data) {
Ok(n) => return (Ok(n), buf),
Err(e) if would_block(&e) => {
if let Err(e) = self.io.ready(true).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), buf),
}
}
}
pub async fn recv_from<B>(&self, mut buf: B) -> (io::Result<(usize, Option<PathBuf>)>, B)
where
B: IoBufMut + Send + 'static,
{
loop {
let total = buf.bytes_total();
let ptr = buf.stable_ptr_mut() as *mut MaybeUninit<u8>;
let spare = unsafe { std::slice::from_raw_parts_mut(ptr, total) };
match self.io.sock.recv_from(spare) {
Ok((n, from)) => {
unsafe { buf.set_init(n) };
return (Ok((n, path_of(&from))), buf);
}
Err(e) if would_block(&e) => {
if let Err(e) = self.io.ready(false).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), buf),
}
}
}
pub async fn recv<B>(&self, buf: B) -> BufResult<usize, B>
where
B: IoBufMut + Send + 'static,
{
let (res, buf) = self.recv_from(buf).await;
(res.map(|(n, _)| n), buf)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.io.sock.take_error()
}
pub fn as_raw_fd(&self) -> std::os::fd::RawFd {
self.io.sock.as_raw_fd()
}
}