#![allow(dead_code)]
#[cfg(uds_supported)]
use super::c_wrappers;
use super::{
imports::*,
util::{check_ancillary_unsound, mk_msghdr_r, mk_msghdr_w},
AncillaryData, AncillaryDataBuf, EncodedAncillaryData, ToUdSocketPath, UdSocketPath,
};
use std::{
fmt::{self, Debug, Formatter},
io::{self, IoSlice, IoSliceMut, Read, Write},
iter,
net::Shutdown,
};
use to_method::To;
pub struct UdStream {
fd: FdOps,
}
impl UdStream {
pub fn connect<'a>(path: impl ToUdSocketPath<'a>) -> io::Result<Self> {
Self::_connect(path.to_socket_path()?, false)
}
pub(crate) fn connect_nonblocking<'a>(path: impl ToUdSocketPath<'a>) -> io::Result<Self> {
Self::_connect(path.to_socket_path()?, true)
}
fn _connect(path: UdSocketPath<'_>, nonblocking: bool) -> io::Result<Self> {
let addr = path.try_to::<sockaddr_un>()?;
let fd = c_wrappers::create_uds(SOCK_STREAM, nonblocking)?;
unsafe {
c_wrappers::connect(&fd, &addr)?;
}
c_wrappers::set_passcred(&fd, true)?;
Ok(Self { fd })
}
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
self.fd.read(buf)
}
pub fn recv_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.fd.read_vectored(bufs)
}
pub fn recv_ancillary<'a: 'b, 'b>(
&self,
buf: &mut [u8],
abuf: &'b mut AncillaryDataBuf<'a>,
) -> io::Result<(usize, usize)> {
check_ancillary_unsound()?;
self.recv_ancillary_vectored(&mut [IoSliceMut::new(buf)], abuf)
}
#[allow(clippy::useless_conversion)]
pub fn recv_ancillary_vectored<'a: 'b, 'b>(
&self,
bufs: &mut [IoSliceMut<'_>],
abuf: &'b mut AncillaryDataBuf<'a>,
) -> io::Result<(usize, usize)> {
check_ancillary_unsound()?;
let mut hdr = mk_msghdr_r(bufs, abuf.as_mut())?;
let (success, bytes_read) = unsafe {
let result = libc::recvmsg(self.as_raw_fd(), &mut hdr as *mut _, 0);
(result != -1, result as usize)
};
if success {
Ok((bytes_read, hdr.msg_controllen as _))
} else {
Err(io::Error::last_os_error())
}
}
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
self.fd.write(buf)
}
pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.fd.write_vectored(bufs)
}
pub fn send_ancillary<'a>(
&self,
buf: &[u8],
ancillary_data: impl IntoIterator<Item = AncillaryData<'a>>,
) -> io::Result<(usize, usize)> {
check_ancillary_unsound()?;
self.send_ancillary_vectored(&[IoSlice::new(buf)], ancillary_data)
}
#[allow(clippy::useless_conversion)]
pub fn send_ancillary_vectored<'a>(
&self,
bufs: &[IoSlice<'_>],
ancillary_data: impl IntoIterator<Item = AncillaryData<'a>>,
) -> io::Result<(usize, usize)> {
check_ancillary_unsound()?;
let abuf = ancillary_data
.into_iter()
.collect::<EncodedAncillaryData<'_>>();
let hdr = mk_msghdr_w(bufs, abuf.as_ref())?;
let (success, bytes_written) = unsafe {
let result = libc::sendmsg(self.as_raw_fd(), &hdr as *const _, 0);
(result != -1, result as usize)
};
if success {
Ok((bytes_written, hdr.msg_controllen as _))
} else {
Err(io::Error::last_os_error())
}
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
c_wrappers::shutdown(&self.fd, how)
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
c_wrappers::set_nonblocking(&self.fd, nonblocking)
}
pub fn is_nonblocking(&self) -> io::Result<bool> {
c_wrappers::get_nonblocking(&self.fd)
}
#[cfg(any(doc, uds_peercred))]
#[cfg_attr( // uds_peercred template
feature = "doc_cfg",
doc(cfg(any(
all(
target_os = "linux",
any(
target_env = "gnu",
target_env = "musl",
target_env = "musleabi",
target_env = "musleabihf"
)
),
target_os = "emscripten",
target_os = "redox",
target_os = "haiku"
)))
)]
pub fn get_peer_credentials(&self) -> io::Result<ucred> {
c_wrappers::get_peer_ucred(&self.fd)
}
}
impl Read for UdStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.fd.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut abuf = AncillaryDataBuf::Owned(Vec::new());
self.recv_ancillary_vectored(bufs, &mut abuf).map(|x| x.0)
}
}
impl Write for UdStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.fd.write(buf)
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.send_ancillary_vectored(bufs, iter::empty())
.map(|x| x.0)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Debug for UdStream {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("UdStream")
.field("fd", &self.as_raw_fd())
.finish()
}
}
impl AsRawFd for UdStream {
#[cfg(unix)]
fn as_raw_fd(&self) -> c_int {
self.fd.as_raw_fd()
}
}
impl IntoRawFd for UdStream {
#[cfg(unix)]
fn into_raw_fd(self) -> c_int {
self.fd.into_raw_fd()
}
}
impl FromRawFd for UdStream {
#[cfg(unix)]
unsafe fn from_raw_fd(fd: c_int) -> Self {
Self { fd: FdOps::new(fd) }
}
}