pub use door_macros::server_procedure;
pub mod illumos;
pub mod server;
use crate::illumos::door_h::door_arg_t;
use crate::illumos::door_h::door_call;
use crate::illumos::errno_h::errno;
use crate::illumos::DoorArg;
use crate::illumos::DoorFd;
use std::fs::File;
use std::io;
use std::os::fd::FromRawFd;
use std::os::fd::IntoRawFd;
use std::os::fd::RawFd;
use std::path::Path;
#[derive(Debug, PartialEq)]
pub enum DoorCallError {
E2BIG,
EAGAIN,
EBADF,
EFAULT,
EINTR,
EINVAL,
EMFILE,
ENFILE,
ENOBUFS,
ENOTSUP,
EOVERFLOW,
}
pub struct Client(RawFd);
impl FromRawFd for Client {
unsafe fn from_raw_fd(raw: RawFd) -> Self {
Self(raw)
}
}
impl Drop for Client {
fn drop(&mut self) {
unsafe { libc::close(self.0) };
}
}
pub enum DoorArgument {
BorrowedRbuf(DoorArg),
OwnedRbuf(DoorArg),
}
impl DoorArgument {
pub fn new(
data: &[u8],
descriptors: &[DoorFd],
response: &mut [u8],
) -> Self {
Self::borrowed_rbuf(data, descriptors, response)
}
pub fn borrowed_rbuf(
data: &[u8],
descriptors: &[DoorFd],
response: &mut [u8],
) -> Self {
Self::BorrowedRbuf(DoorArg::new(data, descriptors, response))
}
pub fn owned_rbuf(
data: &[u8],
descriptors: &[DoorFd],
response: &mut [u8],
) -> Self {
Self::OwnedRbuf(DoorArg::new(data, descriptors, response))
}
fn inner(&self) -> &DoorArg {
match self {
Self::BorrowedRbuf(inner) => inner,
Self::OwnedRbuf(inner) => inner,
}
}
fn inner_mut(&mut self) -> &mut DoorArg {
match self {
Self::BorrowedRbuf(inner) => inner,
Self::OwnedRbuf(inner) => inner,
}
}
pub fn as_door_arg_t(&self) -> &door_arg_t {
self.inner().as_door_arg_t()
}
pub fn data(&self) -> &[u8] {
self.inner().data()
}
pub fn rbuf(&self) -> &[u8] {
self.inner().rbuf()
}
}
impl Drop for DoorArgument {
fn drop(&mut self) {
if let Self::OwnedRbuf(arg) = self {
arg.munmap_rbuf().unwrap()
}
}
}
impl Client {
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let file = File::open(path)?;
Ok(Self(file.into_raw_fd()))
}
pub fn call(
&self,
mut arg: DoorArgument,
) -> Result<DoorArgument, DoorCallError> {
let a = arg.inner().rbuf_addr();
let x = arg.inner_mut().as_mut_door_arg_t();
match unsafe { door_call(self.0, x) } {
0 => match (x.rbuf as u64) == a {
true => Ok(arg),
false => {
let data = unsafe {
std::slice::from_raw_parts(
x.data_ptr as *const u8,
x.data_size,
)
};
let desc = unsafe {
std::slice::from_raw_parts(
x.desc_ptr as *const DoorFd,
x.desc_num.try_into().unwrap(),
)
};
let rbuf = unsafe {
std::slice::from_raw_parts_mut(
x.rbuf as *mut u8,
x.rsize,
)
};
Ok(DoorArgument::owned_rbuf(data, desc, rbuf))
}
},
_ => Err(match errno() {
libc::E2BIG => DoorCallError::E2BIG,
libc::EAGAIN => DoorCallError::EAGAIN,
libc::EBADF => DoorCallError::EBADF,
libc::EFAULT => DoorCallError::EFAULT,
libc::EINTR => DoorCallError::EINTR,
libc::EINVAL => DoorCallError::EINVAL,
libc::EMFILE => DoorCallError::EMFILE,
libc::ENFILE => DoorCallError::ENFILE,
libc::ENOBUFS => DoorCallError::ENOBUFS,
libc::ENOTSUP => DoorCallError::ENOTSUP,
libc::EOVERFLOW => DoorCallError::EOVERFLOW,
_ => unreachable!(),
}),
}
}
pub fn call_with_data(
&self,
data: &[u8],
) -> Result<DoorArgument, DoorCallError> {
let arg = DoorArgument::new(data, &[], &mut []);
self.call(arg)
}
}