use crate::bytes::{BufMut, Bytes, BytesMut};
use crate::net::atp::protocol::varint::{VarInt, VarIntError};
use crate::types::outcome::Outcome;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u64)]
pub enum TransportParameterId {
OriginalDestinationConnectionId = 0x00,
MaxIdleTimeout = 0x01,
StatelessResetToken = 0x02,
MaxUdpPayloadSize = 0x03,
InitialMaxData = 0x04,
InitialMaxStreamDataBidiLocal = 0x05,
InitialMaxStreamDataBidiRemote = 0x06,
InitialMaxStreamDataUni = 0x07,
InitialMaxStreamsBidi = 0x08,
InitialMaxStreamsUni = 0x09,
AckDelayExponent = 0x0a,
MaxAckDelay = 0x0b,
DisableActiveMigration = 0x0c,
PreferredAddress = 0x0d,
ActiveConnectionIdLimit = 0x0e,
InitialSourceConnectionId = 0x0f,
RetrySourceConnectionId = 0x10,
}
impl TransportParameterId {
pub fn to_varint(self) -> VarInt {
match VarInt::new(self as u64) {
Outcome::Ok(varint) => varint,
_ => panic!("transport parameter ID fits in varint"),
}
}
pub fn from_varint(varint: VarInt) -> Option<Self> {
match varint.value() {
0x00 => Some(Self::OriginalDestinationConnectionId),
0x01 => Some(Self::MaxIdleTimeout),
0x02 => Some(Self::StatelessResetToken),
0x03 => Some(Self::MaxUdpPayloadSize),
0x04 => Some(Self::InitialMaxData),
0x05 => Some(Self::InitialMaxStreamDataBidiLocal),
0x06 => Some(Self::InitialMaxStreamDataBidiRemote),
0x07 => Some(Self::InitialMaxStreamDataUni),
0x08 => Some(Self::InitialMaxStreamsBidi),
0x09 => Some(Self::InitialMaxStreamsUni),
0x0a => Some(Self::AckDelayExponent),
0x0b => Some(Self::MaxAckDelay),
0x0c => Some(Self::DisableActiveMigration),
0x0d => Some(Self::PreferredAddress),
0x0e => Some(Self::ActiveConnectionIdLimit),
0x0f => Some(Self::InitialSourceConnectionId),
0x10 => Some(Self::RetrySourceConnectionId),
_ => None,
}
}
pub fn is_required_for_client(self) -> bool {
match self {
Self::InitialMaxData
| Self::InitialMaxStreamDataBidiLocal
| Self::InitialMaxStreamDataBidiRemote
| Self::InitialMaxStreamDataUni
| Self::InitialMaxStreamsBidi
| Self::InitialMaxStreamsUni => true,
_ => false,
}
}
pub fn is_required_for_server(self) -> bool {
match self {
Self::InitialMaxData
| Self::InitialMaxStreamDataBidiLocal
| Self::InitialMaxStreamDataBidiRemote
| Self::InitialMaxStreamDataUni
| Self::InitialMaxStreamsBidi
| Self::InitialMaxStreamsUni => true,
_ => false,
}
}
pub fn is_forbidden_for_client(self) -> bool {
match self {
Self::StatelessResetToken
| Self::PreferredAddress
| Self::OriginalDestinationConnectionId
| Self::RetrySourceConnectionId => true,
_ => false,
}
}
pub fn is_forbidden_for_server(self) -> bool {
match self {
Self::OriginalDestinationConnectionId | Self::RetrySourceConnectionId => false,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TransportParameterValue {
VarInt(VarInt),
Bytes(Bytes),
Empty,
}
impl TransportParameterValue {
pub fn as_varint(&self) -> Option<VarInt> {
match self {
TransportParameterValue::VarInt(v) => Some(*v),
_ => None,
}
}
pub fn as_bytes(&self) -> Option<&Bytes> {
match self {
TransportParameterValue::Bytes(b) => Some(b),
_ => None,
}
}
pub fn is_empty(&self) -> bool {
matches!(self, TransportParameterValue::Empty)
}
pub fn encode<B: BufMut>(
&self,
parameter: TransportParameterId,
buf: &mut B,
) -> Result<(), TransportParameterError> {
match self {
TransportParameterValue::VarInt(v) => {
let mut temp = BytesMut::new();
match v.encode(&mut temp) {
Outcome::Ok(()) => {}
_ => {
return Err(TransportParameterError::InvalidParameterValue {
parameter,
value: 0,
reason: "VarInt encode failed".to_string(),
});
}
}
let len_varint = match VarInt::new(temp.len() as u64) {
Outcome::Ok(varint) => varint,
_ => {
return Err(TransportParameterError::InvalidParameterValue {
parameter,
value: temp.len() as u64,
reason: "Invalid length".to_string(),
});
}
};
let mut len_buf = BytesMut::new();
match len_varint.encode(&mut len_buf) {
Outcome::Ok(()) => buf.put_slice(&len_buf),
_ => {
return Err(TransportParameterError::InvalidParameterValue {
parameter,
value: 0,
reason: "Length varint encode failed".to_string(),
});
}
}
buf.put_slice(&temp);
}
TransportParameterValue::Bytes(bytes) => {
let len_varint = match VarInt::new(bytes.len() as u64) {
Outcome::Ok(varint) => varint,
_ => {
return Err(TransportParameterError::InvalidParameterValue {
parameter,
value: bytes.len() as u64,
reason: "Bytes length too large".to_string(),
});
}
};
let mut len_buf = BytesMut::new();
match len_varint.encode(&mut len_buf) {
Outcome::Ok(()) => buf.put_slice(&len_buf),
_ => {
return Err(TransportParameterError::InvalidParameterValue {
parameter,
value: 0,
reason: "Length varint encode failed".to_string(),
});
}
}
buf.put_slice(bytes);
}
TransportParameterValue::Empty => {
let zero_varint = match VarInt::new(0) {
Outcome::Ok(varint) => varint,
_ => {
return Err(TransportParameterError::InvalidParameterValue {
parameter,
value: 0,
reason: "Zero varint creation failed".to_string(),
});
}
};
let mut zero_buf = BytesMut::new();
match zero_varint.encode(&mut zero_buf) {
Outcome::Ok(()) => buf.put_slice(&zero_buf),
_ => {
return Err(TransportParameterError::InvalidParameterValue {
parameter,
value: 0,
reason: "Zero varint encode failed".to_string(),
});
}
}
}
}
Ok(())
}
pub fn decode(
buf: &mut BytesMut,
expected_type: TransportParameterValueType,
) -> Result<Self, TransportParameterError> {
let length = match VarInt::decode(buf) {
Outcome::Ok(Some(varint)) => varint,
Outcome::Ok(None) => return Err(TransportParameterError::UnexpectedEof),
_ => {
return Err(TransportParameterError::VarInt(
VarIntError::InvalidEncoding,
));
}
};
if buf.len() < length.value() as usize {
return Err(TransportParameterError::UnexpectedEof);
}
match expected_type {
TransportParameterValueType::VarInt => {
if length.value() == 0 {
return Err(TransportParameterError::InvalidParameterLength {
parameter: "varint parameter".to_string(),
expected_min: 1,
actual: 0,
});
}
let mut param_buf = buf.split_to(length.value() as usize);
let varint = match VarInt::decode(&mut param_buf) {
Outcome::Ok(Some(varint)) => varint,
Outcome::Ok(None) => return Err(TransportParameterError::UnexpectedEof),
_ => {
return Err(TransportParameterError::VarInt(
VarIntError::InvalidEncoding,
));
}
};
Ok(TransportParameterValue::VarInt(varint))
}
TransportParameterValueType::Bytes => {
let bytes = buf.split_to(length.value() as usize).freeze();
Ok(TransportParameterValue::Bytes(bytes))
}
TransportParameterValueType::Empty => {
if length.value() != 0 {
return Err(TransportParameterError::InvalidParameterLength {
parameter: "empty parameter".to_string(),
expected_min: 0,
actual: length.value() as usize,
});
}
Ok(TransportParameterValue::Empty)
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TransportParameterValueType {
VarInt,
Bytes,
Empty,
}
#[derive(Debug, Clone)]
pub struct TransportParameters {
known_parameters: HashMap<TransportParameterId, TransportParameterValue>,
unknown_parameters: HashMap<u64, Bytes>,
}
impl TransportParameters {
pub fn new() -> Self {
Self {
known_parameters: HashMap::new(),
unknown_parameters: HashMap::new(),
}
}
pub fn set_parameter(&mut self, id: TransportParameterId, value: TransportParameterValue) {
self.known_parameters.insert(id, value);
}
pub fn set_varint(
&mut self,
id: TransportParameterId,
value: u64,
) -> Result<(), TransportParameterError> {
let varint = match VarInt::new(value) {
Outcome::Ok(varint) => varint,
_ => {
return Err(TransportParameterError::InvalidParameterValue {
parameter: id,
value,
reason: "Invalid varint value".to_string(),
});
}
};
self.set_parameter(id, TransportParameterValue::VarInt(varint));
Ok(())
}
pub fn set_bytes(&mut self, id: TransportParameterId, value: Bytes) {
self.set_parameter(id, TransportParameterValue::Bytes(value));
}
pub fn set_empty(&mut self, id: TransportParameterId) {
self.set_parameter(id, TransportParameterValue::Empty);
}
pub fn get_parameter(&self, id: TransportParameterId) -> Option<&TransportParameterValue> {
self.known_parameters.get(&id)
}
pub fn get_varint(&self, id: TransportParameterId) -> Option<u64> {
self.get_parameter(id)?.as_varint().map(|v| v.value())
}
pub fn get_bytes(&self, id: TransportParameterId) -> Option<&Bytes> {
self.get_parameter(id)?.as_bytes()
}
pub fn has_empty(&self, id: TransportParameterId) -> bool {
self.get_parameter(id).is_some_and(|v| v.is_empty())
}
pub fn set_unknown_parameter(&mut self, id: u64, value: Bytes) {
self.unknown_parameters.insert(id, value);
}
pub fn get_unknown_parameter(&self, id: u64) -> Option<&Bytes> {
self.unknown_parameters.get(&id)
}
pub fn unknown_parameters(&self) -> &HashMap<u64, Bytes> {
&self.unknown_parameters
}
pub fn validate(&self, is_server: bool) -> Result<(), TransportParameterError> {
for ¶m in &[
TransportParameterId::InitialMaxData,
TransportParameterId::InitialMaxStreamDataBidiLocal,
TransportParameterId::InitialMaxStreamDataBidiRemote,
TransportParameterId::InitialMaxStreamDataUni,
TransportParameterId::InitialMaxStreamsBidi,
TransportParameterId::InitialMaxStreamsUni,
] {
if !self.known_parameters.contains_key(¶m) {
return Err(TransportParameterError::MissingRequiredParameter(param));
}
}
for ¶m in self.known_parameters.keys() {
if is_server && param.is_forbidden_for_server() {
return Err(TransportParameterError::ForbiddenParameter { param, is_server });
}
if !is_server && param.is_forbidden_for_client() {
return Err(TransportParameterError::ForbiddenParameter { param, is_server });
}
}
self.validate_parameter_values()?;
self.validate_parameter_combinations()?;
Ok(())
}
fn validate_parameter_values(&self) -> Result<(), TransportParameterError> {
if let Some(max_udp) = self.get_varint(TransportParameterId::MaxUdpPayloadSize) {
if max_udp < 1200 {
return Err(TransportParameterError::InvalidParameterValue {
parameter: TransportParameterId::MaxUdpPayloadSize,
value: max_udp,
reason: "must be at least 1200".to_string(),
});
}
}
if let Some(ack_exp) = self.get_varint(TransportParameterId::AckDelayExponent) {
if ack_exp > 20 {
return Err(TransportParameterError::InvalidParameterValue {
parameter: TransportParameterId::AckDelayExponent,
value: ack_exp,
reason: "must be <= 20".to_string(),
});
}
}
if let Some(max_ack) = self.get_varint(TransportParameterId::MaxAckDelay) {
if max_ack >= (1u64 << 14) {
return Err(TransportParameterError::InvalidParameterValue {
parameter: TransportParameterId::MaxAckDelay,
value: max_ack,
reason: "must be < 2^14 milliseconds".to_string(),
});
}
}
if let Some(conn_limit) = self.get_varint(TransportParameterId::ActiveConnectionIdLimit) {
if conn_limit < 2 {
return Err(TransportParameterError::InvalidParameterValue {
parameter: TransportParameterId::ActiveConnectionIdLimit,
value: conn_limit,
reason: "must be at least 2".to_string(),
});
}
}
if let Some(reset_token) = self.get_bytes(TransportParameterId::StatelessResetToken) {
if reset_token.len() != 16 {
return Err(TransportParameterError::InvalidParameterLength {
parameter: "stateless_reset_token".to_string(),
expected_min: 16,
actual: reset_token.len(),
});
}
}
Ok(())
}
fn validate_parameter_combinations(&self) -> Result<(), TransportParameterError> {
if self.has_empty(TransportParameterId::DisableActiveMigration)
&& self
.known_parameters
.contains_key(&TransportParameterId::PreferredAddress)
{
return Err(TransportParameterError::ConflictingParameters {
param1: TransportParameterId::DisableActiveMigration,
param2: TransportParameterId::PreferredAddress,
reason: "disable_active_migration conflicts with preferred_address".to_string(),
});
}
Ok(())
}
pub fn encode(&self) -> Result<Bytes, TransportParameterError> {
let mut buf = BytesMut::new();
let mut sorted_known: Vec<_> = self.known_parameters.iter().collect();
sorted_known.sort_by_key(|(id, _)| **id as u64);
for (&id, value) in sorted_known {
id.to_varint().encode_to_buf_for(id, &mut buf)?;
value.encode(id, &mut buf)?;
}
let mut sorted_unknown: Vec<_> = self.unknown_parameters.iter().collect();
sorted_unknown.sort_by_key(|(id, _)| **id);
for (&id, value) in sorted_unknown {
let id_varint = match VarInt::new(id) {
Outcome::Ok(varint) => varint,
_ => {
return Err(TransportParameterError::InvalidUnknownParameterValue {
parameter_id: id,
value: id,
reason: "Invalid parameter ID".to_string(),
});
}
};
id_varint.encode_to_buf_unknown(id, &mut buf)?;
let len_varint = match VarInt::new(value.len() as u64) {
Outcome::Ok(varint) => varint,
_ => {
return Err(TransportParameterError::InvalidUnknownParameterValue {
parameter_id: id,
value: value.len() as u64,
reason: "Invalid parameter length".to_string(),
});
}
};
len_varint.encode_to_buf_unknown(id, &mut buf)?;
buf.put_slice(value);
}
Ok(buf.freeze())
}
pub fn decode(data: Bytes) -> Result<Self, TransportParameterError> {
let mut params = Self::new();
let mut seen_parameters = std::collections::HashSet::new();
let mut data_buf = BytesMut::from(&data[..]);
while !data_buf.is_empty() {
let param_id_varint = match VarInt::decode(&mut data_buf) {
Outcome::Ok(Some(varint)) => varint,
Outcome::Ok(None) => return Err(TransportParameterError::UnexpectedEof),
_ => {
return Err(TransportParameterError::VarInt(
VarIntError::InvalidEncoding,
));
}
};
let param_id = param_id_varint.value();
if !seen_parameters.insert(param_id) {
return Err(TransportParameterError::DuplicateParameter(param_id));
}
if let Some(known_id) = TransportParameterId::from_varint(param_id_varint) {
let value_type = get_parameter_value_type(known_id);
let value = TransportParameterValue::decode(&mut data_buf, value_type)?;
params.set_parameter(known_id, value);
} else {
let length = match VarInt::decode(&mut data_buf) {
Outcome::Ok(Some(varint)) => varint,
Outcome::Ok(None) => return Err(TransportParameterError::UnexpectedEof),
_ => {
return Err(TransportParameterError::VarInt(
VarIntError::InvalidEncoding,
));
}
};
if data_buf.len() < length.value() as usize {
return Err(TransportParameterError::UnexpectedEof);
}
let value = data_buf.split_to(length.value() as usize).freeze();
params.set_unknown_parameter(param_id, value);
}
}
Ok(params)
}
}
impl Default for TransportParameters {
fn default() -> Self {
Self::new()
}
}
fn get_parameter_value_type(param: TransportParameterId) -> TransportParameterValueType {
match param {
TransportParameterId::OriginalDestinationConnectionId
| TransportParameterId::StatelessResetToken
| TransportParameterId::PreferredAddress
| TransportParameterId::InitialSourceConnectionId
| TransportParameterId::RetrySourceConnectionId => TransportParameterValueType::Bytes,
TransportParameterId::DisableActiveMigration => TransportParameterValueType::Empty,
_ => TransportParameterValueType::VarInt,
}
}
#[derive(Debug, thiserror::Error)]
pub enum TransportParameterError {
#[error("varint error: {0}")]
VarInt(#[from] VarIntError),
#[error("duplicate transport parameter: {0}")]
DuplicateParameter(u64),
#[error("missing required transport parameter: {0:?}")]
MissingRequiredParameter(TransportParameterId),
#[error("forbidden transport parameter {param:?} for {} endpoint", if *.is_server { "server" } else { "client" })]
ForbiddenParameter {
param: TransportParameterId,
is_server: bool,
},
#[error("invalid value {value} for transport parameter {parameter:?}: {reason}")]
InvalidParameterValue {
parameter: TransportParameterId,
value: u64,
reason: String,
},
#[error("invalid value {value} for unknown transport parameter {parameter_id}: {reason}")]
InvalidUnknownParameterValue {
parameter_id: u64,
value: u64,
reason: String,
},
#[error(
"invalid length for transport parameter {parameter}: expected >= {expected_min}, got {actual}"
)]
InvalidParameterLength {
parameter: String,
expected_min: usize,
actual: usize,
},
#[error("conflicting transport parameters {param1:?} and {param2:?}: {reason}")]
ConflictingParameters {
param1: TransportParameterId,
param2: TransportParameterId,
reason: String,
},
#[error("unexpected end of transport parameter data")]
UnexpectedEof,
}
trait VarIntTransportExt {
fn encode_to_buf_for<B: BufMut>(
&self,
parameter: TransportParameterId,
buf: &mut B,
) -> Result<(), TransportParameterError>;
fn encode_to_buf_unknown<B: BufMut>(
&self,
parameter_id: u64,
buf: &mut B,
) -> Result<(), TransportParameterError>;
}
impl VarIntTransportExt for VarInt {
fn encode_to_buf_for<B: BufMut>(
&self,
parameter: TransportParameterId,
buf: &mut B,
) -> Result<(), TransportParameterError> {
let mut temp = BytesMut::new();
match self.encode(&mut temp) {
Outcome::Ok(()) => {}
_ => {
return Err(TransportParameterError::InvalidParameterValue {
parameter,
value: 0,
reason: "VarInt encode failed".to_string(),
});
}
}
buf.put_slice(&temp);
Ok(())
}
fn encode_to_buf_unknown<B: BufMut>(
&self,
parameter_id: u64,
buf: &mut B,
) -> Result<(), TransportParameterError> {
let mut temp = BytesMut::new();
match self.encode(&mut temp) {
Outcome::Ok(()) => {}
_ => {
return Err(TransportParameterError::InvalidUnknownParameterValue {
parameter_id,
value: 0,
reason: "VarInt encode failed".to_string(),
});
}
}
buf.put_slice(&temp);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_transport_parameters_basic() {
let mut params = TransportParameters::new();
params
.set_varint(TransportParameterId::InitialMaxData, 65536)
.unwrap();
params
.set_varint(TransportParameterId::MaxIdleTimeout, 30000)
.unwrap();
params.set_empty(TransportParameterId::DisableActiveMigration);
assert_eq!(
params.get_varint(TransportParameterId::InitialMaxData),
Some(65536)
);
assert_eq!(
params.get_varint(TransportParameterId::MaxIdleTimeout),
Some(30000)
);
assert!(params.has_empty(TransportParameterId::DisableActiveMigration));
}
#[test]
fn test_transport_parameters_encoding_roundtrip() {
let mut params = TransportParameters::new();
params
.set_varint(TransportParameterId::InitialMaxData, 65536)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiLocal, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiRemote, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataUni, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsBidi, 100)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsUni, 100)
.unwrap();
params.set_unknown_parameter(0xFF00, Bytes::from_static(b"extension_data"));
let encoded = params.encode().unwrap();
let decoded = TransportParameters::decode(encoded).unwrap();
assert_eq!(
decoded.get_varint(TransportParameterId::InitialMaxData),
Some(65536)
);
assert_eq!(
decoded.get_unknown_parameter(0xFF00),
Some(&Bytes::from_static(b"extension_data"))
);
}
#[test]
fn test_transport_parameters_validation() {
let mut params = TransportParameters::new();
assert!(params.validate(false).is_err());
params
.set_varint(TransportParameterId::InitialMaxData, 65536)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiLocal, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiRemote, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataUni, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsBidi, 100)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsUni, 100)
.unwrap();
assert!(params.validate(false).is_ok());
}
#[test]
fn test_invalid_parameter_values() {
let mut params = TransportParameters::new();
params
.set_varint(TransportParameterId::InitialMaxData, 65536)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiLocal, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiRemote, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataUni, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsBidi, 100)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsUni, 100)
.unwrap();
params
.set_varint(TransportParameterId::AckDelayExponent, 25)
.unwrap();
assert!(params.validate(false).is_err());
}
#[test]
fn test_forbidden_parameters() {
let mut params = TransportParameters::new();
params
.set_varint(TransportParameterId::InitialMaxData, 65536)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiLocal, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiRemote, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataUni, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsBidi, 100)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsUni, 100)
.unwrap();
params.set_bytes(
TransportParameterId::StatelessResetToken,
Bytes::from(vec![0u8; 16]),
);
assert!(params.validate(false).is_err());
assert!(params.validate(true).is_ok());
}
#[test]
fn test_duplicate_parameter_detection() {
let mut buf = BytesMut::new();
let max_data_id = TransportParameterId::InitialMaxData.to_varint();
let value = VarInt::new(65536).unwrap();
max_data_id
.encode_to_buf_for(TransportParameterId::InitialMaxData, &mut buf)
.unwrap();
TransportParameterValue::VarInt(value)
.encode(TransportParameterId::InitialMaxData, &mut buf)
.unwrap();
max_data_id
.encode_to_buf_for(TransportParameterId::InitialMaxData, &mut buf)
.unwrap();
TransportParameterValue::VarInt(value)
.encode(TransportParameterId::InitialMaxData, &mut buf)
.unwrap();
let result = TransportParameters::decode(buf.freeze());
assert!(matches!(
result,
Err(TransportParameterError::DuplicateParameter(_))
));
}
#[test]
fn test_conflicting_parameters() {
let mut params = TransportParameters::new();
params
.set_varint(TransportParameterId::InitialMaxData, 65536)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiLocal, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataBidiRemote, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamDataUni, 32768)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsBidi, 100)
.unwrap();
params
.set_varint(TransportParameterId::InitialMaxStreamsUni, 100)
.unwrap();
params.set_empty(TransportParameterId::DisableActiveMigration);
params.set_bytes(
TransportParameterId::PreferredAddress,
Bytes::from_static(b"preferred_address_fixture"),
);
assert!(params.validate(true).is_err());
}
}