use std::collections::VecDeque;
use std::io;
use std::os::fd::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
use std::sync::{Arc, Mutex};
use crate::channel::{Receiver, Sender};
use crate::error::Result;
use crate::interface::{IfIndex, Interface, MacAddr};
pub(crate) type RxQueue = Arc<Mutex<VecDeque<io::Result<Vec<u8>>>>>;
pub(crate) type SentQueue = Arc<Mutex<VecDeque<Vec<u8>>>>;
#[derive(Debug)]
pub struct DummyChannel {
pub tx: Sender,
pub rx: Receiver,
pub inject: Injector,
pub drain: Drain,
}
pub fn channel() -> Result<DummyChannel> {
let (read, write) = make_pipe()?;
let rx_queue: RxQueue = Arc::new(Mutex::new(VecDeque::new()));
let sent: SentQueue = Arc::new(Mutex::new(VecDeque::new()));
let (_sender_read, sender_fd) = make_pipe()?;
let tx = Sender::from_dummy(sent.clone(), sender_fd);
let rx = Receiver::from_dummy(rx_queue.clone(), read);
Ok(DummyChannel {
tx,
rx,
inject: Injector { queue: rx_queue, notify: write },
drain: Drain { sent },
})
}
#[cfg(feature = "tokio")]
#[derive(Debug)]
pub struct AsyncDummyChannel {
pub tx: crate::async_channel::AsyncSender,
pub rx: crate::async_channel::AsyncReceiver,
pub inject: Injector,
pub drain: Drain,
}
#[cfg(feature = "tokio")]
pub fn channel_async() -> Result<AsyncDummyChannel> {
use crate::async_channel::{AsyncReceiver, AsyncSender};
use crate::channel::{RxBackend, TxBackend};
let (read, write) = make_pipe()?;
let rx_queue: RxQueue = Arc::new(Mutex::new(VecDeque::new()));
let sent: SentQueue = Arc::new(Mutex::new(VecDeque::new()));
let (_sender_read, sender_fd) = make_pipe()?;
let tx = AsyncSender::new(TxBackend::Dummy { sent: sent.clone(), fd: sender_fd })?;
let rx = AsyncReceiver::new(RxBackend::Dummy {
queue: rx_queue.clone(),
readiness: read,
last: Vec::new(),
})?;
Ok(AsyncDummyChannel {
tx,
rx,
inject: Injector { queue: rx_queue, notify: write },
drain: Drain { sent },
})
}
#[derive(Debug)]
pub struct Injector {
queue: RxQueue,
notify: OwnedFd,
}
impl Injector {
pub fn inject(&self, frame: Vec<u8>) {
self.push(Ok(frame));
}
pub fn inject_error(&self, err: io::Error) {
self.push(Err(err));
}
fn push(&self, item: io::Result<Vec<u8>>) {
self.queue.lock().expect("dummy queue poisoned").push_back(item);
let byte = [1u8];
unsafe {
libc::write(self.notify.as_raw_fd(), byte.as_ptr().cast(), 1);
}
}
}
#[derive(Debug)]
pub struct Drain {
sent: SentQueue,
}
impl Drain {
#[must_use]
pub fn try_recv(&self) -> Option<Vec<u8>> {
self.sent.lock().expect("dummy queue poisoned").pop_front()
}
#[must_use]
pub fn len(&self) -> usize {
self.sent.lock().expect("dummy queue poisoned").len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub(crate) fn drain_readiness(fd: BorrowedFd<'_>) -> bool {
let mut buf = [0u8; 64];
loop {
let n = unsafe { libc::read(fd.as_raw_fd(), buf.as_mut_ptr().cast(), buf.len()) };
match n {
0 => return true, n if n < 0 => return false, _ => {} }
}
}
pub(crate) fn make_pipe() -> Result<(OwnedFd, OwnedFd)> {
let mut fds = [0 as RawFd; 2];
let rc = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC | libc::O_NONBLOCK) };
if rc != 0 {
return Err(crate::Error::Socket(io::Error::last_os_error()));
}
Ok(unsafe { (OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1])) })
}
#[must_use]
pub fn interfaces() -> Vec<Interface> {
(0..3)
.map(|i| Interface {
name: format!("dummy{i}"),
index: IfIndex(i + 1),
mac: Some(MacAddr([0x02, 0, 0, 0, 0, i as u8])),
ips: Vec::new(),
flags: 0,
mtu: 1500,
})
.collect()
}