pub use crate::protocol::*;
pub use crate::transport::*;
pub mod protocol {
use crc32fast::Hasher;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct PortalHeader {
pub magic: u32, pub version: u8, pub msg_type: u8, pub flags: u16, pub payload_len: u32, pub sequence: u32, pub timestamp: u64, pub checksum: u32, pub reserved: [u8; 4], }
impl PortalHeader {
pub const MAGIC: u32 = 0x55545000;
pub const SIZE: usize = 32;
pub fn new(msg_type: u8, payload_len: u32, sequence: u32) -> Self {
let mut header = Self {
magic: Self::MAGIC,
version: 2,
msg_type,
flags: 0,
payload_len,
sequence,
timestamp: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos() as u64,
checksum: 0,
reserved: [0; 4],
};
header.checksum = header.calculate_checksum();
header
}
pub fn to_bytes(&self) -> [u8; 32] {
unsafe { std::mem::transmute(*self) }
}
pub fn from_bytes(bytes: &[u8; 32]) -> Self {
unsafe { std::mem::transmute(*bytes) }
}
fn calculate_checksum(&self) -> u32 {
let mut hasher = Hasher::new();
hasher.update(&self.magic.to_le_bytes());
hasher.update(&[self.version]);
hasher.update(&[self.msg_type]);
hasher.update(&self.flags.to_le_bytes());
hasher.update(&self.payload_len.to_le_bytes());
hasher.update(&self.sequence.to_le_bytes());
hasher.update(&self.timestamp.to_le_bytes());
hasher.finalize()
}
pub fn verify_checksum(&self) -> bool {
let mut temp_header = *self;
temp_header.checksum = 0;
let expected = temp_header.calculate_checksum();
self.checksum == expected
}
}
}
pub mod transport {
use std::ptr;
use std::slice;
use std::ffi::CString;
use anyhow::{Result, Context};
pub struct SharedMemoryTransport {
name: String,
fd: i32,
ptr: *mut u8,
size: usize,
}
impl SharedMemoryTransport {
pub fn new(name: &str, size: usize) -> Result<Self> {
let c_name = CString::new(name).context("Invalid shared memory name")?;
let fd = unsafe {
libc::shm_open(
c_name.as_ptr(),
libc::O_CREAT | libc::O_RDWR,
0o666
)
};
if fd == -1 {
return Err(anyhow::anyhow!("Failed to create shared memory segment"));
}
unsafe {
if libc::ftruncate(fd, size as libc::off_t) == -1 {
libc::close(fd);
return Err(anyhow::anyhow!("Failed to set shared memory size"));
}
}
let ptr = unsafe {
libc::mmap(
ptr::null_mut(),
size,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_SHARED,
fd,
0
)
};
if ptr == libc::MAP_FAILED {
unsafe { libc::close(fd); }
return Err(anyhow::anyhow!("Failed to map shared memory"));
}
Ok(Self {
name: name.to_string(),
fd,
ptr: ptr as *mut u8,
size,
})
}
pub unsafe fn write_zero_copy(&self, data: &[u8], offset: usize) -> Result<()> {
if offset + data.len() > self.size {
return Err(anyhow::anyhow!("Write would exceed shared memory bounds"));
}
ptr::copy_nonoverlapping(
data.as_ptr(),
self.ptr.add(offset),
data.len()
);
Ok(())
}
pub unsafe fn read_zero_copy(&self, offset: usize, len: usize) -> Result<&[u8]> {
if offset + len > self.size {
return Err(anyhow::anyhow!("Read would exceed shared memory bounds"));
}
Ok(slice::from_raw_parts(self.ptr.add(offset), len))
}
pub fn as_ptr(&self) -> *mut u8 {
self.ptr
}
pub fn size(&self) -> usize {
self.size
}
}
impl Drop for SharedMemoryTransport {
fn drop(&mut self) {
unsafe {
libc::munmap(self.ptr as *mut libc::c_void, self.size);
libc::close(self.fd);
let c_name = CString::new(self.name.clone()).unwrap();
libc::shm_unlink(c_name.as_ptr());
}
}
}
unsafe impl Send for SharedMemoryTransport {}
unsafe impl Sync for SharedMemoryTransport {}
}