1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4 // option. This file may not be copied, modified, or distributed
5 // except according to those terms.
6 
7 use std::cmp::{max, min};
8 use std::time::{Duration, Instant};
9 
10 pub const LOCAL_IDLE_TIMEOUT: Duration = Duration::from_secs(30);
11 
12 #[derive(Debug, Clone)]
13 /// There's a little bit of different behavior for resetting idle timeout. See
14 /// -transport 10.2 ("Idle Timeout").
15 enum IdleTimeoutState {
16     Init,
17     PacketReceived(Instant),
18     AckElicitingPacketSent(Instant),
19 }
20 
21 #[derive(Debug, Clone)]
22 /// There's a little bit of different behavior for resetting idle timeout. See
23 /// -transport 10.2 ("Idle Timeout").
24 pub struct IdleTimeout {
25     timeout: Duration,
26     state: IdleTimeoutState,
27 }
28 
29 #[cfg(test)]
30 impl IdleTimeout {
new(timeout: Duration) -> Self31     pub fn new(timeout: Duration) -> Self {
32         Self {
33             timeout,
34             state: IdleTimeoutState::Init,
35         }
36     }
37 }
38 
39 impl Default for IdleTimeout {
default() -> Self40     fn default() -> Self {
41         Self {
42             timeout: LOCAL_IDLE_TIMEOUT,
43             state: IdleTimeoutState::Init,
44         }
45     }
46 }
47 
48 impl IdleTimeout {
set_peer_timeout(&mut self, peer_timeout: Duration)49     pub fn set_peer_timeout(&mut self, peer_timeout: Duration) {
50         self.timeout = min(self.timeout, peer_timeout);
51     }
52 
expiry(&self, now: Instant, pto: Duration) -> Instant53     pub fn expiry(&self, now: Instant, pto: Duration) -> Instant {
54         let start = match self.state {
55             IdleTimeoutState::Init => now,
56             IdleTimeoutState::PacketReceived(t) | IdleTimeoutState::AckElicitingPacketSent(t) => t,
57         };
58         start + max(self.timeout, pto * 3)
59     }
60 
on_packet_sent(&mut self, now: Instant)61     pub fn on_packet_sent(&mut self, now: Instant) {
62         // Only reset idle timeout if we've received a packet since the last
63         // time we reset the timeout here.
64         match self.state {
65             IdleTimeoutState::AckElicitingPacketSent(_) => {}
66             IdleTimeoutState::Init | IdleTimeoutState::PacketReceived(_) => {
67                 self.state = IdleTimeoutState::AckElicitingPacketSent(now);
68             }
69         }
70     }
71 
on_packet_received(&mut self, now: Instant)72     pub fn on_packet_received(&mut self, now: Instant) {
73         // Only update if this doesn't rewind the idle timeout.
74         // We sometimes process packets after caching them, which uses
75         // the time the packet was received.  That could be in the past.
76         let update = match self.state {
77             IdleTimeoutState::Init => true,
78             IdleTimeoutState::AckElicitingPacketSent(t) | IdleTimeoutState::PacketReceived(t) => {
79                 t <= now
80             }
81         };
82         if update {
83             self.state = IdleTimeoutState::PacketReceived(now);
84         }
85     }
86 
expired(&self, now: Instant, pto: Duration) -> bool87     pub fn expired(&self, now: Instant, pto: Duration) -> bool {
88         now >= self.expiry(now, pto)
89     }
90 }
91