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