use std::os::unix::io::{AsRawFd, OwnedFd};
use tokio::io::unix::AsyncFd;
use tokio::io::Interest;
use crate::netlink::{proto, synth};
const RECV_BUF: usize = 8192;
pub fn spawn_responder(fd: OwnedFd, reply_pid: u32) {
tokio::spawn(async move {
if let Err(e) = responder_loop(fd, reply_pid).await {
eprintln!("sandlock netlink responder error: {e}");
}
});
}
async fn responder_loop(fd: OwnedFd, reply_pid: u32) -> std::io::Result<()> {
let async_fd = AsyncFd::with_interest(fd, Interest::READABLE)?;
let mut buf = vec![0u8; RECV_BUF];
loop {
let mut guard = async_fd.readable().await?;
let raw = guard.get_inner().as_raw_fd();
let n = match guard.try_io(|_| {
let ret = unsafe {
libc::recv(raw, buf.as_mut_ptr() as *mut _, buf.len(), 0)
};
if ret < 0 {
Err(std::io::Error::last_os_error())
} else {
Ok(ret as usize)
}
}) {
Ok(Ok(n)) => n,
Ok(Err(e)) if e.kind() == std::io::ErrorKind::WouldBlock => continue,
Ok(Err(e)) => return Err(e),
Err(_would_block) => continue,
};
if n == 0 {
return Ok(());
}
let req = match proto::parse_request(&buf[..n]) {
Some(r) => r,
None => continue,
};
let reply: Vec<u8> = synth::synthesize_reply(&req, reply_pid)
.into_iter()
.flatten()
.collect();
let sent = unsafe {
libc::send(
raw,
reply.as_ptr() as *const _,
reply.len(),
libc::MSG_NOSIGNAL | libc::MSG_DONTWAIT,
)
};
if sent < 0 {
return Err(std::io::Error::last_os_error());
}
}
}