use std::io::{self, ErrorKind, IoSlice, IoSliceMut};
use std::mem;
use std::net::Shutdown;
use std::os::unix::io::{RawFd, FromRawFd, AsRawFd, IntoRawFd};
use std::path::Path;
use std::time::Duration;
use libc::{SOCK_SEQPACKET, MSG_EOR, MSG_PEEK, c_void, close, send, recv};
#[cfg(feature = "mio_08")]
use mio_08::{event::Source as Source_08, unix::SourceFd as SourceFd_08, Interest as Interest_08, Registry as Registry_08, Token as Token_08};
use crate::addr::*;
use crate::helpers::*;
use crate::ancillary::*;
use crate::credentials::*;
macro_rules! impl_rawfd_traits {($type:tt) => {
impl FromRawFd for $type {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
$type { fd }
}
}
impl AsRawFd for $type {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl IntoRawFd for $type {
fn into_raw_fd(self) -> RawFd {
let fd = self.fd;
mem::forget(self);
fd
}
}
impl Drop for $type {
fn drop(&mut self) {
let _ = unsafe { close(self.fd) };
}
}
}}
macro_rules! impl_mio_if_enabled {($type:tt) => {
#[cfg(feature = "mio_08")]
impl Source_08 for $type {
fn register(&mut self, registry: &Registry_08, token: Token_08, interest: Interest_08)
-> Result<(), io::Error> {
SourceFd_08(&self.fd).register(registry, token, interest)
}
fn reregister(&mut self, registry: &Registry_08, token: Token_08, interest: Interest_08)
-> Result<(), io::Error> {
SourceFd_08(&self.fd).reregister(registry, token, interest)
}
fn deregister(&mut self, registry: &Registry_08) -> Result<(), io::Error> {
SourceFd_08(&self.fd).deregister(registry)
}
}
#[cfg(feature = "mio_08")]
impl<'a> Source_08 for &'a $type {
fn register(&mut self, registry: &Registry_08, token: Token_08, interest: Interest_08)
-> Result<(), io::Error> {
SourceFd_08(&self.fd).register(registry, token, interest)
}
fn reregister(&mut self, registry: &Registry_08, token: Token_08, interest: Interest_08)
-> Result<(), io::Error> {
SourceFd_08(&self.fd).reregister(registry, token, interest)
}
fn deregister(&mut self, registry: &Registry_08) -> Result<(), io::Error> {
SourceFd_08(&self.fd).deregister(registry)
}
}
}}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
#[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
#[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
#[derive(Debug)]
#[repr(transparent)]
pub struct UnixSeqpacketConn {
fd: RawFd,
}
impl_rawfd_traits!{UnixSeqpacketConn}
impl UnixSeqpacketConn {
pub fn connect<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
let addr = UnixSocketAddr::from_path(&path)?;
Self::connect_unix_addr(&addr)
}
pub fn connect_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> {
let socket = Socket::new(SOCK_SEQPACKET, false)?;
set_unix_addr(socket.as_raw_fd(), SetAddr::PEER, addr)?;
Ok(UnixSeqpacketConn { fd: socket.into_raw_fd() })
}
pub fn connect_from_to_unix_addr(from: &UnixSocketAddr, to: &UnixSocketAddr)
-> Result<Self, io::Error> {
let socket = Socket::new(SOCK_SEQPACKET, false)?;
set_unix_addr(socket.as_raw_fd(), SetAddr::LOCAL, from)?;
set_unix_addr(socket.as_raw_fd(), SetAddr::PEER, to)?;
Ok(UnixSeqpacketConn { fd: socket.into_raw_fd() })
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn pair() -> Result<(Self, Self), io::Error> {
let (a, b) = Socket::pair(SOCK_SEQPACKET, false)?;
let a = UnixSeqpacketConn { fd: a.into_raw_fd() };
let b = UnixSeqpacketConn { fd: b.into_raw_fd() };
Ok((a, b))
}
pub fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> {
get_unix_addr(self.fd, GetAddr::LOCAL)
}
pub fn peer_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> {
get_unix_addr(self.fd, GetAddr::PEER)
}
pub fn initial_peer_credentials(&self) -> Result<ConnCredentials, io::Error> {
peer_credentials(self.fd)
}
pub fn initial_peer_selinux_context(&self, buf: &mut[u8]) -> Result<usize, io::Error> {
selinux_context(self.as_raw_fd(), buf)
}
pub fn send(&self, packet: &[u8]) -> Result<usize, io::Error> {
let ptr = packet.as_ptr() as *const c_void;
let flags = MSG_NOSIGNAL | MSG_EOR;
let sent = cvt_r!(unsafe { send(self.fd, ptr, packet.len(), flags) })?;
Ok(sent as usize)
}
pub fn recv(&self, buffer: &mut[u8]) -> Result<usize, io::Error> {
let ptr = buffer.as_ptr() as *mut c_void;
let received = cvt_r!(unsafe { recv(self.fd, ptr, buffer.len(), MSG_NOSIGNAL) })?;
Ok(received as usize)
}
pub fn send_vectored(&self, slices: &[IoSlice])
-> Result<usize, io::Error> {
send_ancillary(self.as_raw_fd(), None, MSG_EOR, slices, &[], None)
}
pub fn recv_vectored(&self, buffers: &mut[IoSliceMut])
-> Result<(usize, bool), io::Error> {
recv_ancillary(self.fd, None, 0, buffers, &mut[])
.map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
}
pub fn send_fds(&self, bytes: &[u8], fds: &[RawFd])
-> Result<usize, io::Error> {
send_ancillary(self.fd, None, MSG_EOR, &[IoSlice::new(bytes)], fds, None)
}
pub fn recv_fds(&self, byte_buffer: &mut[u8], fd_buffer: &mut[RawFd])
-> Result<(usize, bool, usize), io::Error> {
recv_fds(self.fd, None, &mut[IoSliceMut::new(byte_buffer)], fd_buffer)
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn peek(&self, buffer: &mut[u8]) -> Result<usize, io::Error> {
let ptr = buffer.as_ptr() as *mut c_void;
let flags = MSG_NOSIGNAL | MSG_PEEK;
let received = cvt_r!(unsafe { recv(self.fd, ptr, buffer.len(), flags) })?;
Ok(received as usize)
}
pub fn peek_vectored(&self, buffers: &mut[IoSliceMut])
-> Result<(usize, bool), io::Error> {
recv_ancillary(self.fd, None, MSG_PEEK, buffers, &mut[])
.map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn take_error(&self) -> Result<Option<io::Error>, io::Error> {
take_error(self.fd)
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn try_clone(&self) -> Result<Self, io::Error> {
let cloned = Socket::try_clone_from(self.fd)?;
Ok(UnixSeqpacketConn { fd: cloned.into_raw_fd() })
}
#[cfg_attr(not(any(target_vendor="apple", target_os="illumos", target_os="solaris")), doc="```")]
#[cfg_attr(any(target_vendor="apple", target_os="illumos", target_os="solaris"), doc="```no_run")]
pub fn set_read_timeout(&self, timeout: Option<Duration>)
-> Result<(), io::Error> {
set_timeout(self.fd, TimeoutDirection::READ, timeout)
}
#[cfg_attr(not(any(target_vendor="apple", target_os="illumos", target_os="solaris")), doc="```")]
#[cfg_attr(any(target_vendor="apple", target_os="illumos", target_os="solaris"), doc="```no_run")]
pub fn read_timeout(&self) -> Result<Option<Duration>, io::Error> {
get_timeout(self.fd, TimeoutDirection::READ)
}
#[cfg_attr(not(any(target_vendor="apple", target_os="illumos", target_os="solaris")), doc="```")]
#[cfg_attr(any(target_vendor="apple", target_os="illumos", target_os="solaris"), doc="```no_run")]
pub fn set_write_timeout(&self, timeout: Option<Duration>)
-> Result<(), io::Error> {
set_timeout(self.fd, TimeoutDirection::WRITE, timeout)
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn write_timeout(&self) -> Result<Option<Duration>, io::Error> {
get_timeout(self.fd, TimeoutDirection::WRITE)
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn set_nonblocking(&self, nonblocking: bool) -> Result<(), io::Error> {
set_nonblocking(self.fd, nonblocking)
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
let how = match how {
Shutdown::Read => libc::SHUT_RD,
Shutdown::Write => libc::SHUT_WR,
Shutdown::Both => libc::SHUT_RDWR,
};
unsafe { cvt!(libc::shutdown(self.as_raw_fd(), how)) }?;
Ok(())
}
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
#[derive(Debug)]
#[repr(transparent)]
pub struct UnixSeqpacketListener {
fd: RawFd
}
impl_rawfd_traits!{UnixSeqpacketListener}
impl UnixSeqpacketListener {
pub fn bind<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
let addr = UnixSocketAddr::from_path(path.as_ref())?;
Self::bind_unix_addr(&addr)
}
pub fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> {
let socket = Socket::new(SOCK_SEQPACKET, false)?;
set_unix_addr(socket.as_raw_fd(), SetAddr::LOCAL, addr)?;
socket.start_listening()?;
Ok(UnixSeqpacketListener { fd: socket.into_raw_fd() })
}
pub fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> {
get_unix_addr(self.fd, GetAddr::LOCAL)
}
pub fn accept_unix_addr(&self)
-> Result<(UnixSeqpacketConn, UnixSocketAddr), io::Error> {
let (socket, addr) = Socket::accept_from(self.fd, false)?;
let conn = UnixSeqpacketConn { fd: socket.into_raw_fd() };
Ok((conn, addr))
}
pub fn take_error(&self) -> Result<Option<io::Error>, io::Error> {
take_error(self.fd)
}
pub fn try_clone(&self) -> Result<Self, io::Error> {
let cloned = Socket::try_clone_from(self.fd)?;
Ok(UnixSeqpacketListener { fd: cloned.into_raw_fd() })
}
#[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
#[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
pub fn set_timeout(&self, timeout: Option<Duration>)
-> Result<(), io::Error> {
match set_timeout(self.fd, TimeoutDirection::READ, timeout) {
#[cfg(any(
target_vendor="apple", target_os="freebsd",
target_os="netbsd",
target_os="illumos", target_os="solaris",
))]
Ok(()) if timeout.is_some() => Err(io::Error::new(
ErrorKind::InvalidInput,
"listener timeouts are not supported on this OS"
)),
result => result
}
}
#[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
#[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
pub fn timeout(&self) -> Result<Option<Duration>, io::Error> {
get_timeout(self.fd, TimeoutDirection::READ)
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn set_nonblocking(&self, nonblocking: bool) -> Result<(), io::Error> {
set_nonblocking(self.fd, nonblocking)
}
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
#[cfg_attr(all(feature="mio_08", not(target_vendor="apple")), doc="```")]
#[cfg_attr(all(feature="mio_08", target_vendor="apple"), doc="```no_run")]
#[cfg_attr(not(feature="mio_08"), doc="```no_compile")]
#[derive(Debug)]
#[repr(transparent)]
pub struct NonblockingUnixSeqpacketConn {
fd: RawFd,
}
impl_rawfd_traits!{NonblockingUnixSeqpacketConn}
impl_mio_if_enabled!{NonblockingUnixSeqpacketConn}
impl NonblockingUnixSeqpacketConn {
pub fn connect<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
let addr = UnixSocketAddr::from_path(&path)?;
Self::connect_unix_addr(&addr)
}
pub fn connect_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> {
let socket = Socket::new(SOCK_SEQPACKET, true)?;
set_unix_addr(socket.as_raw_fd(), SetAddr::PEER, addr)?;
Ok(NonblockingUnixSeqpacketConn { fd: socket.into_raw_fd() })
}
pub fn connect_from_to_unix_addr(from: &UnixSocketAddr, to: &UnixSocketAddr)
-> Result<Self, io::Error> {
let socket = Socket::new(SOCK_SEQPACKET, true)?;
set_unix_addr(socket.as_raw_fd(), SetAddr::LOCAL, from)?;
set_unix_addr(socket.as_raw_fd(), SetAddr::PEER, to)?;
Ok(NonblockingUnixSeqpacketConn { fd: socket.into_raw_fd() })
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn pair() -> Result<(Self, Self), io::Error> {
let (a, b) = Socket::pair(SOCK_SEQPACKET, true)?;
let a = NonblockingUnixSeqpacketConn { fd: a.into_raw_fd() };
let b = NonblockingUnixSeqpacketConn { fd: b.into_raw_fd() };
Ok((a, b))
}
pub fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> {
get_unix_addr(self.fd, GetAddr::LOCAL)
}
pub fn peer_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> {
get_unix_addr(self.fd, GetAddr::PEER)
}
pub fn initial_peer_credentials(&self) -> Result<ConnCredentials, io::Error> {
peer_credentials(self.fd)
}
pub fn initial_peer_selinux_context(&self, buf: &mut[u8]) -> Result<usize, io::Error> {
selinux_context(self.as_raw_fd(), buf)
}
pub fn send(&self, packet: &[u8]) -> Result<usize, io::Error> {
let ptr = packet.as_ptr() as *const c_void;
let flags = MSG_NOSIGNAL | MSG_EOR;
let sent = cvt_r!(unsafe { send(self.fd, ptr, packet.len(), flags) })?;
Ok(sent as usize)
}
pub fn recv(&self, buffer: &mut[u8]) -> Result<usize, io::Error> {
let ptr = buffer.as_ptr() as *mut c_void;
let received = cvt_r!(unsafe { recv(self.fd, ptr, buffer.len(), MSG_NOSIGNAL) })?;
Ok(received as usize)
}
pub fn send_vectored(&self, slices: &[IoSlice])
-> Result<usize, io::Error> {
send_ancillary(self.as_raw_fd(), None, MSG_EOR, slices, &[], None)
}
pub fn recv_vectored(&self, buffers: &mut[IoSliceMut])
-> Result<(usize, bool), io::Error> {
recv_ancillary(self.fd, None, 0, buffers, &mut[])
.map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
}
pub fn send_fds(&self, bytes: &[u8], fds: &[RawFd])
-> Result<usize, io::Error> {
send_ancillary(self.fd, None, MSG_EOR, &[IoSlice::new(bytes)], fds, None)
}
pub fn recv_fds(&self, byte_buffer: &mut[u8], fd_buffer: &mut[RawFd])
-> Result<(usize, bool, usize), io::Error> {
recv_fds(self.fd, None, &mut[IoSliceMut::new(byte_buffer)], fd_buffer)
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn peek(&self, buffer: &mut[u8]) -> Result<usize, io::Error> {
let ptr = buffer.as_ptr() as *mut c_void;
let flags = MSG_NOSIGNAL | MSG_PEEK;
let received = cvt_r!(unsafe { recv(self.fd, ptr, buffer.len(), flags) })?;
Ok(received as usize)
}
pub fn peek_vectored(&self, buffers: &mut[IoSliceMut])
-> Result<(usize, bool), io::Error> {
recv_ancillary(self.fd, None, MSG_PEEK, buffers, &mut[])
.map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn take_error(&self) -> Result<Option<io::Error>, io::Error> {
take_error(self.fd)
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn try_clone(&self) -> Result<Self, io::Error> {
let cloned = Socket::try_clone_from(self.fd)?;
Ok(NonblockingUnixSeqpacketConn { fd: cloned.into_raw_fd() })
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
let how = match how {
Shutdown::Read => libc::SHUT_RD,
Shutdown::Write => libc::SHUT_WR,
Shutdown::Both => libc::SHUT_RDWR,
};
unsafe { cvt!(libc::shutdown(self.as_raw_fd(), how)) }?;
Ok(())
}
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
#[cfg_attr(all(feature="mio_08", not(target_vendor="apple")), doc="```")]
#[cfg_attr(all(feature="mio_08", target_vendor="apple"), doc="```no_run")]
#[cfg_attr(not(feature="mio_08"), doc="```no_compile")]
#[derive(Debug)]
#[repr(transparent)]
pub struct NonblockingUnixSeqpacketListener {
fd: RawFd
}
impl_rawfd_traits!{NonblockingUnixSeqpacketListener}
impl_mio_if_enabled!{NonblockingUnixSeqpacketListener}
impl NonblockingUnixSeqpacketListener {
pub fn bind<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
let addr = UnixSocketAddr::from_path(&path)?;
Self::bind_unix_addr(&addr)
}
pub fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> {
let socket = Socket::new(SOCK_SEQPACKET, true)?;
set_unix_addr(socket.as_raw_fd(), SetAddr::LOCAL, addr)?;
socket.start_listening()?;
Ok(NonblockingUnixSeqpacketListener { fd: socket.into_raw_fd() })
}
pub fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> {
get_unix_addr(self.fd, GetAddr::LOCAL)
}
#[cfg_attr(not(target_vendor="apple"), doc="```")]
#[cfg_attr(target_vendor="apple", doc="```no_run")]
pub fn accept_unix_addr(&self)
-> Result<(NonblockingUnixSeqpacketConn, UnixSocketAddr), io::Error> {
let (socket, addr) = Socket::accept_from(self.fd, true)?;
let conn = NonblockingUnixSeqpacketConn { fd: socket.into_raw_fd() };
Ok((conn, addr))
}
#[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
#[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
pub fn take_error(&self) -> Result<Option<io::Error>, io::Error> {
take_error(self.fd)
}
pub fn try_clone(&self) -> Result<Self, io::Error> {
let cloned = Socket::try_clone_from(self.fd)?;
Ok(NonblockingUnixSeqpacketListener { fd: cloned.into_raw_fd() })
}
}