use crate::config::Config;
use std::fs::File;
use std::io::Read;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
pub fn message(cfg: &Config) -> Vec<u8> {
format!(
"{} rash {} {} {}\r\n",
hostname(),
std::process::id(),
nonce(),
cfg.message
)
.into_bytes()
}
pub async fn exchange<W, R>(w: &mut W, r: &mut R, msg: &[u8]) -> bool
where
W: AsyncWriteExt + Unpin,
R: AsyncReadExt + Unpin,
{
if w.write_all(msg).await.is_err() || w.flush().await.is_err() {
return false;
}
let mut back = vec![0u8; msg.len()];
if r.read_exact(&mut back).await.is_err() {
return false;
}
back == msg
}
fn hostname() -> String {
let uts = unsafe {
let mut uts: libc::utsname = std::mem::zeroed();
if libc::uname(&mut uts) != 0 {
return String::new();
}
uts
};
#[allow(clippy::unnecessary_cast)]
let bytes: Vec<u8> = uts
.nodename
.iter()
.take_while(|&&c| c != 0)
.map(|&c| c as u8)
.collect();
String::from_utf8_lossy(&bytes).into_owned()
}
pub(crate) fn nonce() -> u64 {
let mut buf = [0u8; 8];
if let Ok(mut f) = File::open("/dev/urandom")
&& f.read_exact(&mut buf).is_ok()
{
return u64::from_ne_bytes(buf);
}
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_or(0, |d| d.as_nanos() as u64);
nanos ^ u64::from(std::process::id())
}