Skip to main content

r_lanlib/
wire.rs

1//! Implements a default Wire using pnet
2
3use pnet::datalink::{self, PacketMetadata as PnetPacketMetadata};
4use std::{
5    sync::{Arc, Mutex},
6    time,
7};
8
9use crate::{
10    error::{RLanLibError, Result},
11    network::NetworkInterface,
12};
13
14/// Default timing for throttling packet sends to prevent packet loss.
15/// 200µs (5,000 pps) balances scan speed against reliability on WiFi,
16/// macOS BPF, and virtualised environments where tighter timings cause
17/// silent packet drops.
18pub const DEFAULT_PACKET_SEND_TIMING: time::Duration =
19    time::Duration::from_micros(200);
20
21/// PacketMetadata from wire
22pub type PacketMetadata = PnetPacketMetadata;
23
24/// Trait describing a packet reader
25pub trait Reader: Send {
26    /// Returns the next packet off of the wire
27    fn next_packet(&mut self) -> Result<&[u8]>;
28    /// Returns the next packet off of the wire along with metadata
29    fn next_packet_with_metadata(&mut self) -> Result<(&[u8], PacketMetadata)>;
30}
31
32/// Trait describing a packet sender
33pub trait Sender: Send {
34    /// Should send a packet over the wire
35    fn send(&mut self, packet: &[u8]) -> Result<()>;
36}
37
38/// Represents a packet Reader and packet Sender tuple
39#[derive(Clone)]
40pub struct Wire(pub Arc<Mutex<dyn Sender>>, pub Arc<Mutex<dyn Reader>>);
41
42/// A PNetReader implementation of packet Reader
43pub struct PNetReader {
44    receiver: Box<dyn datalink::DataLinkReceiver>,
45}
46
47// Implements the Reader trait for our PNet implementation
48impl Reader for PNetReader {
49    fn next_packet(&mut self) -> Result<&[u8]> {
50        self.receiver
51            .next()
52            .map_err(|e| RLanLibError::Wire(e.to_string()))
53    }
54
55    fn next_packet_with_metadata(&mut self) -> Result<(&[u8], PacketMetadata)> {
56        self.receiver
57            .next_with_metadata()
58            .map_err(|e| RLanLibError::Wire(e.to_string()))
59    }
60}
61
62/// A PNetSender implementation of packet Sender
63pub struct PNetSender {
64    sender: Box<dyn datalink::DataLinkSender>,
65}
66
67// Implements the Sender trait for our PNet implementation
68impl Sender for PNetSender {
69    fn send(&mut self, packet: &[u8]) -> Result<()> {
70        let opt = self.sender.send_to(packet, None);
71        match opt {
72            Some(res) => {
73                Ok(res.map_err(|e| RLanLibError::Wire(e.to_string()))?)
74            }
75            None => Err(RLanLibError::Wire("failed to send packet".into())),
76        }
77    }
78}
79
80/// Returns the default wire for current host
81///
82/// Example
83/// ```no_run
84/// # use std::io;
85/// # use r_lanlib::network;
86/// # use r_lanlib::wire;
87/// let interface = network::get_default_interface().unwrap();
88/// let packet_wire = wire::default(&interface).unwrap();
89/// ```
90pub fn default(interface: &NetworkInterface) -> Result<Wire> {
91    let cfg = pnet::datalink::Config {
92        enable_timestamps: true,
93        read_buffer_size: 65536, // 64 KB — holds ~43 max-size frames
94        write_buffer_size: 65536, // 64 KB — consistent with raw socket convention
95        ..pnet::datalink::Config::default()
96    };
97
98    let channel = match pnet::datalink::channel(&interface.into(), cfg) {
99        Ok(pnet::datalink::Channel::Ethernet(tx, rx)) => Ok((tx, rx)),
100        Ok(_) => {
101            Err(RLanLibError::Wire("failed to create packet reader".into()))
102        }
103        Err(e) => Err(RLanLibError::Wire(e.to_string())),
104    }?;
105
106    Ok(Wire(
107        Arc::new(Mutex::new(PNetSender { sender: channel.0 })),
108        Arc::new(Mutex::new(PNetReader {
109            receiver: channel.1,
110        })),
111    ))
112}
113
114#[cfg(test)]
115#[path = "./wire_tests.rs"]
116mod tests;
117
118/// Provides wire mocks for other modules in test
119#[cfg(test)]
120pub mod mocks {
121    use mockall::mock;
122
123    use super::*;
124
125    mock! {
126            pub PacketReader {}
127            impl Reader for PacketReader {
128                fn next_packet(&mut self) -> Result<&'static [u8]>;
129                fn next_packet_with_metadata(&mut self) -> Result<(&'static [u8], PacketMetadata)>;
130            }
131    }
132
133    mock! {
134        pub PacketSender {}
135        impl Sender for PacketSender {
136            fn send(&mut self, packet: &[u8]) -> Result<()>;
137        }
138    }
139}