1use std::sync::{Arc, Mutex};
2
3use thiserror::Error;
4use tokio::{
5 sync::SetOnce,
6 time::{Duration, Instant},
7};
8
9use crate::param::ArcParameters;
10
11#[derive(Debug)]
12struct DeferIdleTimer {
13 defer_idle_timeout: Duration,
14 last_effective_comm: Option<Instant>,
15}
16
17impl DeferIdleTimer {
18 fn new(defer_idle_timeout: Duration) -> Self {
20 Self {
21 defer_idle_timeout,
22 last_effective_comm: None,
23 }
24 }
25
26 fn renew(&mut self) {
31 self.last_effective_comm = Some(Instant::now());
34 }
35
36 fn is_idle_lasted_for(&self, duration: Duration) -> bool {
37 self.last_effective_comm
38 .is_some_and(|last| last.elapsed() >= duration)
39 }
40
41 fn is_expired(&self) -> bool {
46 self.elapsed() >= self.defer_idle_timeout
47 }
48
49 fn elapsed(&self) -> Duration {
50 self.last_effective_comm
51 .map_or(Duration::ZERO, |last| last.elapsed())
52 }
53}
54
55#[derive(Debug, Clone)]
62pub struct ArcDeferIdleTimer(Arc<Mutex<DeferIdleTimer>>);
63
64impl ArcDeferIdleTimer {
65 pub fn new(defer_idle_timeout: Duration) -> Self {
67 Self(Arc::new(Mutex::new(DeferIdleTimer::new(
68 defer_idle_timeout,
69 ))))
70 }
71
72 pub fn renew_on_effective_communicated(&self) {
77 self.0.lock().unwrap().renew()
78 }
79
80 pub fn is_idle_lasted_for(&self, duration: Duration) -> bool {
81 self.0.lock().unwrap().is_idle_lasted_for(duration)
82 }
83
84 pub fn is_expired(&self) -> bool {
89 self.0.lock().unwrap().is_expired()
90 }
91}
92
93#[derive(Debug)]
95pub struct MaxIdleTimer {
96 max_idle_timeout: Arc<SetOnce<Duration>>,
97 last_rcvd_time: Option<Instant>,
98}
99
100#[derive(Debug, Error)]
101#[error("Path has been idle for too long({} ms)", self.idle_for.as_millis())]
102pub struct IdleTimedOut {
103 last_rcvd_time: Option<Instant>,
104 idle_for: Duration,
105}
106
107impl IdleTimedOut {
108 pub fn last_rcvd_time(&self) -> Option<Instant> {
109 self.last_rcvd_time
110 }
111
112 pub fn idle_for(&self) -> Duration {
113 self.idle_for
114 }
115}
116
117impl MaxIdleTimer {
118 pub(crate) fn new(parameters: &ArcParameters) -> Self {
120 let max_idle_timeout = Arc::new(SetOnce::new());
121 if let Some(time) = parameters
122 .lock_guard()
123 .ok()
124 .and_then(|p| p.negotiated_max_idle_timeout())
125 {
126 max_idle_timeout
127 .set(time)
128 .expect("Set will only be called once");
129 } else {
130 let parameters = parameters.clone();
131 let max_idle_timeout = max_idle_timeout.clone();
132 tokio::spawn(async move {
133 let Ok(parameters) = parameters.remote_ready().await else {
134 return;
135 };
136 let time = parameters
137 .negotiated_max_idle_timeout()
138 .expect("Remote parameters has been ready");
139 max_idle_timeout
140 .set(time)
141 .expect("Set will only be called here");
142 });
143 }
144 Self {
145 max_idle_timeout,
146 last_rcvd_time: None,
147 }
148 }
149
150 pub fn renew_on_received_1rtt(&mut self) {
152 self.last_rcvd_time = Some(Instant::now());
153 }
154
155 pub fn run_out(&self, pto: Duration) -> Result<(), IdleTimedOut> {
159 let Some(max_idle_timeout) = self.max_idle_timeout.get().copied() else {
160 return Ok(());
161 };
162 let max_idle_timeout = max_idle_timeout.max(pto * 3);
163
164 let Some(last_rcvd_time) = self.last_rcvd_time else {
165 return Ok(());
166 };
167
168 let since_last_rcvd = last_rcvd_time.elapsed();
169
170 if since_last_rcvd >= max_idle_timeout {
171 return Err(IdleTimedOut {
172 last_rcvd_time: Some(last_rcvd_time),
173 idle_for: since_last_rcvd,
174 });
175 }
176
177 Ok(())
178 }
179}
180
181#[derive(Debug, Clone)]
182pub struct ArcMaxIdleTimer(Arc<Mutex<MaxIdleTimer>>);
183
184impl From<MaxIdleTimer> for ArcMaxIdleTimer {
185 fn from(timer: MaxIdleTimer) -> Self {
186 ArcMaxIdleTimer(Arc::new(Mutex::new(timer)))
187 }
188}
189
190impl ArcMaxIdleTimer {
191 pub fn renew_on_received_1rtt(&self) {
193 self.0.lock().unwrap().renew_on_received_1rtt();
194 }
195
196 pub fn run_out(&self, pto: Duration) -> Result<(), IdleTimedOut> {
198 self.0.lock().unwrap().run_out(pto)
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_defer_idle_timer() {
208 let timer = ArcDeferIdleTimer::new(Duration::from_millis(100));
209 timer.renew_on_effective_communicated();
210 assert!(!timer.is_expired());
211 std::thread::sleep(Duration::from_millis(150));
212 assert!(timer.is_expired());
213 }
214}