@@ -11,12 +11,11 @@ use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
11
11
/// device.
12
12
pub struct Tracer < D : Device > {
13
13
inner : D ,
14
- writer : fn ( Instant , Packet ) ,
14
+ writer : fn ( Instant , TracerPacket ) ,
15
15
}
16
16
17
17
impl < D : Device > Tracer < D > {
18
- /// Create a tracer device.
19
- pub fn new ( inner : D , writer : fn ( timestamp : Instant , packet : Packet ) ) -> Tracer < D > {
18
+ pub fn new ( inner : D , writer : fn ( timestamp : Instant , packet : TracerPacket ) ) -> Tracer < D > {
20
19
Tracer { inner, writer }
21
20
}
22
21
@@ -88,7 +87,7 @@ impl<D: Device> Device for Tracer<D> {
88
87
#[ doc( hidden) ]
89
88
pub struct RxToken < Rx : phy:: RxToken > {
90
89
token : Rx ,
91
- writer : fn ( Instant , Packet ) ,
90
+ writer : fn ( Instant , TracerPacket ) ,
92
91
medium : Medium ,
93
92
timestamp : Instant ,
94
93
}
@@ -101,10 +100,10 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
101
100
self . token . consume ( |buffer| {
102
101
( self . writer ) (
103
102
self . timestamp ,
104
- Packet {
103
+ TracerPacket {
105
104
buffer,
106
105
medium : self . medium ,
107
- prefix : "<- " ,
106
+ direction : TracerDirection :: RX ,
108
107
} ,
109
108
) ;
110
109
f ( buffer)
@@ -119,7 +118,7 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
119
118
#[ doc( hidden) ]
120
119
pub struct TxToken < Tx : phy:: TxToken > {
121
120
token : Tx ,
122
- writer : fn ( Instant , Packet ) ,
121
+ writer : fn ( Instant , TracerPacket ) ,
123
122
medium : Medium ,
124
123
timestamp : Instant ,
125
124
}
@@ -133,10 +132,10 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
133
132
let result = f ( buffer) ;
134
133
( self . writer ) (
135
134
self . timestamp ,
136
- Packet {
135
+ TracerPacket {
137
136
buffer,
138
137
medium : self . medium ,
139
- prefix : "-> " ,
138
+ direction : TracerDirection :: TX ,
140
139
} ,
141
140
) ;
142
141
result
@@ -148,15 +147,34 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
148
147
}
149
148
}
150
149
151
- pub struct Packet < ' a > {
152
- buffer : & ' a [ u8 ] ,
153
- medium : Medium ,
154
- prefix : & ' static str ,
150
+ /// Packet which is being traced by [Tracer](struct.Tracer.html) device.
151
+ #[ derive( Debug , Clone , Copy ) ]
152
+ pub struct TracerPacket < ' a > {
153
+ /// Packet buffer
154
+ pub buffer : & ' a [ u8 ] ,
155
+ /// Packet medium
156
+ pub medium : Medium ,
157
+ /// Direction in which packet is being traced
158
+ pub direction : TracerDirection ,
159
+ }
160
+
161
+ /// Direction on which packet is being traced
162
+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
163
+ pub enum TracerDirection {
164
+ /// Packet is received by Smoltcp interface
165
+ RX ,
166
+ /// Packet is transmitted by Smoltcp interface
167
+ TX ,
155
168
}
156
169
157
- impl < ' a > fmt:: Display for Packet < ' a > {
170
+ impl < ' a > fmt:: Display for TracerPacket < ' a > {
158
171
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
159
- let mut indent = PrettyIndent :: new ( self . prefix ) ;
172
+ let prefix = match self . direction {
173
+ TracerDirection :: RX => "<- " ,
174
+ TracerDirection :: TX => "-> " ,
175
+ } ;
176
+
177
+ let mut indent = PrettyIndent :: new ( prefix) ;
160
178
match self . medium {
161
179
#[ cfg( feature = "medium-ethernet" ) ]
162
180
Medium :: Ethernet => crate :: wire:: EthernetFrame :: < & ' static [ u8 ] > :: pretty_print (
@@ -189,3 +207,136 @@ impl<'a> fmt::Display for Packet<'a> {
189
207
}
190
208
}
191
209
}
210
+
211
+ #[ cfg( test) ]
212
+ mod tests {
213
+ use core:: cell:: RefCell ;
214
+ use std:: collections:: VecDeque ;
215
+
216
+ use super :: * ;
217
+
218
+ use crate :: phy:: ChecksumCapabilities ;
219
+ use crate :: wire:: Ipv4Address ;
220
+ use crate :: {
221
+ phy:: { Device , Loopback , RxToken , TxToken } ,
222
+ time:: Instant ,
223
+ wire:: {
224
+ EthernetAddress , EthernetFrame , EthernetProtocol , EthernetRepr , IpProtocol , Ipv4Packet ,
225
+ Ipv4Repr ,
226
+ } ,
227
+ } ;
228
+
229
+ #[ test]
230
+ fn test_tracer ( ) {
231
+ type TracerEvent = ( Instant , Vec < u8 > , Medium , TracerDirection ) ;
232
+ thread_local ! {
233
+ static TRACE_EVENTS : RefCell <VecDeque <TracerEvent >> = const { RefCell :: new( VecDeque :: new( ) ) } ;
234
+ }
235
+ TRACE_EVENTS . replace ( VecDeque :: new ( ) ) ;
236
+
237
+ let loopback_device = Loopback :: new ( crate :: phy:: Medium :: Ip ) ;
238
+ let mut tracer_device = Tracer :: new ( loopback_device, |instant, packet| {
239
+ TRACE_EVENTS . with_borrow_mut ( |events| {
240
+ events. push_back ( (
241
+ instant,
242
+ packet. buffer . to_owned ( ) ,
243
+ packet. medium ,
244
+ packet. direction ,
245
+ ) )
246
+ } ) ;
247
+ } ) ;
248
+
249
+ let expected_payload = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ;
250
+
251
+ let tx_instant = Instant :: from_secs ( 1 ) ;
252
+ let tx_token = tracer_device. transmit ( tx_instant) . unwrap ( ) ;
253
+
254
+ tx_token. consume ( expected_payload. len ( ) , |buf| {
255
+ buf. copy_from_slice ( & expected_payload)
256
+ } ) ;
257
+ let last_event = TRACE_EVENTS . with_borrow_mut ( |events| events. pop_front ( ) ) ;
258
+ assert_eq ! (
259
+ last_event,
260
+ Some ( (
261
+ tx_instant,
262
+ expected_payload. into( ) ,
263
+ Medium :: Ip ,
264
+ TracerDirection :: TX
265
+ ) )
266
+ ) ;
267
+ let last_event = TRACE_EVENTS . with_borrow_mut ( |events| events. pop_front ( ) ) ;
268
+ assert_eq ! ( last_event, None ) ;
269
+
270
+ let rx_instant = Instant :: from_secs ( 2 ) ;
271
+ let ( rx_token, _) = tracer_device. receive ( rx_instant) . unwrap ( ) ;
272
+ let mut rx_pkt = [ 0 ; 8 ] ;
273
+ rx_token. consume ( |buf| rx_pkt. copy_from_slice ( buf) ) ;
274
+
275
+ assert_eq ! ( rx_pkt, expected_payload) ;
276
+
277
+ let last_event = TRACE_EVENTS . with_borrow_mut ( |events| events. pop_front ( ) ) ;
278
+ assert_eq ! (
279
+ last_event,
280
+ Some ( (
281
+ rx_instant,
282
+ expected_payload. into( ) ,
283
+ Medium :: Ip ,
284
+ TracerDirection :: RX
285
+ ) )
286
+ ) ;
287
+ let last_event = TRACE_EVENTS . with_borrow_mut ( |events| events. pop_front ( ) ) ;
288
+ assert_eq ! ( last_event, None ) ;
289
+ }
290
+
291
+ #[ test]
292
+ fn test_tracer_packet_display_ether ( ) {
293
+ let repr = EthernetRepr {
294
+ src_addr : EthernetAddress ( [ 0 , 1 , 2 , 3 , 4 , 5 ] ) ,
295
+ dst_addr : EthernetAddress ( [ 5 , 4 , 3 , 2 , 1 , 0 ] ) ,
296
+ ethertype : EthernetProtocol :: Unknown ( 0 ) ,
297
+ } ;
298
+ let mut buffer = vec ! [ 0_u8 ; repr. buffer_len( ) ] ;
299
+ {
300
+ let mut frame = EthernetFrame :: new_unchecked ( & mut buffer) ;
301
+ repr. emit ( & mut frame) ;
302
+ }
303
+
304
+ let pkt = TracerPacket {
305
+ buffer : & buffer,
306
+ medium : Medium :: Ethernet ,
307
+ direction : TracerDirection :: RX ,
308
+ } ;
309
+
310
+ let pkt_pretty = pkt. to_string ( ) ;
311
+ assert_eq ! (
312
+ pkt_pretty,
313
+ "<- EthernetII src=00-01-02-03-04-05 dst=05-04-03-02-01-00 type=0x0000"
314
+ ) ;
315
+ }
316
+
317
+ #[ test]
318
+ fn test_tracer_packet_display_ip ( ) {
319
+ let repr = Ipv4Repr {
320
+ src_addr : Ipv4Address :: new ( 10 , 0 , 0 , 1 ) ,
321
+ dst_addr : Ipv4Address :: new ( 10 , 0 , 0 , 2 ) ,
322
+ next_header : IpProtocol :: Unknown ( 255 ) ,
323
+ payload_len : 0 ,
324
+ hop_limit : 64 ,
325
+ } ;
326
+
327
+ let mut buffer = vec ! [ 0_u8 ; repr. buffer_len( ) ] ;
328
+ {
329
+ let mut packet = Ipv4Packet :: new_unchecked ( & mut buffer) ;
330
+ repr. emit ( & mut packet, & ChecksumCapabilities :: default ( ) ) ;
331
+ }
332
+
333
+ let pkt = TracerPacket {
334
+ buffer : & buffer,
335
+ medium : Medium :: Ip ,
336
+ direction : TracerDirection :: TX ,
337
+ } ;
338
+
339
+ let pkt_pretty = pkt. to_string ( ) ;
340
+ assert_eq ! ( pkt_pretty, "-> IPv4 src=10.0.0.1 dst=10.0.0.2 proto=0xff" ) ;
341
+ }
342
+ }
0 commit comments