pub mod pipe;
use core::future::poll_fn;
use core::pin::Pin;
use core::task::{Context, Poll};
use std::io;
use std::os::fd::OwnedFd;
use std::os::unix::net::{SocketAddr as UnixSocketAddr, UnixDatagram, UnixListener, UnixStream};
use std::path::Path;
use std::time::Duration;
use futures_core::Stream;
use crate::buf::owned::{IoBuf, IoBufMut};
use crate::io::source::write::{Dest, Peer};
use crate::io::source::{Addr, Kind};
use crate::io::sys::UnixAddr;
use crate::io::{Handle, Interest, IoObject, Ready, sys};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct UCred {
uid: u32,
gid: u32,
pid: Option<i32>,
}
impl UCred {
pub fn uid(&self) -> u32 {
self.uid
}
pub fn gid(&self) -> u32 {
self.gid
}
pub fn pid(&self) -> Option<i32> {
self.pid
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
fn peer_cred(fd: std::os::fd::RawFd) -> io::Result<UCred> {
let mut cred = libc::ucred {
pid: 0,
uid: 0,
gid: 0,
};
let mut len = size_of::<libc::ucred>() as libc::socklen_t;
if unsafe {
libc::getsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_PEERCRED,
core::ptr::from_mut(&mut cred).cast(),
&mut len,
)
} != 0
{
return Err(io::Error::last_os_error());
}
Ok(UCred {
uid: cred.uid,
gid: cred.gid,
pid: Some(cred.pid),
})
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn peer_cred(fd: std::os::fd::RawFd) -> io::Result<UCred> {
let (mut uid, mut gid) = (0, 0);
if unsafe { libc::getpeereid(fd, &mut uid, &mut gid) } != 0 {
return Err(io::Error::last_os_error());
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
let pid = {
let mut pid: libc::pid_t = 0;
let mut len = size_of::<libc::pid_t>() as libc::socklen_t;
let r = unsafe {
libc::getsockopt(
fd,
libc::SOL_LOCAL,
libc::LOCAL_PEERPID,
core::ptr::from_mut(&mut pid).cast(),
&mut len,
)
};
(r == 0).then_some(pid)
};
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
let pid = None;
Ok(UCred { uid, gid, pid })
}
fn unix(addr: Addr) -> io::Result<UnixSocketAddr> {
match addr {
Addr::Unix(addr) => Ok(addr.into_inner()),
Addr::Inet(_) => Err(io::Error::new(
io::ErrorKind::InvalidData,
"a Unix socket's peer has an internet address",
)),
}
}
impl Handle<UnixListener> {
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<Handle<UnixListener>> {
Handle::adopt(UnixListener::bind(path)?, Kind::UnixListener)
}
pub fn bind_addr(addr: &UnixSocketAddr) -> io::Result<Handle<UnixListener>> {
Handle::adopt(UnixListener::bind_addr(addr)?, Kind::UnixListener)
}
pub async fn accept(&self) -> io::Result<(Handle<UnixStream>, UnixSocketAddr)> {
poll_fn(|cx| self.poll_accept(cx)).await
}
fn poll_accept(
&self,
cx: &mut Context<'_>,
) -> Poll<io::Result<(Handle<UnixStream>, UnixSocketAddr)>> {
self.source().poll_accept(cx).map(|accepted| {
let (fd, addr) = accepted?;
Ok((stream(fd), unix(addr)?))
})
}
pub fn incoming(
&self,
) -> impl Stream<Item = io::Result<Handle<UnixStream>>> + Send + Unpin + '_ {
Incoming { listener: self }
}
}
fn stream(fd: OwnedFd) -> Handle<UnixStream> {
Handle::from_nonblocking(UnixStream::from(fd), Kind::Stream)
}
struct Incoming<'a> {
listener: &'a Handle<UnixListener>,
}
impl Stream for Incoming<'_> {
type Item = io::Result<Handle<UnixStream>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.listener
.poll_accept(cx)
.map(|accepted| Some(accepted.map(|(stream, _)| stream)))
}
}
const FULL_BACKLOG_PAUSE: Duration = Duration::from_millis(1);
const FULL_BACKLOG_PAUSE_MAX: Duration = Duration::from_millis(64);
pub(super) async fn connect(socket: OwnedFd, addr: &UnixAddr) -> io::Result<Handle<UnixStream>> {
let stream = Handle::from_nonblocking(UnixStream::from(socket), Kind::Stream);
let mut pause = FULL_BACKLOG_PAUSE;
loop {
match poll_fn(|cx| stream.source().poll_connect(cx, Peer::Unix(addr))).await {
Ok(()) => return Ok(stream),
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
crate::time::sleep(pause).await;
pause = (pause * 2).min(FULL_BACKLOG_PAUSE_MAX);
}
Err(err) => return Err(err),
}
}
}
impl Handle<UnixStream> {
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<Handle<UnixStream>> {
connect(
sys::socket(libc::AF_UNIX, libc::SOCK_STREAM)?,
&UnixAddr::path(path.as_ref())?,
)
.await
}
pub async fn connect_addr(addr: &UnixSocketAddr) -> io::Result<Handle<UnixStream>> {
connect(
sys::socket(libc::AF_UNIX, libc::SOCK_STREAM)?,
&UnixAddr::of(addr)?,
)
.await
}
pub fn peer_cred(&self) -> io::Result<UCred> {
peer_cred(self.raw_io())
}
pub fn pair() -> io::Result<(Handle<UnixStream>, Handle<UnixStream>)> {
let (a, b) = UnixStream::pair()?;
Ok((
Handle::adopt(a, Kind::Stream)?,
Handle::adopt(b, Kind::Stream)?,
))
}
pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
poll_fn(|cx| self.source().poll_write(cx, buf)).await
}
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
poll_fn(|cx| self.source().poll_read(cx, buf, false)).await
}
pub async fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
poll_fn(|cx| self.source().poll_read(cx, buf, true)).await
}
}
impl Handle<UnixDatagram> {
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<Handle<UnixDatagram>> {
Handle::adopt(UnixDatagram::bind(path)?, Kind::UnixDatagram)
}
pub fn bind_addr(addr: &UnixSocketAddr) -> io::Result<Handle<UnixDatagram>> {
Handle::adopt(UnixDatagram::bind_addr(addr)?, Kind::UnixDatagram)
}
pub fn unbound() -> io::Result<Handle<UnixDatagram>> {
Ok(Handle::from_nonblocking(
UnixDatagram::from(sys::socket(libc::AF_UNIX, libc::SOCK_DGRAM)?),
Kind::UnixDatagram,
))
}
pub fn pair() -> io::Result<(Handle<UnixDatagram>, Handle<UnixDatagram>)> {
let (a, b) = UnixDatagram::pair()?;
Ok((
Handle::adopt(a, Kind::UnixDatagram)?,
Handle::adopt(b, Kind::UnixDatagram)?,
))
}
pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
poll_fn(|cx| self.source().poll_send(cx, buf, Dest::Connected)).await
}
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
self.receive(buf, false).await.map(|(n, _)| n)
}
pub async fn send_owned<B>(&self, buf: B) -> (io::Result<usize>, B)
where
B: IoBuf,
{
self.source().send_owned(buf, Dest::Connected).await
}
pub async fn send_to_owned<P, B>(&self, buf: B, path: P) -> (io::Result<usize>, B)
where
P: AsRef<Path>,
B: IoBuf,
{
match UnixAddr::path(path.as_ref()) {
Ok(addr) => self.source().send_owned(buf, Dest::Unix(&addr)).await,
Err(err) => (Err(err), buf),
}
}
pub async fn recv_owned<B>(&self, buf: B) -> (io::Result<usize>, B)
where
B: IoBufMut,
{
let (result, buf) = self.recv_from_owned(buf).await;
(result.map(|(n, _)| n), buf)
}
pub async fn recv_from_owned<B>(&self, buf: B) -> (io::Result<(usize, UnixSocketAddr)>, B)
where
B: IoBufMut,
{
let (result, buf) = self.source().recv_from_owned(buf).await;
(
result.and_then(|(n, addr)| unix(addr).map(|addr| (n, addr))),
buf,
)
}
pub async fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.receive(buf, true).await.map(|(n, _)| n)
}
pub async fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
let addr = UnixAddr::path(path.as_ref())?;
poll_fn(|cx| self.source().poll_send(cx, buf, Dest::Unix(&addr))).await
}
pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, UnixSocketAddr)> {
self.receive(buf, false).await
}
pub async fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, UnixSocketAddr)> {
self.receive(buf, true).await
}
async fn receive(&self, buf: &mut [u8], peek: bool) -> io::Result<(usize, UnixSocketAddr)> {
poll_fn(|cx| self.poll_receive(cx, buf, peek)).await
}
#[inline(always)]
fn poll_receive(
&self,
cx: &mut Context<'_>,
buf: &mut [u8],
peek: bool,
) -> Poll<io::Result<(usize, UnixSocketAddr)>> {
self.source().poll_receive_as(cx, buf, peek)
}
pub async fn readable(&self) -> io::Result<()> {
self.ready(Interest::READABLE).await.map(drop)
}
pub async fn writable(&self) -> io::Result<()> {
self.ready(Interest::WRITABLE).await.map(drop)
}
pub async fn ready(&self, interest: Interest) -> io::Result<Ready> {
poll_fn(|cx| super::poll_ready(self.source(), cx, interest)).await
}
pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.source().poll_read_ready(cx).map(|r| r.map(drop))
}
pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.source().poll_write_ready(cx).map(|r| r.map(drop))
}
pub fn try_send(&self, buf: &[u8]) -> io::Result<usize> {
super::at_once(|cx| self.source().poll_send(cx, buf, Dest::Connected))
}
pub fn try_send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
let addr = UnixAddr::path(path.as_ref())?;
super::at_once(|cx| self.source().poll_send(cx, buf, Dest::Unix(&addr)))
}
pub fn try_recv(&self, buf: &mut [u8]) -> io::Result<usize> {
super::at_once(|cx| self.poll_receive(cx, buf, false)).map(|(n, _)| n)
}
pub fn try_recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, UnixSocketAddr)> {
super::at_once(|cx| self.poll_receive(cx, buf, false))
}
}