use std::ops::{Index, IndexMut};
use std::time::{Duration, Instant};
pub(crate) const REKEY_AFTER_TIME: Duration = Duration::from_secs(120);
pub(crate) const REJECT_AFTER_TIME: Duration = Duration::from_secs(180);
const REKEY_ATTEMPT_TIME: Duration = Duration::from_secs(90);
const REKEY_TIMEOUT: Duration = Duration::from_secs(5);
const KEEPALIVE_TIMEOUT: Duration = Duration::from_secs(10);
pub(crate) const COOKIE_EXPIRATION_TIME: Duration = Duration::from_secs(120);
pub(crate) const MAX_JITTER: Duration = Duration::from_millis(333);
pub(crate) const REKEY_AFTER_MESSAGES: u64 = 1 << 60;
pub(crate) const REJECT_AFTER_MESSAGES: u64 = u64::MAX - (1 << 13);
#[derive(Debug)]
pub(crate) enum TimerName {
TimeLastHandshakeCompleted,
TimeLastHandshakeStarted,
TimeLastPacketReceived,
TimeLastPacketSent,
TimeLastDataPacketReceived,
TimeLastDataPacketSent,
TimePersistentKeepalive,
TimeLastUpdate,
Top,
}
use self::TimerName::*;
#[derive(Debug)]
pub(crate) struct Timers {
timers: [Instant; TimerName::Top as usize],
last_data_received_without_reply: Option<Instant>,
first_data_sent_without_reply: Option<Instant>,
persistent_keepalive: Option<Duration>,
send_handshake_at: Option<Instant>,
rekey_attempt_time: Duration,
pub(crate) keepalive_timeout: Duration,
pub(crate) rekey_timeout: Duration,
}
impl Timers {
pub(super) fn new(persistent_keepalive: Option<Duration>, now: Instant) -> Timers {
Timers {
timers: [now; TimerName::Top as usize],
last_data_received_without_reply: Default::default(),
first_data_sent_without_reply: Default::default(),
persistent_keepalive,
send_handshake_at: None,
rekey_attempt_time: REKEY_ATTEMPT_TIME,
keepalive_timeout: KEEPALIVE_TIMEOUT,
rekey_timeout: REKEY_TIMEOUT,
}
}
pub(crate) fn reject_after_time(&self) -> Instant {
self[TimeLastHandshakeCompleted] + REJECT_AFTER_TIME * 3
}
pub(crate) fn rekey_attempt_time(&self) -> Instant {
self[TimeLastHandshakeStarted] + self.rekey_attempt_time
}
pub(crate) fn rekey_after_time_without_response(&self) -> Option<Instant> {
let first_packet_without_reply = self.first_data_sent_without_reply?;
Some(first_packet_without_reply + self.keepalive_timeout + self.rekey_timeout)
}
pub(crate) fn keepalive_after_time_without_send(&self) -> Option<Instant> {
let last_data_received_without_reply = self.last_data_received_without_reply?;
Some(last_data_received_without_reply + self.keepalive_timeout)
}
pub(crate) fn next_persistent_keepalive(&self) -> Option<Instant> {
Some(self[TimePersistentKeepalive] + self.persistent_keepalive?)
}
pub(crate) fn clear(&mut self, now: Instant) {
for t in &mut self.timers[..] {
*t = now;
}
self.first_data_sent_without_reply = None;
self.last_data_received_without_reply = None;
}
pub(crate) fn tick(&mut self, timer_name: TimerName, now: Instant) {
match timer_name {
TimeLastPacketReceived => self.first_data_sent_without_reply = None,
TimeLastPacketSent => self.last_data_received_without_reply = None,
TimeLastDataPacketReceived => self.last_data_received_without_reply = Some(now),
TimeLastDataPacketSent => {
match self.first_data_sent_without_reply {
Some(_) => {
}
None => self.first_data_sent_without_reply = Some(now),
}
}
_ => {}
}
self[timer_name] = now;
}
pub(crate) fn rekey_timeout(&self, sent_at: Instant) -> Instant {
sent_at + self.rekey_timeout
}
pub(crate) fn scheduled_handshake(&self) -> Option<Instant> {
self.send_handshake_at
}
pub(crate) fn schedule_handshake(&mut self, at: Instant) {
let existing = self.send_handshake_at.replace(at);
debug_assert!(existing.is_none(), "a handshake is already scheduled");
}
pub(crate) fn take_due_handshake(&mut self, now: Instant) -> Option<Instant> {
self.send_handshake_at.take_if(|at| now >= *at)
}
pub(crate) fn consume_passive_keepalive(&mut self) {
self.last_data_received_without_reply = None;
}
pub(crate) fn set_rekey_attempt_time(&mut self, rekey_attempt_time: Duration) {
debug_assert!(
rekey_attempt_time <= REJECT_AFTER_TIME * 3,
"REKEY_ATTEMPT_TIME must be at most REJECT_AFTER_TIME * 3"
);
self.rekey_attempt_time = rekey_attempt_time;
}
pub(crate) fn set_keepalive_timeout(&mut self, keepalive_timeout: Duration) {
debug_assert!(
keepalive_timeout
.checked_add(self.rekey_timeout)
.is_some_and(|sum| sum <= REJECT_AFTER_TIME),
"KEEPALIVE_TIMEOUT + REKEY_TIMEOUT must be at most REJECT_AFTER_TIME"
);
self.keepalive_timeout = keepalive_timeout;
}
pub(crate) fn set_rekey_timeout(&mut self, rekey_timeout: Duration) {
debug_assert!(
rekey_timeout
.checked_add(self.keepalive_timeout)
.is_some_and(|sum| sum <= REJECT_AFTER_TIME),
"KEEPALIVE_TIMEOUT + REKEY_TIMEOUT must be at most REJECT_AFTER_TIME"
);
self.rekey_timeout = rekey_timeout;
}
}
impl Index<TimerName> for Timers {
type Output = Instant;
fn index(&self, index: TimerName) -> &Self::Output {
&self.timers[index as usize]
}
}
impl IndexMut<TimerName> for Timers {
fn index_mut(&mut self, index: TimerName) -> &mut Self::Output {
&mut self.timers[index as usize]
}
}