use crate::{frame::ExtensionTag, stateless_reset, varint::VarInt};
use s2n_codec::{
decoder_invariant,
zerocopy::{FromBytes as _, IntoBytes as _},
DecoderError, Encoder, EncoderValue,
};
const TAG: VarInt = VarInt::from_u32(0xdc0000);
const MAX_STATELESS_RESET_TOKEN_COUNT: usize = 4092;
macro_rules! dc_stateless_reset_tokens_tag {
() => {
0xdc0000u64
};
}
#[derive(Debug, PartialEq, Eq, zerocopy::Immutable)]
pub struct DcStatelessResetTokens<'a> {
stateless_reset_tokens: &'a [stateless_reset::Token],
}
impl<'a> DcStatelessResetTokens<'a> {
pub const fn tag(&self) -> ExtensionTag {
TAG
}
pub fn new(stateless_reset_tokens: &'a [stateless_reset::Token]) -> Result<Self, &'static str> {
ensure!(
!stateless_reset_tokens.is_empty(),
Err("at least one stateless reset token is required")
);
ensure!(
stateless_reset_tokens.len() <= MAX_STATELESS_RESET_TOKEN_COUNT,
Err("too many stateless reset tokens")
);
Ok(Self {
stateless_reset_tokens,
})
}
}
impl<'a> IntoIterator for DcStatelessResetTokens<'a> {
type Item = &'a stateless_reset::Token;
type IntoIter = core::slice::Iter<'a, stateless_reset::Token>;
fn into_iter(self) -> Self::IntoIter {
self.stateless_reset_tokens.iter()
}
}
macro_rules! impl_decode_parameterized {
($slice_from_prefix:ident, $buffer:ident) => {{
let (count, buffer) = $buffer.decode::<VarInt>()?;
decoder_invariant!(
count > VarInt::ZERO,
"at least one stateless token must be supplied"
);
decoder_invariant!(
count <= MAX_STATELESS_RESET_TOKEN_COUNT,
"too many stateless reset tokens"
);
let count: usize = count
.try_into()
.expect("MAX_STATELESS_RESET_TOKEN_COUNT fits in usize");
let buffer = buffer.into_less_safe_slice();
let (stateless_reset_tokens, remaining) =
<[stateless_reset::Token]>::$slice_from_prefix(buffer, count)
.map_err(|_| DecoderError::InvariantViolation("invalid encoding"))?;
let frame = DcStatelessResetTokens {
stateless_reset_tokens,
};
Ok((frame, remaining.into()))
}};
}
impl<'a> ::s2n_codec::DecoderParameterizedValue<'a> for DcStatelessResetTokens<'a> {
type Parameter = ExtensionTag;
#[inline]
fn decode_parameterized(
_tag: Self::Parameter,
buffer: ::s2n_codec::DecoderBuffer<'a>,
) -> ::s2n_codec::DecoderBufferResult<'a, Self> {
impl_decode_parameterized!(ref_from_prefix_with_elems, buffer)
}
}
impl<'a> ::s2n_codec::DecoderParameterizedValueMut<'a> for DcStatelessResetTokens<'a> {
type Parameter = ExtensionTag;
#[inline]
fn decode_parameterized_mut(
_tag: Self::Parameter,
buffer: ::s2n_codec::DecoderBufferMut<'a>,
) -> ::s2n_codec::DecoderBufferMutResult<'a, Self> {
impl_decode_parameterized!(mut_from_prefix_with_elems, buffer)
}
}
impl EncoderValue for DcStatelessResetTokens<'_> {
fn encode<E: Encoder>(&self, buffer: &mut E) {
buffer.encode(&TAG);
let count =
self.stateless_reset_tokens.len().try_into().expect(
"count is limited to MAX_STATELESS_RESET_TOKEN_COUNT, which fits in VarInt",
);
buffer.encode::<VarInt>(&count);
buffer.encode(&self.stateless_reset_tokens.as_bytes());
}
}
#[cfg(test)]
mod tests {
use crate::{
frame::{
dc_stateless_reset_tokens::{MAX_STATELESS_RESET_TOKEN_COUNT, TAG},
DcStatelessResetTokens, ExtensionTag,
},
stateless_reset,
};
use s2n_codec::{DecoderBuffer, DecoderParameterizedValue, EncoderValue};
#[test]
fn round_trip() {
let tokens: Vec<stateless_reset::Token> = vec![
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].into(),
[7, 7, 7, 3, 3, 3, 4, 4, 4, 8, 8, 8, 9, 9, 9, 9].into(),
];
let frame = DcStatelessResetTokens::new(tokens.as_slice()).unwrap();
let encoded = frame.encode_to_vec();
let buffer = DecoderBuffer::new(encoded.as_slice());
let (tag, buffer) = buffer.decode::<ExtensionTag>().expect("decoding succeeds");
assert_eq!(TAG, tag);
let (frame, remaining) =
DcStatelessResetTokens::decode_parameterized(TAG, buffer).expect("decoding succeeds");
assert!(remaining.is_empty());
assert_eq!(tokens.len(), frame.stateless_reset_tokens.len());
for (index, &token) in frame.into_iter().enumerate() {
assert_eq!(tokens[index], token);
}
}
#[test]
fn invalid_token_size() {
let frame = DcStatelessResetTokens {
stateless_reset_tokens: &[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].into()],
};
let mut encoded = frame.encode_to_vec();
encoded.truncate(encoded.len() - 1);
let buffer = DecoderBuffer::new(encoded.as_slice());
let (tag, buffer) = buffer.decode::<ExtensionTag>().expect("decoding succeeds");
assert_eq!(TAG, tag);
assert!(DcStatelessResetTokens::decode_parameterized(TAG, buffer).is_err());
}
#[test]
fn zero_tokens() {
let frame = DcStatelessResetTokens {
stateless_reset_tokens: &[],
};
let encoded = frame.encode_to_vec();
let buffer = DecoderBuffer::new(encoded.as_slice());
let (tag, buffer) = buffer.decode::<ExtensionTag>().expect("decoding succeeds");
assert_eq!(TAG, tag);
assert!(DcStatelessResetTokens::decode_parameterized(TAG, buffer).is_err());
assert!(DcStatelessResetTokens::new(&[]).is_err());
}
#[test]
fn maximum_sized_frame() {
let tokens: Vec<stateless_reset::Token> =
vec![stateless_reset::token::testing::TEST_TOKEN_1; MAX_STATELESS_RESET_TOKEN_COUNT];
let frame = DcStatelessResetTokens::new(tokens.as_slice()).unwrap();
let encoded = frame.encode_to_vec();
let buffer = DecoderBuffer::new(encoded.as_slice());
let (tag, buffer) = buffer.decode::<ExtensionTag>().expect("decoding succeeds");
assert_eq!(TAG, tag);
let (frame, remaining) =
DcStatelessResetTokens::decode_parameterized(TAG, buffer).expect("decoding succeeds");
assert!(remaining.is_empty());
assert_eq!(tokens.len(), frame.stateless_reset_tokens.len());
}
#[test]
fn too_many_tokens() {
let frame = DcStatelessResetTokens {
stateless_reset_tokens: &[stateless_reset::token::testing::TEST_TOKEN_1;
MAX_STATELESS_RESET_TOKEN_COUNT + 1],
};
let encoded = frame.encode_to_vec();
let buffer = DecoderBuffer::new(encoded.as_slice());
let (tag, buffer) = buffer.decode::<ExtensionTag>().expect("decoding succeeds");
assert_eq!(TAG, tag);
assert!(DcStatelessResetTokens::decode_parameterized(TAG, buffer).is_err());
assert!(DcStatelessResetTokens::new(
&[stateless_reset::token::testing::TEST_TOKEN_1; MAX_STATELESS_RESET_TOKEN_COUNT + 1]
)
.is_err());
}
}