@@ -8,21 +8,23 @@ use pnet::datalink::{
8
8
use pnet:: packet:: ethernet:: { EtherTypes , EthernetPacket , MutableEthernetPacket } ;
9
9
use pnet:: packet:: Packet as PnetPacket ;
10
10
use pnet:: util:: MacAddr ;
11
+ use rand:: Rng ;
11
12
use serde:: { Deserialize , Serialize } ;
12
13
13
14
use crate :: error:: ArpchatError ;
15
+ use crate :: ringbuffer:: Ringbuffer ;
14
16
15
17
const ARP_HTYPE : & [ u8 ] = & [ 0x00 , 0x01 ] ; // Hardware Type (Ethernet)
16
18
const ARP_HLEN : u8 = 6 ; // Hardware Address Length
17
19
const ARP_OPER : & [ u8 ] = & [ 0 , 1 ] ; // Operation (Request)
18
20
const PACKET_PREFIX : & [ u8 ] = b"uwu" ;
19
21
20
- // Tag, seq, and total, are each one byte, thus the `+ 3`.
21
- const PACKET_PART_SIZE : usize = u8:: MAX as usize - ( PACKET_PREFIX . len ( ) + 3 ) ;
22
-
23
22
pub const ID_SIZE : usize = 8 ;
24
23
pub type Id = [ u8 ; ID_SIZE ] ;
25
24
25
+ // Tag, seq, and total, are each one byte, thus the `+ 3`.
26
+ const PACKET_PART_SIZE : usize = u8:: MAX as usize - ( PACKET_PREFIX . len ( ) + 3 + ID_SIZE ) ;
27
+
26
28
#[ derive( Default , Serialize , Deserialize , Copy , Clone , Debug , PartialEq , Eq ) ]
27
29
pub enum EtherType {
28
30
#[ default]
@@ -134,15 +136,16 @@ pub struct Channel {
134
136
tx : Box < dyn DataLinkSender > ,
135
137
rx : Box < dyn DataLinkReceiver > ,
136
138
137
- /// Buffer of received packet parts, keyed by the number of parts and
138
- /// its tag. This keying method is far from foolproof but reduces
139
- /// the chance of colliding packets just a tiny bit.
139
+ /// Buffer of received packet parts, keyed by the packet id.
140
140
///
141
141
/// Each value is the Vec of its parts, and counts as a packet when
142
142
/// every part is non-empty. There are probably several optimization
143
143
/// opportunities here, but c'mon, a naive approach is perfectly fine
144
144
/// for a program this cursed.
145
- buffer : HashMap < ( u8 , u8 ) , Vec < Vec < u8 > > > ,
145
+ buffer : HashMap < Id , Vec < Vec < u8 > > > ,
146
+
147
+ /// Recent packet buffer for deduplication.
148
+ recent : Ringbuffer < Id > ,
146
149
}
147
150
148
151
impl Channel {
@@ -159,6 +162,7 @@ impl Channel {
159
162
tx,
160
163
rx,
161
164
buffer : HashMap :: new ( ) ,
165
+ recent : Ringbuffer :: with_capacity ( 16 ) ,
162
166
} )
163
167
}
164
168
@@ -171,23 +175,33 @@ impl Channel {
171
175
let mut parts: Vec < & [ u8 ] > = data. chunks ( PACKET_PART_SIZE ) . collect ( ) ;
172
176
173
177
if parts. is_empty ( ) {
174
- // Empty packets still need one byte of data to go through :)
178
+ // We need to send some data so empty enums go through! Not entirely
179
+ // sure *why* this is the case... pushing an empty string feels like
180
+ // it should be fine, but it doesn't work.
175
181
parts. push ( b"." ) ;
176
182
}
177
183
if parts. len ( ) - 1 > u8:: MAX as usize {
178
184
return Err ( ArpchatError :: MsgTooLong ) ;
179
185
}
180
186
181
187
let total = ( parts. len ( ) - 1 ) as u8 ;
188
+ let id: Id = rand:: thread_rng ( ) . gen ( ) ;
182
189
for ( seq, part) in parts. into_iter ( ) . enumerate ( ) {
183
- self . send_part ( packet. tag ( ) , seq as u8 , total, part) ?;
190
+ self . send_part ( packet. tag ( ) , seq as u8 , total, id , part) ?;
184
191
}
185
192
186
193
Ok ( ( ) )
187
194
}
188
195
189
- fn send_part ( & mut self , tag : u8 , seq : u8 , total : u8 , part : & [ u8 ] ) -> Result < ( ) , ArpchatError > {
190
- let data = & [ PACKET_PREFIX , & [ tag, seq, total] , part] . concat ( ) ;
196
+ fn send_part (
197
+ & mut self ,
198
+ tag : u8 ,
199
+ seq : u8 ,
200
+ total : u8 ,
201
+ id : Id ,
202
+ part : & [ u8 ] ,
203
+ ) -> Result < ( ) , ArpchatError > {
204
+ let data = & [ PACKET_PREFIX , & [ tag, seq, total] , & id, part] . concat ( ) ;
191
205
192
206
// The length of the data must fit in a u8. This should also
193
207
// guarantee that we'll be inside the MTU.
@@ -247,28 +261,39 @@ impl Channel {
247
261
}
248
262
249
263
if let & [ tag, seq, total, ref inner @ ..] = & data[ PACKET_PREFIX . len ( ) ..] {
250
- let key = ( tag, total) ;
251
-
252
- if let Some ( parts) = self . buffer . get_mut ( & key) {
253
- parts[ seq as usize ] = inner. to_vec ( ) ;
254
- } else {
255
- let mut parts = vec ! [ vec![ ] ; total as usize + 1 ] ;
256
- parts[ seq as usize ] = inner. to_vec ( ) ;
257
- self . buffer . insert ( key, parts) ;
258
- }
264
+ Ok ( try {
265
+ let id: Id = inner[ ..ID_SIZE ] . try_into ( ) . ok ( ) ?;
266
+ let inner = & inner[ ID_SIZE ..] ;
259
267
260
- // SAFETY: Guaranteed to exist because it's populated directly above.
261
- let parts = unsafe { self . buffer . get ( & key) . unwrap_unchecked ( ) } ;
268
+ // Skip if we already have this packet.
269
+ if self . recent . contains ( & id) {
270
+ None ?;
271
+ }
262
272
263
- if parts. iter ( ) . all ( |p| !p. is_empty ( ) ) {
273
+ if let Some ( parts) = self . buffer . get_mut ( & id) {
274
+ parts[ seq as usize ] = inner. to_vec ( ) ;
275
+ } else {
276
+ let mut parts = vec ! [ vec![ ] ; total as usize + 1 ] ;
277
+ parts[ seq as usize ] = inner. to_vec ( ) ;
278
+ self . buffer . insert ( id, parts) ;
279
+ }
280
+
281
+ // SAFETY: Guaranteed to exist because it's populated directly above.
282
+ let parts = unsafe { self . buffer . get ( & id) . unwrap_unchecked ( ) } ;
283
+
284
+ // Short-circuit if we don't have all the parts yet.
285
+ if !parts. iter ( ) . all ( |p| !p. is_empty ( ) ) {
286
+ None ?;
287
+ }
288
+
289
+ // Put the packet together.
264
290
let packet = Packet :: deserialize ( tag, & parts. concat ( ) ) ;
265
291
if packet. is_some ( ) {
266
- self . buffer . remove ( & key) ;
292
+ self . buffer . remove ( & id) ;
293
+ self . recent . push ( id) ;
267
294
}
268
- Ok ( packet)
269
- } else {
270
- Ok ( None )
271
- }
295
+ packet?
296
+ } )
272
297
} else {
273
298
Ok ( None )
274
299
}
0 commit comments