use std::{
io::{self, Error, ErrorKind},
mem,
};
use crate::Id;
type SunFamily = u16;
const AF_UNIX: SunFamily = libc::AF_UNIX as SunFamily;
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct Namaste {
socket_fd: i32,
}
impl Namaste {
pub unsafe fn make(id: Id) -> io::Result<Self> {
let socket_fd = match libc::socket(libc::AF_UNIX, libc::SOCK_STREAM | libc::SOCK_NONBLOCK, 0) {
err_code @ -1 => return Err(Error::new(
ErrorKind::Other, format!("libc::socket() returned {:?}; possible errno: {:?}", err_code, *libc::__errno_location()),
)),
other => other,
};
let mut addr = libc::sockaddr_un {
sun_family: AF_UNIX,
sun_path: [0; mem::size_of::<libc::sockaddr_un>() - mem::size_of::<SunFamily>()],
};
for (i, b) in id.into_iter().enumerate() {
addr.sun_path[i + 1] = *b as i8;
}
match {
let addr = mem::transmute::<&libc::sockaddr_un, &libc::sockaddr>(&addr);
libc::bind(socket_fd, addr, mem::size_of::<libc::sockaddr_un>() as u32)
} {
0 => Ok(Self { socket_fd }),
other => {
close_fd(socket_fd)?;
Err(Error::new(ErrorKind::Other, format!("libc::bind() returned {:?}; possible errno: {:?}", other, *libc::__errno_location())))
},
}
}
}
impl Drop for Namaste {
fn drop(&mut self) {
if let Err(err) = unsafe {
close_fd(self.socket_fd)
} {
__e!("{}", err);
}
}
}
unsafe fn close_fd(fd: i32) -> io::Result<()> {
match libc::close(fd) {
0 => Ok(()),
other => Err(Error::new(
ErrorKind::Other, format!("libc::close() on #{} returned {:?}; possible errno: {:?}", fd, other, *libc::__errno_location()),
)),
}
}
#[test]
fn test_namaste() {
let af_unix: i32 = libc::AF_UNIX;
assert!(af_unix >= 0 && af_unix as u32 <= u32::from(SunFamily::max_value()));
assert!(mem::size_of::<SunFamily>() + mem::size_of::<Id>() + 1 < mem::size_of::<libc::sockaddr_un>());
assert!(mem::size_of::<libc::sockaddr_un>() < usize::from(u8::max_value()));
let mut id = tiny_keccak::sha3_512(crate::ID.as_bytes());
for _ in 0..1000 {
id = tiny_keccak::sha3_512(&id);
let mut i8_array = [0_i8; mem::size_of::<Id>()];
for (i, b) in id.iter().enumerate() {
i8_array[i] = *b as i8;
}
let mut u8_array = [0_u8; mem::size_of::<Id>()];
for (i, n) in i8_array.iter().enumerate() {
u8_array[i] = *n as u8;
}
assert_eq!(&id[..], &u8_array[..]);
unsafe {
let namaste = Namaste::make(id).unwrap();
for _ in 0..3 {
assert!(Namaste::make(id).is_err());
}
drop(namaste);
for _ in 0..3 {
assert!(Namaste::make(id).is_ok());
}
}
}
}