use std::os::unix::io::AsRawFd;
use std::path::{Path, PathBuf};
use std::task::{Context, Poll};
use tokio::io::unix::AsyncFd;
use crate::UnixSeqpacket;
pub struct UnixSeqpacketListener {
io: AsyncFd<socket2::Socket>,
}
impl std::fmt::Debug for UnixSeqpacketListener {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("UnixSeqpacketListener")
.field("fd", &self.io.get_ref().as_raw_fd())
.finish()
}
}
impl UnixSeqpacketListener {
fn new(socket: socket2::Socket) -> std::io::Result<Self> {
let io = AsyncFd::new(socket)?;
Ok(Self { io })
}
pub fn bind<P: AsRef<Path>>(address: P) -> std::io::Result<Self> {
Self::bind_with_backlog(address, 128)
}
pub fn bind_with_backlog<P: AsRef<Path>>(address: P, backlog: std::os::raw::c_int) -> std::io::Result<Self> {
let address = socket2::SockAddr::unix(address)?;
let socket = socket2::Socket::new(socket2::Domain::unix(), crate::socket_type(), None)?;
socket.bind(&address)?;
socket.listen(backlog)?;
Self::new(socket)
}
pub fn local_addr(&self) -> std::io::Result<PathBuf> {
let addr = self.io.get_ref().local_addr()?;
Ok(crate::address_path(&addr)?.into())
}
pub fn take_error(&self) -> std::io::Result<Option<std::io::Error>> {
self.io.get_ref().take_error()
}
pub fn poll_accept(&mut self, cx: &mut Context) -> Poll<std::io::Result<UnixSeqpacket>> {
let (socket, _addr) = loop {
let mut ready_guard = ready!(self.io.poll_read_ready(cx)?);
match ready_guard.try_io(|inner| inner.get_ref().accept()) {
Ok(x) => break x?,
Err(_would_block) => continue,
}
};
socket.set_nonblocking(true)?;
Poll::Ready(Ok(UnixSeqpacket::new(socket)?))
}
pub async fn accept(&mut self) -> std::io::Result<UnixSeqpacket> {
let (socket, _addr) = loop {
let mut ready_guard = self.io.readable().await?;
match ready_guard.try_io(|inner| inner.get_ref().accept()) {
Ok(x) => break x?,
Err(_would_block) => continue,
}
};
socket.set_nonblocking(true)?;
Ok(UnixSeqpacket::new(socket)?)
}
}