use crate::{
ack, connection, endpoint, event,
event::IntoEvent,
inet::{SocketAddressV4, SocketAddressV6, Unspecified},
stateless_reset,
stream::{StreamId, StreamType},
varint::VarInt,
};
use core::{mem::size_of, time::Duration};
use s2n_codec::{
decoder_invariant, decoder_value, DecoderBuffer, DecoderBufferMut, DecoderBufferMutResult,
DecoderBufferResult, DecoderError, DecoderValue, DecoderValueMut, Encoder, EncoderValue,
};
#[cfg(test)]
mod tests;
pub trait TransportParameter: Sized {
const ID: TransportParameterId;
const ENABLED: bool = true;
type CodecValue: EncoderValue;
fn from_codec_value(value: Self::CodecValue) -> Self;
fn try_into_codec_value(&self) -> Option<&Self::CodecValue>;
fn default_value() -> Self;
#[cfg(feature = "alloc")]
fn append_to_buffer(&self, buffer: &mut alloc::vec::Vec<u8>) {
let original_size = buffer.len();
let new_parameter_size = TransportParameterCodec(self).encoding_size();
buffer.resize(original_size + new_parameter_size, 0);
let mut buffer = s2n_codec::EncoderBuffer::new(buffer);
buffer.set_position(original_size);
buffer.encode(&TransportParameterCodec(self));
}
}
pub trait TransportParameterValidator: Sized {
fn validate(self) -> Result<Self, DecoderError> {
Ok(self)
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct ZeroRttParameters {
pub active_connection_id_limit: VarInt,
pub initial_max_data: VarInt,
pub initial_max_stream_data_bidi_local: VarInt,
pub initial_max_stream_data_bidi_remote: VarInt,
pub initial_max_stream_data_uni: VarInt,
pub initial_max_streams_bidi: VarInt,
pub initial_max_streams_uni: VarInt,
pub max_datagram_frame_size: VarInt,
}
impl<
OriginalDestinationConnectionId,
StatelessResetToken,
PreferredAddress,
RetrySourceConnectionId,
>
TransportParameters<
OriginalDestinationConnectionId,
StatelessResetToken,
PreferredAddress,
RetrySourceConnectionId,
>
{
pub fn zero_rtt_parameters(&self) -> ZeroRttParameters {
let Self {
active_connection_id_limit,
initial_max_data,
initial_max_stream_data_bidi_local,
initial_max_stream_data_bidi_remote,
initial_max_stream_data_uni,
initial_max_streams_bidi,
initial_max_streams_uni,
max_datagram_frame_size,
..
} = self;
ZeroRttParameters {
active_connection_id_limit: **active_connection_id_limit,
initial_max_data: **initial_max_data,
initial_max_stream_data_bidi_local: **initial_max_stream_data_bidi_local,
initial_max_stream_data_bidi_remote: **initial_max_stream_data_bidi_remote,
initial_max_stream_data_uni: **initial_max_stream_data_uni,
initial_max_streams_bidi: **initial_max_streams_bidi,
initial_max_streams_uni: **initial_max_streams_uni,
max_datagram_frame_size: **max_datagram_frame_size,
}
}
}
decoder_value!(
impl<'a> ClientTransportParameters {
fn decode(buffer: Buffer) -> Result<Self> {
let len = buffer.len();
let (slice, buffer) = buffer.decode_slice(len)?;
let parameters = Self::decode_parameters(slice.peek())?;
Ok((parameters, buffer))
}
}
);
decoder_value!(
impl<'a> ServerTransportParameters {
fn decode(buffer: Buffer) -> Result<Self> {
let len = buffer.len();
let (slice, buffer) = buffer.decode_slice(len)?;
let parameters = Self::decode_parameters(slice.peek())?;
Ok((parameters, buffer))
}
}
);
type TransportParameterId = VarInt;
type TransportParameterLength = VarInt;
struct TransportParameterCodec<T>(T);
impl<'a, T: TransportParameter> DecoderValue<'a> for TransportParameterCodec<T>
where
T::CodecValue: DecoderValue<'a>,
{
fn decode(buffer: DecoderBuffer<'a>) -> DecoderBufferResult<'a, Self> {
let (value, buffer) = buffer.decode_with_len_prefix::<TransportParameterLength, _>()?;
Ok((Self(T::from_codec_value(value)), buffer))
}
}
impl<'a, T: TransportParameter> DecoderValueMut<'a> for TransportParameterCodec<T>
where
T::CodecValue: DecoderValueMut<'a>,
{
fn decode_mut(buffer: DecoderBufferMut<'a>) -> DecoderBufferMutResult<'a, Self> {
let (value, buffer) = buffer.decode_with_len_prefix::<TransportParameterLength, _>()?;
Ok((Self(T::from_codec_value(value)), buffer))
}
}
impl<T: TransportParameter> EncoderValue for TransportParameterCodec<&T>
where
T::CodecValue: EncoderValue,
{
fn encode<E: Encoder>(&self, buffer: &mut E) {
if let Some(value) = self.0.try_into_codec_value() {
buffer.encode(&T::ID);
buffer.encode_with_len_prefix::<TransportParameterLength, _>(value);
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct ValidationError(pub(crate) &'static str);
const MAX_ENCODABLE_VALUE: ValidationError =
ValidationError("provided value exceeds maximum encodable value");
impl core::fmt::Display for ValidationError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<DecoderError> for ValidationError {
fn from(error: DecoderError) -> Self {
ValidationError(error.into())
}
}
impl From<crate::varint::VarIntError> for ValidationError {
fn from(_: crate::varint::VarIntError) -> Self {
MAX_ENCODABLE_VALUE
}
}
impl From<core::num::TryFromIntError> for ValidationError {
fn from(_: core::num::TryFromIntError) -> Self {
MAX_ENCODABLE_VALUE
}
}
impl From<core::convert::Infallible> for ValidationError {
fn from(_: core::convert::Infallible) -> Self {
MAX_ENCODABLE_VALUE
}
}
impl core::error::Error for ValidationError {}
macro_rules! transport_parameter {
($name:ident($encodable_type:ty), $tag:expr) => {
transport_parameter!(
$name($encodable_type),
$tag,
<$encodable_type as Default>::default()
);
};
($name:ident($encodable_type:ty), $tag:expr, $default:expr) => {
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct $name($encodable_type);
impl Default for $name {
fn default() -> Self {
Self($default)
}
}
impl $name {
pub fn new<T: TryInto<$encodable_type>>(value: T) -> Option<Self> {
value
.try_into()
.ok()
.map(Self)
.and_then(|value| value.validate().ok())
}
}
impl TryFrom<$encodable_type> for $name {
type Error = ValidationError;
fn try_from(value: $encodable_type) -> Result<Self, Self::Error> {
Self(value).validate().map_err(|err| err.into())
}
}
impl TransportParameter for $name {
type CodecValue = $encodable_type;
const ID: TransportParameterId = TransportParameterId::from_u8($tag);
fn from_codec_value(value: Self::CodecValue) -> Self {
Self(value)
}
fn try_into_codec_value(&self) -> Option<&Self::CodecValue> {
if self.0 == $default {
None
} else {
Some(&self.0)
}
}
fn default_value() -> Self {
Self($default)
}
}
impl core::ops::Deref for $name {
type Target = $encodable_type;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl PartialEq<$encodable_type> for $name {
fn eq(&self, value: &$encodable_type) -> bool {
self.0.eq(value)
}
}
impl PartialOrd<$encodable_type> for $name {
fn partial_cmp(&self, value: &$encodable_type) -> Option<core::cmp::Ordering> {
self.0.partial_cmp(value)
}
}
};
}
macro_rules! varint_transport_parameter {
($name:ident, $tag:expr $(, $default:expr)?) => {
transport_parameter!($name(VarInt), $tag $(, $default)?);
impl TryFrom<u64> for $name {
type Error = ValidationError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
let value = VarInt::new(value)?;
Self::try_from(value)
}
}
impl $name {
pub const fn as_varint(self) -> VarInt {
self.0
}
}
};
}
macro_rules! duration_transport_parameter {
($name:ident, $tag:expr $(, $default:expr)?) => {
transport_parameter!($name(VarInt), $tag $(, $default)?);
impl $name {
pub const fn as_duration(self) -> Duration {
Duration::from_millis(self.0.as_u64())
}
}
impl TryFrom<Duration> for $name {
type Error = ValidationError;
fn try_from(value: Duration) -> Result<Self, Self::Error> {
let value: VarInt = value.as_millis().try_into()?;
value.try_into()
}
}
impl From<$name> for Duration {
fn from(value: $name) -> Self {
value.as_duration()
}
}
};
}
macro_rules! optional_transport_parameter {
($ty:ty) => {
impl TransportParameter for Option<$ty> {
type CodecValue = $ty;
const ID: TransportParameterId = <$ty as TransportParameter>::ID;
fn from_codec_value(value: Self::CodecValue) -> Self {
Some(value)
}
fn try_into_codec_value(&self) -> Option<&Self::CodecValue> {
self.as_ref()
}
fn default_value() -> Self {
None
}
}
impl TransportParameterValidator for Option<$ty> {
fn validate(self) -> Result<Self, DecoderError> {
if let Some(value) = self {
Ok(Some(value.validate()?))
} else {
Ok(None)
}
}
}
};
}
macro_rules! connection_id_parameter {
($name:ident, $id_type:ident, $tag:expr) => {
transport_parameter!($name(connection::$id_type), $tag);
impl TransportParameterValidator for $name {}
impl TryFrom<&[u8]> for $name {
type Error = crate::connection::id::Error;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
Ok(Self(connection::$id_type::try_from(value)?))
}
}
decoder_value!(
impl<'a> $name {
fn decode(buffer: Buffer) -> Result<Self> {
let (connection_id, buffer) = buffer.decode()?;
Ok((Self(connection_id), buffer))
}
}
);
impl EncoderValue for $name {
fn encode<E: Encoder>(&self, encoder: &mut E) {
self.0.encode(encoder)
}
}
};
}
connection_id_parameter!(OriginalDestinationConnectionId, InitialId, 0x00);
optional_transport_parameter!(OriginalDestinationConnectionId);
transport_parameter!(MaxIdleTimeout(VarInt), 0x01, VarInt::from_u8(0));
impl MaxIdleTimeout {
pub const RECOMMENDED: Self = Self(VarInt::from_u32(30_000));
pub fn load_peer(&mut self, peer: &Self) {
match (self.as_duration(), peer.as_duration()) {
(Some(current_duration), Some(peer_duration)) => {
if current_duration > peer_duration {
*self = *peer;
}
}
(Some(_), None) => {
}
(None, Some(_)) => {
*self = *peer;
}
(None, None) => {
}
}
}
pub fn as_duration(&self) -> Option<Duration> {
let duration = Duration::from_millis(self.0.as_u64());
if duration == Duration::from_secs(0) {
None
} else {
Some(duration)
}
}
}
impl TransportParameterValidator for MaxIdleTimeout {}
impl TryFrom<Duration> for MaxIdleTimeout {
type Error = ValidationError;
fn try_from(value: Duration) -> Result<Self, Self::Error> {
let value: VarInt = value.as_millis().try_into()?;
value.try_into()
}
}
impl From<MaxIdleTimeout> for Duration {
fn from(value: MaxIdleTimeout) -> Self {
value.as_duration().unwrap_or_default()
}
}
optional_transport_parameter!(stateless_reset::Token);
impl TransportParameter for stateless_reset::Token {
type CodecValue = Self;
const ID: TransportParameterId = TransportParameterId::from_u8(0x02);
fn from_codec_value(value: Self) -> Self {
value
}
fn try_into_codec_value(&self) -> Option<&Self> {
Some(self)
}
fn default_value() -> Self {
Self::ZEROED
}
}
impl TransportParameterValidator for stateless_reset::Token {}
transport_parameter!(MaxUdpPayloadSize(VarInt), 0x03, VarInt::from_u16(65527));
impl TransportParameterValidator for MaxUdpPayloadSize {
fn validate(self) -> Result<Self, DecoderError> {
decoder_invariant!(
(1200..=65527).contains(&*self.0),
"max_udp_payload_size should be within 1200 and 65527 bytes"
);
Ok(self)
}
}
impl TryFrom<u16> for MaxUdpPayloadSize {
type Error = ValidationError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
let value: VarInt = value.into();
value.try_into()
}
}
varint_transport_parameter!(InitialMaxData, 0x04);
pub const fn compute_data_window(mbps: u64, rtt: Duration, rtt_count: u64) -> VarInt {
let mut window = mbps;
window *= 125;
window *= rtt.as_millis() as u64;
window *= rtt_count;
VarInt::from_u32(window as u32)
}
impl InitialMaxData {
pub const RECOMMENDED: Self = Self(compute_data_window(150, Duration::from_millis(100), 2));
}
impl TransportParameterValidator for InitialMaxData {}
varint_transport_parameter!(InitialMaxStreamDataBidiLocal, 0x05);
impl InitialMaxStreamDataBidiLocal {
pub const RECOMMENDED: Self = Self(InitialMaxData::RECOMMENDED.0);
}
impl TransportParameterValidator for InitialMaxStreamDataBidiLocal {}
varint_transport_parameter!(InitialMaxStreamDataBidiRemote, 0x06);
impl InitialMaxStreamDataBidiRemote {
pub const RECOMMENDED: Self = Self(InitialMaxData::RECOMMENDED.0);
}
impl TransportParameterValidator for InitialMaxStreamDataBidiRemote {}
varint_transport_parameter!(InitialMaxStreamDataUni, 0x07);
impl InitialMaxStreamDataUni {
pub const RECOMMENDED: Self = Self(InitialMaxData::RECOMMENDED.0);
}
impl TransportParameterValidator for InitialMaxStreamDataUni {}
varint_transport_parameter!(InitialMaxStreamsBidi, 0x08);
impl InitialMaxStreamsBidi {
pub const RECOMMENDED: Self = Self(VarInt::from_u8(100));
}
impl TransportParameterValidator for InitialMaxStreamsBidi {
fn validate(self) -> Result<Self, DecoderError> {
decoder_invariant!(
*self <= 2u64.pow(60),
"initial_max_streams_bidi cannot be greater than 2^60"
);
Ok(self)
}
}
varint_transport_parameter!(InitialMaxStreamsUni, 0x09);
impl InitialMaxStreamsUni {
pub const RECOMMENDED: Self = Self(VarInt::from_u8(100));
}
impl TransportParameterValidator for InitialMaxStreamsUni {
fn validate(self) -> Result<Self, DecoderError> {
decoder_invariant!(
*self <= 2u64.pow(60),
"initial_max_streams_uni cannot be greater than 2^60"
);
Ok(self)
}
}
transport_parameter!(MaxDatagramFrameSize(VarInt), 0x20, VarInt::from_u16(0));
impl MaxDatagramFrameSize {
pub const RECOMMENDED: u64 = 65535;
pub const DEFAULT: Self = Self(VarInt::from_u16(0));
}
impl TransportParameterValidator for MaxDatagramFrameSize {
fn validate(self) -> Result<Self, DecoderError> {
Ok(self)
}
}
impl TryFrom<u64> for MaxDatagramFrameSize {
type Error = ValidationError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
let value = VarInt::new(value)?;
Self::try_from(value)
}
}
transport_parameter!(AckDelayExponent(u8), 0x0a, 3);
impl AckDelayExponent {
pub const RECOMMENDED: Self = Self(3);
pub const fn as_u8(self) -> u8 {
self.0
}
}
impl TransportParameterValidator for AckDelayExponent {
fn validate(self) -> Result<Self, DecoderError> {
decoder_invariant!(self.0 <= 20, "ack_delay_exponent cannot be greater than 20");
Ok(self)
}
}
duration_transport_parameter!(MaxAckDelay, 0x0b, VarInt::from_u8(25));
impl MaxAckDelay {
pub const RECOMMENDED: Self = Self(VarInt::from_u8(25));
}
impl TransportParameterValidator for MaxAckDelay {
fn validate(self) -> Result<Self, DecoderError> {
decoder_invariant!(
*self.0 <= 2u64.pow(14),
"max_ack_delay cannot be greater than 2^14"
);
Ok(self)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum MigrationSupport {
#[default]
Enabled,
Disabled,
}
impl MigrationSupport {
pub const RECOMMENDED: Self = Self::Enabled;
}
impl TransportParameter for MigrationSupport {
type CodecValue = ();
const ID: TransportParameterId = TransportParameterId::from_u8(0x0c);
fn from_codec_value(_value: ()) -> Self {
MigrationSupport::Disabled
}
fn try_into_codec_value(&self) -> Option<&()> {
if let MigrationSupport::Disabled = self {
Some(&())
} else {
None
}
}
fn default_value() -> Self {
Self::default()
}
}
impl TransportParameterValidator for MigrationSupport {}
optional_transport_parameter!(PreferredAddress);
type CidLength = u8;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PreferredAddress {
pub ipv4_address: Option<SocketAddressV4>,
pub ipv6_address: Option<SocketAddressV6>,
pub connection_id: crate::connection::UnboundedId,
pub stateless_reset_token: crate::stateless_reset::Token,
}
impl Unspecified for PreferredAddress {
fn is_unspecified(&self) -> bool {
self.ipv4_address
.as_ref()
.map(Unspecified::is_unspecified)
.unwrap_or(true)
&& self
.ipv6_address
.as_ref()
.map(Unspecified::is_unspecified)
.unwrap_or(true)
}
}
impl TransportParameter for PreferredAddress {
type CodecValue = Self;
const ID: TransportParameterId = TransportParameterId::from_u8(0x0d);
fn from_codec_value(value: Self) -> Self {
value
}
fn try_into_codec_value(&self) -> Option<&Self> {
Some(self)
}
fn default_value() -> Self {
unimplemented!(
"PreferredAddress is an optional transport parameter, so the default is None"
)
}
}
impl TransportParameterValidator for PreferredAddress {
fn validate(self) -> Result<Self, DecoderError> {
decoder_invariant!(
!self.is_unspecified(),
"at least one address needs to be specified"
);
Ok(self)
}
}
decoder_value!(
impl<'a> PreferredAddress {
fn decode(buffer: Buffer) -> Result<Self> {
let (ipv4_address, buffer) = buffer.decode::<SocketAddressV4>()?;
let ipv4_address = ipv4_address.filter_unspecified();
let (ipv6_address, buffer) = buffer.decode::<SocketAddressV6>()?;
let ipv6_address = ipv6_address.filter_unspecified();
let (connection_id, buffer) = buffer.decode_with_len_prefix::<CidLength, _>()?;
let (stateless_reset_token, buffer) = buffer.decode()?;
let preferred_address = Self {
ipv4_address,
ipv6_address,
connection_id,
stateless_reset_token,
};
Ok((preferred_address, buffer))
}
}
);
impl EncoderValue for PreferredAddress {
fn encode<E: Encoder>(&self, buffer: &mut E) {
if let Some(ip) = self.ipv4_address.as_ref() {
buffer.encode(ip);
} else {
buffer.write_repeated(size_of::<SocketAddressV4>(), 0);
}
if let Some(ip) = self.ipv6_address.as_ref() {
buffer.encode(ip);
} else {
buffer.write_repeated(size_of::<SocketAddressV6>(), 0);
}
buffer.encode_with_len_prefix::<CidLength, _>(&self.connection_id);
buffer.encode(&self.stateless_reset_token);
}
}
varint_transport_parameter!(ActiveConnectionIdLimit, 0x0e, VarInt::from_u8(2));
impl ActiveConnectionIdLimit {
pub const RECOMMENDED: Self = Self(VarInt::from_u8(2));
}
impl TransportParameterValidator for ActiveConnectionIdLimit {
fn validate(self) -> Result<Self, DecoderError> {
decoder_invariant!(
*self.0 >= 2,
"active_connection_id_limit must be at least 2"
);
Ok(self)
}
}
impl ActiveConnectionIdLimit {
pub fn is_default(self) -> bool {
self == Self::default_value()
}
}
connection_id_parameter!(InitialSourceConnectionId, UnboundedId, 0x0f);
optional_transport_parameter!(InitialSourceConnectionId);
impl From<connection::id::LocalId> for InitialSourceConnectionId {
fn from(id: connection::id::LocalId) -> Self {
InitialSourceConnectionId(id.into())
}
}
connection_id_parameter!(RetrySourceConnectionId, LocalId, 0x10);
optional_transport_parameter!(RetrySourceConnectionId);
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Eq, Ord)]
pub struct DcSupportedVersions {
len: u8,
versions: [u32; DC_SUPPORTED_VERSIONS_MAX_LEN as usize],
}
const DC_SUPPORTED_VERSIONS_MAX_LEN: u8 = 4;
impl DcSupportedVersions {
pub fn for_client<I: IntoIterator<Item = u32>>(supported_versions: I) -> Self {
let mut versions = [0; DC_SUPPORTED_VERSIONS_MAX_LEN as usize];
let mut len = 0;
for (index, version) in supported_versions.into_iter().enumerate() {
versions[index] = version;
len += 1;
debug_assert!(
len <= DC_SUPPORTED_VERSIONS_MAX_LEN,
"Only {DC_SUPPORTED_VERSIONS_MAX_LEN} supported versions are supported"
);
ensure!(len <= DC_SUPPORTED_VERSIONS_MAX_LEN, break);
}
DcSupportedVersions { len, versions }
}
pub fn for_server(supported_version: u32) -> Self {
DcSupportedVersions {
len: 1,
versions: [supported_version, 0, 0, 0],
}
}
pub fn selected_version(&self) -> Result<Option<u32>, DecoderError> {
match self.len {
0 => Ok(None),
1 => Ok(Some(self.versions[0])),
_ => Err(DecoderError::InvariantViolation(
"multiple versions selected by the server",
)),
}
}
}
impl TransportParameter for DcSupportedVersions {
const ID: TransportParameterId = TransportParameterId::from_u32(0xdc0000);
type CodecValue = Self;
fn from_codec_value(value: Self::CodecValue) -> Self {
value
}
fn try_into_codec_value(&self) -> Option<&Self::CodecValue> {
if *self == Self::default_value() {
None
} else {
Some(self)
}
}
fn default_value() -> Self {
Self::default()
}
}
impl EncoderValue for DcSupportedVersions {
fn encode<E: Encoder>(&self, buffer: &mut E) {
for &version in self.versions.iter().take(self.len as usize) {
VarInt::from_u32(version).encode(buffer);
}
}
}
decoder_value!(
impl<'a> DcSupportedVersions {
fn decode(buffer: Buffer) -> Result<Self> {
let mut versions = [0; DC_SUPPORTED_VERSIONS_MAX_LEN as usize];
let mut len = 0;
let mut buffer = buffer;
while !buffer.is_empty() {
let (version, remaining) = buffer.decode::<VarInt>()?;
buffer = remaining;
decoder_invariant!(
version.as_u64() <= u32::MAX as u64,
"the largest supported version is u32::MAX"
);
versions[len] = version.as_u64() as u32;
len += 1;
ensure!(len < DC_SUPPORTED_VERSIONS_MAX_LEN as usize, break);
}
let remaining_capacity = buffer.len();
let buffer = buffer.skip(remaining_capacity)?;
Ok((
Self {
len: len as u8,
versions,
},
buffer,
))
}
}
);
impl TransportParameterValidator for DcSupportedVersions {}
impl<'a> IntoIterator for &'a DcSupportedVersions {
type Item = &'a u32;
type IntoIter = core::slice::Iter<'a, u32>;
fn into_iter(self) -> Self::IntoIter {
self.versions[..self.len as usize].iter()
}
}
impl<'a> IntoEvent<&'a [u32]> for &'a DcSupportedVersions {
fn into_event(self) -> &'a [u32] {
&self.versions[..self.len as usize]
}
}
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub enum MtuProbingCompleteSupport {
Enabled,
#[default]
Disabled,
}
impl TransportParameter for MtuProbingCompleteSupport {
type CodecValue = ();
const ID: TransportParameterId = TransportParameterId::from_u32(0xdc0002);
fn from_codec_value(_value: ()) -> Self {
MtuProbingCompleteSupport::Enabled
}
fn try_into_codec_value(&self) -> Option<&()> {
if let MtuProbingCompleteSupport::Enabled = self {
Some(&())
} else {
None
}
}
fn default_value() -> Self {
Self::default()
}
}
impl TransportParameterValidator for MtuProbingCompleteSupport {}
impl IntoEvent<bool> for MtuProbingCompleteSupport {
fn into_event(self) -> bool {
matches!(self, MtuProbingCompleteSupport::Enabled)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct InitialFlowControlLimits {
pub stream_limits: InitialStreamLimits,
pub max_data: VarInt,
pub max_open_remote_bidirectional_streams: VarInt,
pub max_open_remote_unidirectional_streams: VarInt,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct InitialStreamLimits {
pub max_data_bidi_local: VarInt,
pub max_data_bidi_remote: VarInt,
pub max_data_uni: VarInt,
}
impl InitialStreamLimits {
pub fn max_data(&self, local_endpoint_type: endpoint::Type, stream_id: StreamId) -> VarInt {
match (stream_id.initiator(), stream_id.stream_type()) {
(endpoint_type, StreamType::Bidirectional) if endpoint_type == local_endpoint_type => {
self.max_data_bidi_local
}
(_, StreamType::Bidirectional) => self.max_data_bidi_remote,
(_, StreamType::Unidirectional) => self.max_data_uni,
}
}
}
pub struct DatagramLimits {
pub max_datagram_payload: u64,
}
impl<
OriginalDestinationConnectionId,
StatelessResetToken,
PreferredAddress,
RetrySourceConnectionId,
>
TransportParameters<
OriginalDestinationConnectionId,
StatelessResetToken,
PreferredAddress,
RetrySourceConnectionId,
>
{
pub fn flow_control_limits(&self) -> InitialFlowControlLimits {
let Self {
initial_max_data,
initial_max_streams_bidi,
initial_max_streams_uni,
..
} = self;
InitialFlowControlLimits {
stream_limits: self.stream_limits(),
max_data: **initial_max_data,
max_open_remote_bidirectional_streams: **initial_max_streams_bidi,
max_open_remote_unidirectional_streams: **initial_max_streams_uni,
}
}
pub fn stream_limits(&self) -> InitialStreamLimits {
let Self {
initial_max_stream_data_bidi_local,
initial_max_stream_data_bidi_remote,
initial_max_stream_data_uni,
..
} = self;
InitialStreamLimits {
max_data_bidi_local: **initial_max_stream_data_bidi_local,
max_data_bidi_remote: **initial_max_stream_data_bidi_remote,
max_data_uni: **initial_max_stream_data_uni,
}
}
pub fn ack_settings(&self) -> ack::Settings {
let Self {
max_ack_delay,
ack_delay_exponent,
..
} = self;
ack::Settings {
max_ack_delay: max_ack_delay.as_duration(),
ack_delay_exponent: **ack_delay_exponent,
..Default::default()
}
}
pub fn datagram_limits(&self) -> DatagramLimits {
let max_datagram_payload = self.max_datagram_frame_size.as_u64();
let max_udp_payload = self.max_udp_payload_size.as_u64();
DatagramLimits {
max_datagram_payload: max_datagram_payload.min(max_udp_payload),
}
}
}
mod disabled_parameter;
pub use disabled_parameter::DisabledParameter;
pub type ClientTransportParameters = TransportParameters<
DisabledParameter<OriginalDestinationConnectionId>,
DisabledParameter<stateless_reset::Token>,
DisabledParameter<PreferredAddress>,
DisabledParameter<RetrySourceConnectionId>,
>;
pub type ServerTransportParameters = TransportParameters<
Option<OriginalDestinationConnectionId>,
Option<stateless_reset::Token>,
Option<PreferredAddress>,
Option<RetrySourceConnectionId>,
>;
impl<'a> IntoEvent<event::builder::TransportParameters<'a>> for &'a ServerTransportParameters {
fn into_event(self) -> event::builder::TransportParameters<'a> {
event::builder::TransportParameters {
original_destination_connection_id: self
.original_destination_connection_id
.as_ref()
.map(|cid| cid.into_event()),
initial_source_connection_id: self
.initial_source_connection_id
.as_ref()
.map(|cid| cid.into_event()),
retry_source_connection_id: self
.retry_source_connection_id
.as_ref()
.map(|cid| cid.into_event()),
stateless_reset_token: self
.stateless_reset_token
.as_ref()
.map(|token| token.as_ref()),
preferred_address: self
.preferred_address
.as_ref()
.map(|addr| addr.into_event()),
migration_support: self.migration_support.into_event(),
max_idle_timeout: Duration::from(self.max_idle_timeout),
max_udp_payload_size: self.max_udp_payload_size.into_event(),
ack_delay_exponent: self.ack_delay_exponent.into_event(),
max_ack_delay: Duration::from(self.max_ack_delay),
active_connection_id_limit: self.active_connection_id_limit.into_event(),
initial_max_stream_data_bidi_local: self
.initial_max_stream_data_bidi_local
.into_event(),
initial_max_stream_data_bidi_remote: self
.initial_max_stream_data_bidi_remote
.into_event(),
initial_max_stream_data_uni: self.initial_max_stream_data_uni.into_event(),
initial_max_streams_bidi: self.initial_max_streams_bidi.into_event(),
initial_max_streams_uni: self.initial_max_streams_uni.into_event(),
max_datagram_frame_size: self.max_datagram_frame_size.into_event(),
dc_supported_versions: self.dc_supported_versions.into_event(),
mtu_probing_complete_support: self.mtu_probing_complete_support.into_event(),
}
}
}
impl<'a> IntoEvent<event::builder::TransportParameters<'a>> for &'a ClientTransportParameters {
fn into_event(self) -> event::builder::TransportParameters<'a> {
event::builder::TransportParameters {
original_destination_connection_id: None,
initial_source_connection_id: self
.initial_source_connection_id
.as_ref()
.map(|cid| cid.into_event()),
retry_source_connection_id: None,
stateless_reset_token: None,
preferred_address: None,
migration_support: self.migration_support.into_event(),
max_idle_timeout: Duration::from(self.max_idle_timeout),
max_udp_payload_size: self.max_udp_payload_size.into_event(),
ack_delay_exponent: self.ack_delay_exponent.into_event(),
max_ack_delay: Duration::from(self.max_ack_delay),
active_connection_id_limit: self.active_connection_id_limit.into_event(),
initial_max_stream_data_bidi_local: self
.initial_max_stream_data_bidi_local
.into_event(),
initial_max_stream_data_bidi_remote: self
.initial_max_stream_data_bidi_remote
.into_event(),
initial_max_stream_data_uni: self.initial_max_stream_data_uni.into_event(),
initial_max_streams_bidi: self.initial_max_streams_bidi.into_event(),
initial_max_streams_uni: self.initial_max_streams_uni.into_event(),
max_datagram_frame_size: self.max_datagram_frame_size.into_event(),
dc_supported_versions: self.dc_supported_versions.into_event(),
mtu_probing_complete_support: self.mtu_probing_complete_support.into_event(),
}
}
}
macro_rules! impl_transport_parameters {
(
pub struct TransportParameters <
$($server_param:ident),* $(,)? >
{ $($field:ident : $field_ty:ty),* $(,)? }
) => {
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct TransportParameters<$($server_param),*> {
$(
pub $field: $field_ty
),*
}
impl<$($server_param),*> Default for TransportParameters<$($server_param),*>
where
$(
$server_param: TransportParameter,
)*
{
fn default() -> Self {
Self {
$(
$field: TransportParameter::default_value(),
)*
}
}
}
impl<$($server_param),*> EncoderValue for TransportParameters<$($server_param),*>
where
$(
$server_param: TransportParameter,
$server_param::CodecValue: EncoderValue,
)*
{
fn encode<E: Encoder>(&self, buffer: &mut E) {
$(
buffer.encode(&TransportParameterCodec(&self.$field));
)*
}
}
impl<'a, $($server_param),*> TransportParameters<$($server_param),*>
where
$(
$server_param: TransportParameter + TransportParameterValidator,
$server_param::CodecValue: DecoderValue<'a>,
)*
{
fn decode_parameters(
mut buffer: DecoderBuffer<'a>
) -> Result<TransportParameters<$($server_param),*>, DecoderError> {
let mut parameters = Self::default();
#[derive(Default)]
struct UsedFields {
$(
$field: bool,
)*
}
let mut used_fields = UsedFields::default();
while !buffer.is_empty() {
let (tag, inner_buffer) = buffer.decode::<TransportParameterId>()?;
buffer = match tag {
$(
tag if tag == <$field_ty>::ID => {
s2n_codec::decoder_invariant!(
<$field_ty>::ENABLED,
concat!(stringify!($field), " is not allowed in this context")
);
s2n_codec::decoder_invariant!(
core::mem::replace(&mut used_fields.$field, true) == false,
concat!("duplicate value for ", stringify!($field))
);
let (value, inner_buffer) =
inner_buffer.decode::<TransportParameterCodec<$field_ty>>()?;
parameters.$field = value.0.validate()?;
inner_buffer
}
)*
_ => {
inner_buffer.skip_with_len_prefix::<TransportParameterLength>()?
}
}
}
Ok(parameters)
}
}
};
}
impl_transport_parameters!(
pub struct TransportParameters<
OriginalDestinationConnectionId,
StatelessResetToken,
PreferredAddress,
RetrySourceConnectionId,
> {
max_idle_timeout: MaxIdleTimeout,
max_udp_payload_size: MaxUdpPayloadSize,
initial_max_data: InitialMaxData,
initial_max_stream_data_bidi_local: InitialMaxStreamDataBidiLocal,
initial_max_stream_data_bidi_remote: InitialMaxStreamDataBidiRemote,
initial_max_stream_data_uni: InitialMaxStreamDataUni,
initial_max_streams_bidi: InitialMaxStreamsBidi,
initial_max_streams_uni: InitialMaxStreamsUni,
max_datagram_frame_size: MaxDatagramFrameSize,
ack_delay_exponent: AckDelayExponent,
max_ack_delay: MaxAckDelay,
migration_support: MigrationSupport,
active_connection_id_limit: ActiveConnectionIdLimit,
original_destination_connection_id: OriginalDestinationConnectionId,
stateless_reset_token: StatelessResetToken,
preferred_address: PreferredAddress,
initial_source_connection_id: Option<InitialSourceConnectionId>,
retry_source_connection_id: RetrySourceConnectionId,
dc_supported_versions: DcSupportedVersions,
mtu_probing_complete_support: MtuProbingCompleteSupport,
}
);
impl<
OriginalDestinationConnectionId,
StatelessResetToken,
PreferredAddress,
RetrySourceConnectionId,
>
TransportParameters<
OriginalDestinationConnectionId,
StatelessResetToken,
PreferredAddress,
RetrySourceConnectionId,
>
{
pub fn load_limits(&mut self, limits: &crate::connection::limits::Limits) {
macro_rules! load {
($from:ident, $to:ident) => {
self.$to = limits.$from;
};
}
load!(max_idle_timeout, max_idle_timeout);
load!(data_window, initial_max_data);
load!(
bidirectional_local_data_window,
initial_max_stream_data_bidi_local
);
load!(
bidirectional_remote_data_window,
initial_max_stream_data_bidi_remote
);
load!(unidirectional_data_window, initial_max_stream_data_uni);
load!(
max_open_remote_bidirectional_streams,
initial_max_streams_bidi
);
load!(
max_open_remote_unidirectional_streams,
initial_max_streams_uni
);
load!(max_ack_delay, max_ack_delay);
load!(ack_delay_exponent, ack_delay_exponent);
load!(max_active_connection_ids, active_connection_id_limit);
load!(max_datagram_frame_size, max_datagram_frame_size);
load!(migration_support, migration_support);
}
}