use pnet::datalink::{self, PacketMetadata as PnetPacketMetadata};
use std::{
sync::{Arc, Mutex},
time,
};
use crate::{
error::{RLanLibError, Result},
network::NetworkInterface,
};
pub const DEFAULT_PACKET_SEND_TIMING: time::Duration =
time::Duration::from_micros(200);
pub type PacketMetadata = PnetPacketMetadata;
pub trait Reader: Send {
fn next_packet(&mut self) -> Result<&[u8]>;
fn next_packet_with_metadata(&mut self) -> Result<(&[u8], PacketMetadata)>;
}
pub trait Sender: Send {
fn send(&mut self, packet: &[u8]) -> Result<()>;
}
#[derive(Clone)]
pub struct Wire(pub Arc<Mutex<dyn Sender>>, pub Arc<Mutex<dyn Reader>>);
pub struct PNetReader {
receiver: Box<dyn datalink::DataLinkReceiver>,
}
impl Reader for PNetReader {
fn next_packet(&mut self) -> Result<&[u8]> {
self.receiver
.next()
.map_err(|e| RLanLibError::Wire(e.to_string()))
}
fn next_packet_with_metadata(&mut self) -> Result<(&[u8], PacketMetadata)> {
self.receiver
.next_with_metadata()
.map_err(|e| RLanLibError::Wire(e.to_string()))
}
}
pub struct PNetSender {
sender: Box<dyn datalink::DataLinkSender>,
}
impl Sender for PNetSender {
fn send(&mut self, packet: &[u8]) -> Result<()> {
let opt = self.sender.send_to(packet, None);
match opt {
Some(res) => {
Ok(res.map_err(|e| RLanLibError::Wire(e.to_string()))?)
}
None => Err(RLanLibError::Wire("failed to send packet".into())),
}
}
}
pub fn default(interface: &NetworkInterface) -> Result<Wire> {
let cfg = pnet::datalink::Config {
enable_timestamps: true,
read_buffer_size: 65536, write_buffer_size: 65536, ..pnet::datalink::Config::default()
};
let channel = match pnet::datalink::channel(&interface.into(), cfg) {
Ok(pnet::datalink::Channel::Ethernet(tx, rx)) => Ok((tx, rx)),
Ok(_) => {
Err(RLanLibError::Wire("failed to create packet reader".into()))
}
Err(e) => Err(RLanLibError::Wire(e.to_string())),
}?;
Ok(Wire(
Arc::new(Mutex::new(PNetSender { sender: channel.0 })),
Arc::new(Mutex::new(PNetReader {
receiver: channel.1,
})),
))
}
#[cfg(test)]
#[path = "./wire_tests.rs"]
mod tests;
#[cfg(test)]
pub mod mocks {
use mockall::mock;
use super::*;
mock! {
pub PacketReader {}
impl Reader for PacketReader {
fn next_packet(&mut self) -> Result<&'static [u8]>;
fn next_packet_with_metadata(&mut self) -> Result<(&'static [u8], PacketMetadata)>;
}
}
mock! {
pub PacketSender {}
impl Sender for PacketSender {
fn send(&mut self, packet: &[u8]) -> Result<()>;
}
}
}