Skip to content

Commit 72531a1

Browse files
author
Artem Kryvokrysenko
committed
tracer: update public API for smoltcp::phy::Tracer to allow custom inspection and printing of packet
Currently `smoltcp::phy::tracer::Packet` is not exported as public type, which leaves very limited options for using `Tracer` device: traced packets only can be directly printed "as-is" and only in limited context (inside the closure). I'm updating API of `Tracer` device to provide access to internal fields of traced packet; this will enable implementation of custom printing or packet inspection functions I renamed `smoltcp::phy::tracer::Packet` to `smoltcp::phy::tracer::TracerPacket`, following prefixing convention used by types declared in `smoltcp::phy::pcap_writer`
1 parent a54589c commit 72531a1

File tree

2 files changed

+179
-15
lines changed

2 files changed

+179
-15
lines changed

src/phy/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub use self::loopback::Loopback;
125125
pub use self::pcap_writer::{PcapLinkType, PcapMode, PcapSink, PcapWriter};
126126
#[cfg(all(feature = "phy-raw_socket", unix))]
127127
pub use self::raw_socket::RawSocket;
128-
pub use self::tracer::Tracer;
128+
pub use self::tracer::{Tracer, TracerDirection, TracerPacket};
129129
#[cfg(all(
130130
feature = "phy-tuntap_interface",
131131
any(target_os = "linux", target_os = "android")

src/phy/tracer.rs

Lines changed: 178 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
1111
/// device.
1212
pub struct Tracer<D: Device> {
1313
inner: D,
14-
writer: fn(Instant, Packet),
14+
writer: fn(Instant, TracerPacket),
1515
}
1616

1717
impl<D: Device> Tracer<D> {
1818
/// Create a tracer device.
19-
pub fn new(inner: D, writer: fn(timestamp: Instant, packet: Packet)) -> Tracer<D> {
19+
pub fn new(inner: D, writer: fn(timestamp: Instant, packet: TracerPacket)) -> Tracer<D> {
2020
Tracer { inner, writer }
2121
}
2222

@@ -88,7 +88,7 @@ impl<D: Device> Device for Tracer<D> {
8888
#[doc(hidden)]
8989
pub struct RxToken<Rx: phy::RxToken> {
9090
token: Rx,
91-
writer: fn(Instant, Packet),
91+
writer: fn(Instant, TracerPacket),
9292
medium: Medium,
9393
timestamp: Instant,
9494
}
@@ -101,10 +101,10 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
101101
self.token.consume(|buffer| {
102102
(self.writer)(
103103
self.timestamp,
104-
Packet {
104+
TracerPacket {
105105
buffer,
106106
medium: self.medium,
107-
prefix: "<- ",
107+
direction: TracerDirection::RX,
108108
},
109109
);
110110
f(buffer)
@@ -119,7 +119,7 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
119119
#[doc(hidden)]
120120
pub struct TxToken<Tx: phy::TxToken> {
121121
token: Tx,
122-
writer: fn(Instant, Packet),
122+
writer: fn(Instant, TracerPacket),
123123
medium: Medium,
124124
timestamp: Instant,
125125
}
@@ -133,10 +133,10 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
133133
let result = f(buffer);
134134
(self.writer)(
135135
self.timestamp,
136-
Packet {
136+
TracerPacket {
137137
buffer,
138138
medium: self.medium,
139-
prefix: "-> ",
139+
direction: TracerDirection::TX,
140140
},
141141
);
142142
result
@@ -148,15 +148,34 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
148148
}
149149
}
150150

151-
pub struct Packet<'a> {
152-
buffer: &'a [u8],
153-
medium: Medium,
154-
prefix: &'static str,
151+
/// Packet which is being traced by [Tracer](struct.Tracer.html) device.
152+
#[derive(Debug, Clone, Copy)]
153+
pub struct TracerPacket<'a> {
154+
/// Packet buffer
155+
pub buffer: &'a [u8],
156+
/// Packet medium
157+
pub medium: Medium,
158+
/// Direction in which packet is being traced
159+
pub direction: TracerDirection,
160+
}
161+
162+
/// Direction on which packet is being traced
163+
#[derive(Debug, Clone, Copy, PartialEq)]
164+
pub enum TracerDirection {
165+
/// Packet is received by Smoltcp interface
166+
RX,
167+
/// Packet is transmitted by Smoltcp interface
168+
TX,
155169
}
156170

157-
impl<'a> fmt::Display for Packet<'a> {
171+
impl<'a> fmt::Display for TracerPacket<'a> {
158172
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159-
let mut indent = PrettyIndent::new(self.prefix);
173+
let prefix = match self.direction {
174+
TracerDirection::RX => "<- ",
175+
TracerDirection::TX => "-> ",
176+
};
177+
178+
let mut indent = PrettyIndent::new(prefix);
160179
match self.medium {
161180
#[cfg(feature = "medium-ethernet")]
162181
Medium::Ethernet => crate::wire::EthernetFrame::<&'static [u8]>::pretty_print(
@@ -189,3 +208,148 @@ impl<'a> fmt::Display for Packet<'a> {
189208
}
190209
}
191210
}
211+
212+
#[cfg(test)]
213+
mod tests {
214+
use core::cell::RefCell;
215+
use std::collections::VecDeque;
216+
217+
use super::*;
218+
219+
use crate::phy::ChecksumCapabilities;
220+
use crate::{
221+
phy::{Device, Loopback, RxToken, TxToken},
222+
time::Instant,
223+
};
224+
225+
#[cfg(any(
226+
feature = "medium-ethernet",
227+
feature = "medium-ip",
228+
feature = "medium-ieee802154"
229+
))]
230+
#[test]
231+
fn test_tracer() {
232+
type TracerEvent = (Instant, Vec<u8>, Medium, TracerDirection);
233+
thread_local! {
234+
static TRACE_EVENTS: RefCell<VecDeque<TracerEvent>> = const { RefCell::new(VecDeque::new()) };
235+
}
236+
TRACE_EVENTS.replace(VecDeque::new());
237+
238+
let medium = Medium::default();
239+
240+
let loopback_device = Loopback::new(medium);
241+
let mut tracer_device = Tracer::new(loopback_device, |instant, packet| {
242+
TRACE_EVENTS.with_borrow_mut(|events| {
243+
events.push_back((
244+
instant,
245+
packet.buffer.to_owned(),
246+
packet.medium,
247+
packet.direction,
248+
))
249+
});
250+
});
251+
252+
let expected_payload = [1, 2, 3, 4, 5, 6, 7, 8];
253+
254+
let tx_instant = Instant::from_secs(1);
255+
let tx_token = tracer_device.transmit(tx_instant).unwrap();
256+
257+
tx_token.consume(expected_payload.len(), |buf| {
258+
buf.copy_from_slice(&expected_payload)
259+
});
260+
let last_event = TRACE_EVENTS.with_borrow_mut(|events| events.pop_front());
261+
assert_eq!(
262+
last_event,
263+
Some((
264+
tx_instant,
265+
expected_payload.into(),
266+
medium,
267+
TracerDirection::TX
268+
))
269+
);
270+
let last_event = TRACE_EVENTS.with_borrow_mut(|events| events.pop_front());
271+
assert_eq!(last_event, None);
272+
273+
let rx_instant = Instant::from_secs(2);
274+
let (rx_token, _) = tracer_device.receive(rx_instant).unwrap();
275+
let mut rx_pkt = [0; 8];
276+
rx_token.consume(|buf| rx_pkt.copy_from_slice(buf));
277+
278+
assert_eq!(rx_pkt, expected_payload);
279+
280+
let last_event = TRACE_EVENTS.with_borrow_mut(|events| events.pop_front());
281+
assert_eq!(
282+
last_event,
283+
Some((
284+
rx_instant,
285+
expected_payload.into(),
286+
medium,
287+
TracerDirection::RX
288+
))
289+
);
290+
let last_event = TRACE_EVENTS.with_borrow_mut(|events| events.pop_front());
291+
assert_eq!(last_event, None);
292+
}
293+
294+
#[cfg(feature = "medium-ethernet")]
295+
#[test]
296+
fn test_tracer_packet_display_ether() {
297+
use crate::wire::{EthernetAddress, EthernetProtocol, EthernetRepr};
298+
299+
let repr = EthernetRepr {
300+
src_addr: EthernetAddress([0, 1, 2, 3, 4, 5]),
301+
dst_addr: EthernetAddress([5, 4, 3, 2, 1, 0]),
302+
ethertype: EthernetProtocol::Unknown(0),
303+
};
304+
let mut buffer = vec![0_u8; repr.buffer_len()];
305+
{
306+
use crate::wire::EthernetFrame;
307+
308+
let mut frame = EthernetFrame::new_unchecked(&mut buffer);
309+
repr.emit(&mut frame);
310+
}
311+
312+
let pkt = TracerPacket {
313+
buffer: &buffer,
314+
medium: Medium::Ethernet,
315+
direction: TracerDirection::RX,
316+
};
317+
318+
let pkt_pretty = pkt.to_string();
319+
assert_eq!(
320+
pkt_pretty,
321+
"<- EthernetII src=00-01-02-03-04-05 dst=05-04-03-02-01-00 type=0x0000"
322+
);
323+
}
324+
325+
#[cfg(all(feature = "medium-ip", feature = "proto-ipv4"))]
326+
#[test]
327+
fn test_tracer_packet_display_ip() {
328+
use crate::wire::{IpProtocol, Ipv4Address, Ipv4Repr};
329+
330+
let repr = Ipv4Repr {
331+
src_addr: Ipv4Address::new(10, 0, 0, 1),
332+
dst_addr: Ipv4Address::new(10, 0, 0, 2),
333+
next_header: IpProtocol::Unknown(255),
334+
payload_len: 0,
335+
hop_limit: 64,
336+
};
337+
338+
let mut buffer = vec![0_u8; repr.buffer_len()];
339+
{
340+
use crate::wire::Ipv4Packet;
341+
342+
let mut packet = Ipv4Packet::new_unchecked(&mut buffer);
343+
repr.emit(&mut packet, &ChecksumCapabilities::default());
344+
}
345+
346+
let pkt = TracerPacket {
347+
buffer: &buffer,
348+
medium: Medium::Ip,
349+
direction: TracerDirection::TX,
350+
};
351+
352+
let pkt_pretty = pkt.to_string();
353+
assert_eq!(pkt_pretty, "-> IPv4 src=10.0.0.1 dst=10.0.0.2 proto=0xff");
354+
}
355+
}

0 commit comments

Comments
 (0)