use std::io::Error as IoError;
use std::io::IoSlice;
use std::io::IoSliceMut;
use std::os::fd::AsRawFd;
use std::path::Path;
use nix::cmsg_space;
use nix::fcntl::fcntl;
use nix::fcntl::FcntlArg;
use nix::fcntl::OFlag;
use nix::sys::socket::accept;
use nix::sys::socket::bind;
use nix::sys::socket::connect;
use nix::sys::socket::listen;
use nix::sys::socket::recvmsg;
use nix::sys::socket::sendmsg;
use nix::sys::socket::socket;
use nix::sys::socket::AddressFamily;
use nix::sys::socket::Backlog;
use nix::sys::socket::ControlMessage;
use nix::sys::socket::ControlMessageOwned;
use nix::sys::socket::MsgFlags;
use nix::sys::socket::SockFlag;
use nix::sys::socket::SockType;
use nix::sys::socket::UnixAddr;
use nix::NixPath;
use crate::rutabaga_os::AsBorrowedDescriptor;
use crate::rutabaga_os::AsRawDescriptor;
use crate::rutabaga_os::FromRawDescriptor;
use crate::rutabaga_os::OwnedDescriptor;
use crate::rutabaga_os::RawDescriptor;
use crate::rutabaga_os::TubeType;
use crate::rutabaga_utils::RutabagaError;
use crate::rutabaga_utils::RutabagaResult;
const MAX_IDENTIFIERS: usize = 28;
pub struct Tube {
socket: OwnedDescriptor,
}
impl Tube {
pub fn new<P: AsRef<Path> + NixPath>(path: P, kind: TubeType) -> RutabagaResult<Tube> {
let socket_fd = match kind {
TubeType::Packet => socket(
AddressFamily::Unix,
SockType::SeqPacket,
SockFlag::empty(),
None,
)?,
TubeType::Stream => socket(
AddressFamily::Unix,
SockType::Stream,
SockFlag::SOCK_CLOEXEC,
None,
)?,
};
let unix_addr = UnixAddr::new(&path)?;
connect(socket_fd.as_raw_fd(), &unix_addr)?;
Ok(Tube {
socket: socket_fd.into(),
})
}
pub fn send(&self, opaque_data: &[u8], descriptors: &[RawDescriptor]) -> RutabagaResult<usize> {
let cmsg = ControlMessage::ScmRights(descriptors);
let bytes_sent = sendmsg::<()>(
self.socket.as_raw_descriptor(),
&[IoSlice::new(opaque_data)],
&[cmsg],
MsgFlags::empty(),
None,
)?;
Ok(bytes_sent)
}
pub fn receive(&self, opaque_data: &mut [u8]) -> RutabagaResult<(usize, Vec<OwnedDescriptor>)> {
let mut iovecs = [IoSliceMut::new(opaque_data)];
let mut cmsgspace = cmsg_space!([RawDescriptor; MAX_IDENTIFIERS]);
let flags = MsgFlags::empty();
let r = recvmsg::<()>(
self.socket.as_raw_descriptor(),
&mut iovecs,
Some(&mut cmsgspace),
flags,
)?;
let len = r.bytes;
let descriptors = match r.cmsgs().next() {
Some(ControlMessageOwned::ScmRights(fds)) => {
fds.into_iter()
.map(|fd| {
unsafe { OwnedDescriptor::from_raw_descriptor(fd) }
})
.collect()
}
Some(_) => return Err(RutabagaError::Unsupported),
None => Vec::new(),
};
Ok((len, descriptors))
}
}
impl AsBorrowedDescriptor for Tube {
fn as_borrowed_descriptor(&self) -> &OwnedDescriptor {
&self.socket
}
}
pub struct Listener {
socket: OwnedDescriptor,
}
impl Listener {
pub fn bind<P: AsRef<Path> + NixPath>(path: P) -> RutabagaResult<Listener> {
let socket = socket(
AddressFamily::Unix,
SockType::SeqPacket,
SockFlag::empty(),
None,
)?;
let unix_addr = UnixAddr::new(&path)?;
bind(socket.as_raw_fd(), &unix_addr)?;
listen(&socket, Backlog::new(128)?)?;
fcntl(socket.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?;
Ok(Listener {
socket: socket.into(),
})
}
pub fn accept(&self) -> RutabagaResult<Tube> {
let sock = match accept(self.socket.as_raw_descriptor()) {
Ok(socket) => socket,
Err(_) => return Err(IoError::last_os_error().into()),
};
let descriptor: OwnedDescriptor = unsafe { OwnedDescriptor::from_raw_descriptor(sock) };
Ok(Tube { socket: descriptor })
}
}
impl AsBorrowedDescriptor for Listener {
fn as_borrowed_descriptor(&self) -> &OwnedDescriptor {
&self.socket
}
}