4
4
5
5
use self :: codec:: { TunnelCodec , TunnelMessage } ;
6
6
use crate :: utils:: { hashing:: IntHashMap , types:: GameID } ;
7
+ use bytes:: Bytes ;
7
8
use futures_util:: { Sink , Stream } ;
8
9
use hyper:: upgrade:: Upgraded ;
9
10
use hyper_util:: rt:: TokioIo ;
@@ -17,8 +18,12 @@ use std::{
17
18
Arc ,
18
19
} ,
19
20
task:: { ready, Context , Poll } ,
21
+ time:: Duration ,
22
+ } ;
23
+ use tokio:: {
24
+ sync:: mpsc,
25
+ time:: { interval_at, Instant , Interval , MissedTickBehavior } ,
20
26
} ;
21
- use tokio:: sync:: mpsc;
22
27
use tokio_util:: codec:: Framed ;
23
28
24
29
use super :: sessions:: AssociationId ;
@@ -240,6 +245,8 @@ pub struct Tunnel {
240
245
write_state : TunnelWriteState ,
241
246
/// The service access
242
247
service : Arc < TunnelService > ,
248
+ /// Interval for sending keep alive messages
249
+ keep_alive_interval : Interval ,
243
250
}
244
251
245
252
impl Drop for Tunnel {
@@ -273,6 +280,9 @@ enum TunnelReadState {
273
280
}
274
281
275
282
impl Tunnel {
283
+ // Send keep-alive pings every 10s
284
+ const KEEP_ALIVE_DELAY : Duration = Duration :: from_secs ( 10 ) ;
285
+
276
286
/// Starts a new tunnel on `io` using the tunnel `service`
277
287
///
278
288
/// ## Arguments
@@ -294,13 +304,20 @@ impl Tunnel {
294
304
. write ( )
295
305
. insert_tunnel ( id, TunnelHandle { tx } ) ;
296
306
307
+ // Create the interval to track keep alive pings
308
+ let keep_alive_start = Instant :: now ( ) + Self :: KEEP_ALIVE_DELAY ;
309
+ let mut keep_alive_interval = interval_at ( keep_alive_start, Self :: KEEP_ALIVE_DELAY ) ;
310
+
311
+ keep_alive_interval. set_missed_tick_behavior ( MissedTickBehavior :: Delay ) ;
312
+
297
313
// Spawn the tunnel task
298
314
tokio:: spawn ( Tunnel {
299
315
service,
300
316
id,
301
317
io,
302
318
rx,
303
319
write_state : Default :: default ( ) ,
320
+ keep_alive_interval,
304
321
} ) ;
305
322
306
323
id
@@ -372,6 +389,11 @@ impl Tunnel {
372
389
return Poll :: Ready ( TunnelReadState :: Stop ) ;
373
390
} ;
374
391
392
+ // Ping messages can be ignored
393
+ if message. index == 255 {
394
+ return Poll :: Ready ( TunnelReadState :: Continue ) ;
395
+ }
396
+
375
397
// Get the path through the tunnel
376
398
let ( target_handle, index) = match self . service . get_tunnel_route ( self . id , message. index ) {
377
399
Some ( value) => value,
@@ -413,6 +435,27 @@ impl Future for Tunnel {
413
435
}
414
436
}
415
437
438
+ // Write a ping message at the interval if we aren't already sending a message
439
+ if this. keep_alive_interval . poll_tick ( cx) . is_ready ( ) {
440
+ if let TunnelWriteState :: Recv = this. write_state {
441
+ // Move to a writing state
442
+ this. write_state = TunnelWriteState :: Write ( Some ( TunnelMessage {
443
+ index : 255 ,
444
+ message : Bytes :: new ( ) ,
445
+ } ) ) ;
446
+
447
+ // Poll the writer with the new message
448
+ if let Poll :: Ready ( next_state) = this. poll_write_state ( cx) {
449
+ this. write_state = next_state;
450
+
451
+ // Tunnel has stopped
452
+ if let TunnelWriteState :: Stop = this. write_state {
453
+ return Poll :: Ready ( ( ) ) ;
454
+ }
455
+ }
456
+ }
457
+ }
458
+
416
459
Poll :: Pending
417
460
}
418
461
}
@@ -443,6 +486,13 @@ mod codec {
443
486
//! Length: 16-bits. Determines the size in bytes of the payload that follows
444
487
//!
445
488
//! Payload: Variable length. The message bytes payload of `Length`
489
+ //!
490
+ //!
491
+ //! ## Keep alive
492
+ //!
493
+ //! The server will send keep-alive messages, these are in the same
494
+ //! format as the packet above. However, the index will always be 255
495
+ //! and the payload will be empty.
446
496
447
497
use bytes:: { Buf , BufMut , Bytes } ;
448
498
use tokio_util:: codec:: { Decoder , Encoder } ;
0 commit comments