use crate::{
channel, func,
handles::{FromRawHandle, OwnedHandle, RawHandle},
Deserializer, FnOnceObject, Receiver, Sender,
};
use lazy_static::lazy_static;
use std::default::Default;
use std::mem::ManuallyDrop;
use std::sync::RwLock;
lazy_static! {
pub(crate) static ref HANDLE_BROKER: RwLock<RawHandle> = RwLock::new(Default::default());
pub(crate) static ref HANDLE_BROKER_HOLDER: RwLock<Option<Sender<()>>> = RwLock::new(None);
}
pub(crate) fn start_root() {
let (ours, theirs) = channel().expect("Failed to create holder channel for handle broker");
let broker = ManuallyDrop::new(
handle_broker
.spawn(theirs)
.expect("Failed to start handle broker"),
);
*HANDLE_BROKER
.write()
.expect("Failed to acquire write access to HANDLE_BROKER") = broker.id();
*HANDLE_BROKER_HOLDER
.write()
.expect("Failed to acquire write access to HANDLE_BROKER_HOLDER") = Some(ours);
}
#[func]
fn handle_broker(mut holder: Receiver<()>) {
holder
.recv()
.expect("Failed to receive from holder in handle broker");
std::process::exit(0);
}
pub(crate) fn crossmist_main(mut args: std::env::Args) -> ! {
let handle_broker_id: RawHandle = parse_raw_handle(
&args
.next()
.expect("Expected four CLI arguments for crossmist"),
);
let handle_broker_holder_id: RawHandle = parse_raw_handle(
&args
.next()
.expect("Expected four CLI arguments for crossmist"),
);
let handle_tx: RawHandle = parse_raw_handle(
&args
.next()
.expect("Expected four CLI arguments for crossmist"),
);
let handle_rx: RawHandle = parse_raw_handle(
&args
.next()
.expect("Expected four CLI arguments for crossmist"),
);
*HANDLE_BROKER
.write()
.expect("Failed to acquire write access to HANDLE_BROKER") = handle_broker_id;
*HANDLE_BROKER_HOLDER
.write()
.expect("Failed to acquire write access to HANDLE_BROKER_HOLDER") =
Some(unsafe { Sender::from_raw_handle(handle_broker_holder_id) });
enable_cloexec(handle_tx).expect("Failed to set O_CLOEXEC for the file descriptor");
enable_cloexec(handle_rx).expect("Failed to set O_CLOEXEC for the file descriptor");
let mut entry_rx = unsafe { Receiver::<(Vec<u8>, Vec<RawHandle>)>::from_raw_handle(handle_rx) };
let (entry_data, entry_handles) = entry_rx
.recv()
.expect("Failed to read entry for crossmist")
.expect("No entry passed");
drop(entry_rx);
for handle in &entry_handles {
enable_cloexec(*handle).expect("Failed to set O_CLOEXEC for the file descriptor");
}
let entry_handles = entry_handles
.into_iter()
.map(|handle| unsafe { OwnedHandle::from_raw_handle(handle) })
.collect();
let mut deserializer = Deserializer::new(entry_data, entry_handles);
let entry: Box<dyn FnOnceObject<(RawHandle,), Output = i32>> =
unsafe { deserializer.deserialize() }.expect("Failed to deserialize entry");
std::process::exit(entry.call_object_once((handle_tx,)))
}
fn parse_raw_handle(s: &str) -> RawHandle {
use windows::Win32::Foundation;
Foundation::HANDLE(s.parse::<isize>().expect("Failed to parse handle"))
}
pub(crate) fn disable_cloexec(handle: RawHandle) -> std::io::Result<()> {
use windows::Win32::Foundation;
unsafe {
Foundation::SetHandleInformation(
handle,
Foundation::HANDLE_FLAG_INHERIT.0,
Foundation::HANDLE_FLAG_INHERIT,
)
.ok()?
};
Ok(())
}
pub(crate) fn enable_cloexec(handle: RawHandle) -> std::io::Result<()> {
use windows::Win32::Foundation;
unsafe {
Foundation::SetHandleInformation(
handle,
Foundation::HANDLE_FLAG_INHERIT.0,
Foundation::HANDLE_FLAGS::default(),
)
.ok()?
};
Ok(())
}
pub(crate) fn is_cloexec(handle: RawHandle) -> std::io::Result<bool> {
use windows::Win32::Foundation;
let mut flags = 0u32;
unsafe { Foundation::GetHandleInformation(handle, &mut flags as *mut u32).ok()? };
Ok((flags & Foundation::HANDLE_FLAG_INHERIT.0) == 0)
}