use std::io;
use std::mem::ManuallyDrop;
use std::net::Shutdown;
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::os::unix::net::{SocketAddr, UnixStream as StdStream};
use std::path::Path;
use socket2::{Domain, SockAddr, Socket, Type};
use super::{ListenSocket, StreamSocket};
use crate::buf::{IoBuf, IoBufMut, RecvBuf};
fn with_std<T>(sock: &Socket, f: impl FnOnce(&StdStream) -> io::Result<T>) -> io::Result<T> {
let std = ManuallyDrop::new(unsafe { StdStream::from_raw_fd(sock.as_raw_fd()) });
f(&std)
}
fn new_socket() -> io::Result<Socket> {
Socket::new(Domain::UNIX, Type::STREAM, None)
}
pub struct UnixListener {
inner: ListenSocket,
}
impl UnixListener {
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let sock = new_socket()?;
sock.bind(&SockAddr::unix(path)?)?;
sock.listen(4096)?;
Ok(Self {
inner: ListenSocket::new(sock),
})
}
pub fn from_std(listener: std::os::unix::net::UnixListener) -> Self {
let sock = unsafe { Socket::from_raw_fd(listener.into_raw_fd()) };
Self {
inner: ListenSocket::new(sock),
}
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
with_std(self.inner.socket(), StdStream::local_addr)
}
pub async fn accept(&self) -> io::Result<UnixStream> {
let inner = self.inner.accept().await?;
Ok(UnixStream { inner })
}
}
impl AsRawFd for UnixListener {
fn as_raw_fd(&self) -> RawFd {
self.inner.socket().as_raw_fd()
}
}
impl std::fmt::Debug for UnixListener {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UnixListener")
.field("fd", &self.as_raw_fd())
.finish()
}
}
pub struct UnixStream {
inner: StreamSocket,
}
impl UnixStream {
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let addr = SockAddr::unix(path)?;
let inner = StreamSocket::connect(new_socket()?, addr).await?;
Ok(Self { inner })
}
pub fn pair() -> io::Result<(Self, Self)> {
let (a, b) = Socket::pair(Domain::UNIX, Type::STREAM, None)?;
let wrap = |sock| Self {
inner: StreamSocket::new(sock),
};
Ok((wrap(a), wrap(b)))
}
pub fn from_std(stream: std::os::unix::net::UnixStream) -> Self {
let sock = unsafe { Socket::from_raw_fd(stream.into_raw_fd()) };
Self {
inner: StreamSocket::new(sock),
}
}
pub async fn recv(&self) -> io::Result<RecvBuf> {
self.inner.recv().await
}
pub async fn read<B: IoBufMut>(&self, buf: B) -> (io::Result<usize>, B) {
self.inner.read(buf).await
}
pub async fn write<B: IoBuf>(&self, buf: B) -> (io::Result<usize>, B) {
self.inner.write(buf).await
}
pub async fn write_all<B: IoBuf>(&self, buf: B) -> (io::Result<()>, B) {
self.inner.write_all(buf).await
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.inner.socket().shutdown(how)
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
with_std(self.inner.socket(), StdStream::peer_addr)
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
with_std(self.inner.socket(), StdStream::local_addr)
}
}
impl AsRawFd for UnixStream {
fn as_raw_fd(&self) -> RawFd {
self.inner.socket().as_raw_fd()
}
}
impl std::fmt::Debug for UnixStream {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UnixStream")
.field("fd", &self.as_raw_fd())
.finish()
}
}