use libc::{c_void, free, size_t};
use std::{
ffi::CString,
io::{Error, ErrorKind::Other},
net::TcpListener,
os::{
raw::{c_char, c_int},
unix::io::{FromRawFd, RawFd},
},
ptr::null_mut,
};
type FdType = RawFd;
extern "C" {
fn launch_activate_socket(name: *const c_char, fds: *mut *mut c_int, cnt: *mut size_t)
-> c_int;
}
pub fn get_activation_socket(name: &str) -> Result<TcpListener, Error> {
let fds = get_fds(name).unwrap_or_default();
match fds.get(0) {
Some(fd) => {
let listener = unsafe { TcpListener::from_raw_fd(*fd) };
Ok(listener)
}
None => Err(Error::new(
Other,
"Couln't find file descriptor from socket activation",
)),
}
}
fn get_fds(name: &str) -> Option<Vec<FdType>> {
unsafe {
let mut fds: *mut c_int = null_mut();
let mut cnt: size_t = 0;
let name = CString::new(name).expect("CString::new failed");
if launch_activate_socket(name.as_ptr(), &mut fds, &mut cnt) == 0 {
assert!(!fds.is_null());
let result = std::slice::from_raw_parts(fds, cnt).to_vec();
free(fds as *mut c_void);
Some(result)
} else {
None
}
}
}