#[cfg(feature = "std")]
use core::cmp;
use core::cmp::Ordering;
use core::fmt;
#[cfg(feature = "std")]
use core::time::Duration;
#[cfg(feature = "std")]
use std::time::{SystemTime, UNIX_EPOCH};
use domain_macros::*;
use crate::new::base::build::BuildInMessage;
use crate::new::base::name::{CanonicalName, Name, NameCompressor};
use crate::new::base::wire::{AsBytes, BuildBytes, TruncationError, U16};
use crate::new::base::{CanonicalRecordData, RType, Serial, TTL};
use super::SecAlg;
#[derive(Clone, Debug, PartialEq, Eq, Hash, BuildBytes, ParseBytes)]
pub struct Rrsig<'a> {
pub rtype: RType,
pub algorithm: SecAlg,
pub labels: u8,
pub ttl: TTL,
pub expiration: Serial,
pub inception: Serial,
pub keytag: U16,
pub signer: &'a Name,
pub signature: &'a [u8],
}
impl Rrsig<'_> {
#[cfg(feature = "bumpalo")]
pub fn clone_to_bump<'r>(&self, bump: &'r bumpalo::Bump) -> Rrsig<'r> {
use crate::utils::dst::copy_to_bump;
Rrsig {
signer: copy_to_bump(self.signer, bump),
signature: bump.alloc_slice_copy(self.signature),
..self.clone()
}
}
}
impl CanonicalRecordData for Rrsig<'_> {
fn cmp_canonical(&self, that: &Self) -> Ordering {
let this_initial = (
self.rtype,
self.algorithm,
self.labels,
self.ttl,
self.expiration.as_bytes(),
self.inception.as_bytes(),
self.keytag,
);
let that_initial = (
that.rtype,
that.algorithm,
that.labels,
that.ttl,
that.expiration.as_bytes(),
that.inception.as_bytes(),
that.keytag,
);
this_initial
.cmp(&that_initial)
.then_with(|| self.signer.cmp_lowercase_composed(that.signer))
.then_with(|| self.signature.cmp(that.signature))
}
}
impl BuildInMessage for Rrsig<'_> {
fn build_in_message(
&self,
contents: &mut [u8],
start: usize,
_compressor: &mut NameCompressor,
) -> Result<usize, TruncationError> {
let bytes = contents.get_mut(start..).ok_or(TruncationError)?;
let rest = self.build_bytes(bytes)?.len();
Ok(contents.len() - rest)
}
}
impl Rrsig<'_> {
pub fn type_covered(&self) -> RType {
self.rtype
}
pub fn original_ttl(&self) -> TTL {
self.ttl
}
pub fn key_tag(&self) -> u16 {
self.keytag.into()
}
pub fn expiration(&self) -> Timestamp {
Timestamp(self.expiration)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Timestamp(Serial);
impl Timestamp {
#[must_use]
pub fn into_int(self) -> u32 {
self.0.into()
}
#[must_use]
#[cfg(feature = "std")]
pub fn to_system_time(self, reference: SystemTime) -> SystemTime {
const POW_2_32: u64 = 0x1_0000_0000;
let ref_secs =
reference.duration_since(UNIX_EPOCH).unwrap().as_secs();
let k = ref_secs / POW_2_32;
let ref_secs_mod = ref_secs % POW_2_32;
let ts_secs = self.into_int() as u64;
let ts_secs = if ts_secs < ref_secs_mod {
if ref_secs_mod - ts_secs <= POW_2_32 / 2 {
ts_secs + k * POW_2_32
} else {
ts_secs + (k + 1) * POW_2_32
}
} else {
if ts_secs - ref_secs_mod < POW_2_32 / 2 {
ts_secs + k * POW_2_32
} else {
let k = if k > 0 { k - 1 } else { k };
ts_secs + k * POW_2_32
}
};
UNIX_EPOCH + Duration::from_secs(ts_secs)
}
}
impl From<u32> for Timestamp {
fn from(item: u32) -> Self {
Self(Serial::from(item))
}
}
impl fmt::Display for Timestamp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(feature = "std")]
impl cmp::PartialOrd for Timestamp {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl From<Timestamp> for crate::rdata::dnssec::Timestamp {
fn from(ts: Timestamp) -> Self {
let v: u32 = ts.0.into();
v.into()
}
}