use crate::utils::epoch::Epoch;
use core::time::Duration;
use crate::{error::*, secure_channel, transport::packet::Packet};
use log::error;
const MRP_STANDALONE_ACK_TIMEOUT: u64 = 200;
#[derive(Debug)]
pub struct RetransEntry {
msg_ctr: u32,
}
impl RetransEntry {
pub fn new(msg_ctr: u32) -> Self {
Self { msg_ctr }
}
pub fn get_msg_ctr(&self) -> u32 {
self.msg_ctr
}
}
#[derive(Debug, Clone)]
pub struct AckEntry {
msg_ctr: u32,
ack_timeout: Duration,
}
impl AckEntry {
pub fn new(msg_ctr: u32, epoch: Epoch) -> Result<Self, Error> {
if let Some(ack_timeout) =
epoch().checked_add(Duration::from_millis(MRP_STANDALONE_ACK_TIMEOUT))
{
Ok(Self {
msg_ctr,
ack_timeout,
})
} else {
Err(ErrorCode::Invalid.into())
}
}
pub fn get_msg_ctr(&self) -> u32 {
self.msg_ctr
}
pub fn has_timed_out(&self, epoch: Epoch) -> bool {
self.ack_timeout > epoch()
}
}
#[derive(Default, Debug)]
pub struct ReliableMessage {
retrans: Option<RetransEntry>,
ack: Option<AckEntry>,
}
impl ReliableMessage {
pub fn new() -> Self {
Self {
..Default::default()
}
}
pub fn is_empty(&self) -> bool {
self.retrans.is_none() && self.ack.is_none()
}
pub fn is_ack_ready(&self, epoch: Epoch) -> bool {
if let Some(ack_entry) = &self.ack {
ack_entry.has_timed_out(epoch)
} else {
false
}
}
pub fn prepare_ack(_exch_id: u16, proto_tx: &mut Packet) {
secure_channel::common::create_mrp_standalone_ack(proto_tx);
}
pub fn pre_send(&mut self, proto_tx: &mut Packet) -> Result<(), Error> {
if let Some(ack_entry) = &self.ack {
proto_tx.proto.set_ack(ack_entry.get_msg_ctr());
self.ack = None;
}
if !proto_tx.is_reliable() {
return Ok(());
}
if self.retrans.is_some() {
error!("Previous retrans entry for this exchange already exists");
Err(ErrorCode::Invalid)?;
}
self.retrans = Some(RetransEntry::new(proto_tx.plain.ctr));
Ok(())
}
pub fn recv(&mut self, proto_rx: &Packet, epoch: Epoch) -> Result<(), Error> {
if proto_rx.proto.is_ack() {
let ack_msg_ctr = proto_rx.proto.get_ack_msg_ctr().ok_or(ErrorCode::Invalid)?;
if let Some(entry) = &self.retrans {
if entry.get_msg_ctr() != ack_msg_ctr {
error!("Mismatch in retrans-table's msg counter and received msg counter: received {}, expected {}. This is expected for the timebeing", ack_msg_ctr, entry.get_msg_ctr());
}
self.retrans = None;
}
}
if proto_rx.proto.is_reliable() {
if self.ack.is_some() {
error!("Previous ACK entry for this exchange already exists");
Err(ErrorCode::Invalid)?;
}
self.ack = Some(AckEntry::new(proto_rx.plain.ctr, epoch)?);
}
Ok(())
}
}