use crate::{
demi_sgarray_t,
demi_sgaseg_t,
inetstack::protocols::{
layer1::PhysicalLayer,
MAX_HEADER_SIZE,
},
runtime::{
fail::Fail,
logging,
memory::{
DemiBuffer,
MemoryRuntime,
},
network::consts::RECEIVE_BATCH_SIZE,
SharedDemiRuntime,
SharedObject,
},
};
use ::arrayvec::ArrayVec;
use ::libc::c_void;
use ::std::{
collections::VecDeque,
mem,
ops::{
Deref,
DerefMut,
},
time::Instant,
};
pub struct TestPhysicalLayer {
incoming: VecDeque<DemiBuffer>,
outgoing: VecDeque<DemiBuffer>,
runtime: SharedDemiRuntime,
}
#[derive(Clone)]
pub struct SharedTestPhysicalLayer(SharedObject<TestPhysicalLayer>);
impl SharedTestPhysicalLayer {
pub fn new_test(now: Instant) -> Self {
logging::initialize();
Self(SharedObject::<TestPhysicalLayer>::new(TestPhysicalLayer {
incoming: VecDeque::new(),
outgoing: VecDeque::new(),
runtime: SharedDemiRuntime::new(now),
}))
}
fn pop_frames(&mut self, num_frames: usize) -> VecDeque<DemiBuffer> {
let length: usize = self.outgoing.len();
self.outgoing.split_off(length - num_frames)
}
pub fn pop_all_frames(&mut self) -> VecDeque<DemiBuffer> {
self.outgoing.split_off(0)
}
pub fn pop_frame(&mut self) -> DemiBuffer {
self.pop_frames(1).pop_front().expect("should be at least one frame")
}
pub fn push_frame(&mut self, pkt: DemiBuffer) {
self.incoming.push_back(pkt);
}
pub fn get_runtime(&self) -> SharedDemiRuntime {
self.runtime.clone()
}
}
impl PhysicalLayer for SharedTestPhysicalLayer {
fn transmit(&mut self, pkt: DemiBuffer) -> Result<(), Fail> {
debug!(
"transmit frame: {:?} total packet size: {:?}",
self.outgoing.len(),
pkt.len()
);
assert!(pkt.len() < u16::MAX as usize);
self.outgoing.push_back(pkt);
Ok(())
}
fn receive(&mut self) -> Result<ArrayVec<DemiBuffer, RECEIVE_BATCH_SIZE>, Fail> {
let mut out = ArrayVec::new();
if let Some(buf) = self.incoming.pop_front() {
out.push(buf);
}
Ok(out)
}
}
impl Deref for SharedTestPhysicalLayer {
type Target = TestPhysicalLayer;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl DerefMut for SharedTestPhysicalLayer {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.deref_mut()
}
}
impl MemoryRuntime for SharedTestPhysicalLayer {
fn sgaalloc(&self, size: usize) -> Result<demi_sgarray_t, Fail> {
if size == 0 {
let cause: String = format!("cannot allocate a zero-sized buffer");
error!("sgaalloc(): {}", cause);
return Err(Fail::new(libc::EINVAL, &cause));
}
if size > u16::MAX as usize {
return Err(Fail::new(libc::EINVAL, "size too large for a single demi_sgaseg_t"));
}
let buf: DemiBuffer = DemiBuffer::new_with_headroom(size as u16, MAX_HEADER_SIZE as u16);
let data: *const u8 = buf.as_ptr();
let sga_seg: demi_sgaseg_t = demi_sgaseg_t {
sgaseg_buf: data as *mut c_void,
sgaseg_len: size as u32,
};
Ok(demi_sgarray_t {
sga_buf: buf.into_raw().as_ptr() as *mut c_void,
sga_numsegs: 1,
sga_segs: [sga_seg],
sga_addr: unsafe { mem::zeroed() },
})
}
}