use rusl::platform::{
AddressFamily, NonNegativeI32, SocketAddressUnix, SocketFlags, SocketOptions, SocketType,
};
use rusl::string::unix_str::UnixStr;
use crate::error::Result;
use crate::io::{Read, Write};
use crate::unix::fd::{AsRawFd, OwnedFd, RawFd};
#[cfg(test)]
mod test;
#[derive(Debug)]
pub struct UnixStream(OwnedFd);
impl UnixStream {
pub fn connect(path: &UnixStr, blocking: bool) -> Result<Self> {
let block = blocking
.then(SocketFlags::empty)
.unwrap_or(SocketFlags::SOCK_NONBLOCK);
let fd = rusl::network::socket(
AddressFamily::AF_UNIX,
SocketOptions::new(SocketType::SOCK_STREAM, block),
0,
)?;
let addr = SocketAddressUnix::try_from_unix(path)?;
rusl::network::connect_unix(fd, &addr)?;
Ok(Self(OwnedFd(fd)))
}
}
impl AsRawFd for UnixStream {
fn as_raw_fd(&self) -> RawFd {
self.0 .0
}
}
impl Read for UnixStream {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
Ok(rusl::unistd::read(self.0 .0, buf)?)
}
}
impl Write for UnixStream {
#[inline]
fn write(&mut self, buf: &[u8]) -> Result<usize> {
Ok(rusl::unistd::write(self.0 .0, buf)?)
}
#[inline]
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
pub struct UnixListener(OwnedFd);
impl UnixListener {
pub fn bind(path: &UnixStr, blocking: bool) -> Result<Self> {
let block = blocking
.then(SocketFlags::empty)
.unwrap_or(SocketFlags::SOCK_NONBLOCK);
let fd = rusl::network::socket(
AddressFamily::AF_UNIX,
SocketOptions::new(SocketType::SOCK_STREAM, block),
0,
)?;
let addr = SocketAddressUnix::try_from_unix(path)?;
rusl::network::bind_unix(fd, &addr)?;
rusl::network::listen(fd, NonNegativeI32::MAX)?;
Ok(Self(OwnedFd(fd)))
}
pub fn accept(&self, blocking: bool) -> Result<UnixStream> {
let block = blocking
.then(SocketFlags::empty)
.unwrap_or(SocketFlags::SOCK_NONBLOCK);
let client = rusl::network::accept_unix(self.0 .0, SocketFlags::SOCK_CLOEXEC | block)?.0;
Ok(UnixStream(OwnedFd(client)))
}
}