use filedesc::FileDesc;
use std::os::raw::c_int;
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, OwnedFd};
use std::path::{Path, PathBuf};
use std::task::{Context, Poll};
use tokio::io::unix::AsyncFd;
use crate::{sys, UnixSeqpacket};
pub struct UnixSeqpacketListener {
io: AsyncFd<FileDesc>,
}
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 AsFd for UnixSeqpacketListener {
fn as_fd(&self) -> BorrowedFd<'_> {
self.io.get_ref().as_fd()
}
}
impl TryFrom<OwnedFd> for UnixSeqpacketListener {
type Error = std::io::Error;
fn try_from(fd: OwnedFd) -> Result<Self, Self::Error> {
Self::new(FileDesc::new(fd))
}
}
impl From<UnixSeqpacketListener> for OwnedFd {
fn from(socket: UnixSeqpacketListener) -> Self {
socket.io.into_inner().into_fd()
}
}
impl UnixSeqpacketListener {
fn new(socket: FileDesc) -> 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: c_int) -> std::io::Result<Self> {
let socket = sys::local_seqpacket_socket()?;
sys::bind(&socket, address)?;
sys::listen(&socket, backlog)?;
Self::new(socket)
}
pub unsafe fn from_raw_fd(fd: std::os::unix::io::RawFd) -> std::io::Result<Self> {
Self::new(FileDesc::from_raw_fd(fd))
}
pub fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
self.io.as_raw_fd()
}
pub fn into_raw_fd(self) -> std::os::unix::io::RawFd {
self.io.into_inner().into_raw_fd()
}
pub fn local_addr(&self) -> std::io::Result<PathBuf> {
sys::get_local_address(self.io.get_ref())
}
pub fn take_error(&self) -> std::io::Result<Option<std::io::Error>> {
sys::take_socket_error(self.io.get_ref())
}
pub fn poll_accept(&mut self, cx: &mut Context) -> Poll<std::io::Result<UnixSeqpacket>> {
let socket = loop {
let mut ready_guard = ready!(self.io.poll_read_ready(cx)?);
match ready_guard.try_io(|inner| sys::accept(inner.get_ref())) {
Ok(x) => break x?,
Err(_would_block) => continue,
}
};
Poll::Ready(Ok(UnixSeqpacket::new(socket)?))
}
pub async fn accept(&mut self) -> std::io::Result<UnixSeqpacket> {
let socket = loop {
let mut ready_guard = self.io.readable().await?;
match ready_guard.try_io(|inner| sys::accept(inner.get_ref())) {
Ok(x) => break x?,
Err(_would_block) => continue,
}
};
UnixSeqpacket::new(socket)
}
}
impl AsRawFd for UnixSeqpacketListener {
fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
self.as_raw_fd()
}
}
impl IntoRawFd for UnixSeqpacketListener {
fn into_raw_fd(self) -> std::os::unix::io::RawFd {
self.into_raw_fd()
}
}