use crate::illumos::door_h::{
door_call,
door_create,
door_arg_t,
DOOR_REFUSE_DESC,
door_desc_t,
door_return,
};
use crate::illumos::stropts_h::{ fattach, fdetach };
use crate::illumos::errno;
use libc;
use std::ffi;
use std::ptr;
use std::slice;
pub struct ClientRef {
door_descriptor: libc::c_int
}
impl ClientRef {
pub fn call(&self, request: &[u8]) -> Result<Vec<u8>,Error> {
let mut response = Vec::with_capacity(1024);
let mut arg = door_arg_t {
data_ptr: request.as_ptr() as *const i8,
data_size: request.len(),
desc_ptr: ptr::null(),
desc_num: 0,
rbuf: response.as_mut_ptr() as *const i8,
rsize: response.len()
};
if unsafe{ door_call(self.door_descriptor, &mut arg) } == -1 {
return Err(Error::DoorCall(errno()));
}
unsafe{ response.set_len(arg.data_size); }
let slice = unsafe{ std::slice::from_raw_parts(arg.data_ptr as *const u8, arg.data_size) };
Ok(slice.to_vec())
}
}
pub struct Client {
door_descriptor: libc::c_int
}
impl Client {
pub fn new(path: &str) -> Result<Self,Error> {
let path = ffi::CString::new(path)?;
match unsafe{ libc::open(path.as_ptr(), libc::O_RDONLY) } {
-1 => return Err(Error::OpenDoor(errno())),
door_descriptor => Ok(Self{ door_descriptor })
}
}
pub fn call(&self, request: &[u8]) -> Result<Vec<u8>,Error> {
let cr = self.borrow();
cr.call(request)
}
pub fn borrow(&self) -> ClientRef {
ClientRef{ door_descriptor: self.door_descriptor }
}
}
impl Drop for Client {
fn drop(&mut self) {
unsafe{ libc::close(self.door_descriptor); }
}
}
pub struct Server {
jamb_path: ffi::CString,
door_descriptor: libc::c_int
}
#[derive(Debug)]
pub enum Error {
InvalidPath(ffi::NulError),
InstallJamb(libc::c_int),
AttachDoor(libc::c_int),
OpenDoor(libc::c_int),
DoorCall(libc::c_int),
CreateDoor(libc::c_int),
}
impl From<ffi::NulError> for Error {
fn from(other: ffi::NulError) -> Self {
Self::InvalidPath(other)
}
}
impl Drop for Server {
fn drop(&mut self) {
unsafe{ fdetach(self.jamb_path.as_ptr()); }
unsafe{ libc::unlink(self.jamb_path.as_ptr()); }
unsafe{ libc::close(self.door_descriptor); }
}
}
pub trait ServerProcedure {
fn rust_wrapper(request: &[u8]) -> Vec<u8>;
extern "C" fn c_wrapper(
_cookie: *const libc::c_void,
argp: *const libc::c_char,
arg_size: libc::size_t,
_dp: *const door_desc_t,
_n_desc: libc::c_uint
) {
let request = unsafe{ slice::from_raw_parts(argp as *const u8, arg_size) };
let response = Self::rust_wrapper(request);
let data_ptr = response.as_ptr();
let data_size = response.len();
unsafe{ door_return(data_ptr as *const libc::c_char, data_size, ptr::null(), 0); }
}
fn install(path: &str) -> Result<Server,Error> {
let jamb_path = ffi::CString::new(path)?;
let door_descriptor = unsafe{ door_create(Self::c_wrapper, ptr::null(), DOOR_REFUSE_DESC) };
if door_descriptor == -1 {
return Err(Error::CreateDoor(errno()));
}
let create_new = libc::O_RDWR | libc::O_CREAT | libc::O_EXCL;
match unsafe{ libc::open(jamb_path.as_ptr(), create_new, 0400) } {
-1 => {
unsafe{ libc::close(door_descriptor) };
return Err(Error::InstallJamb(errno()))
},
jamb_descriptor => unsafe{ libc::close(jamb_descriptor); }
}
match unsafe{ fattach(door_descriptor, jamb_path.as_ptr()) } {
-1 => {
unsafe{ libc::close(door_descriptor) };
unsafe{ libc::unlink(jamb_path.as_ptr()); }
Err(Error::AttachDoor(errno()))
},
_ => Ok(Server{ jamb_path, door_descriptor })
}
}
}
#[macro_export]
macro_rules! derive_server_procedure {
($function_name:ident as $type_name:ident) => {
use portunusd::door::ServerProcedure;
struct $type_name;
impl ServerProcedure for $type_name {
fn rust_wrapper(request: &[u8]) -> Vec<u8> {
$function_name(request)
}
}
}
}