1use std::{
10 convert::TryFrom,
11 net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6},
12};
13
14use bytes::{Buf, BufMut};
15use rand::{seq::SliceRandom as _, Rng as _, RngCore};
16use thiserror::Error;
17
18use crate::{
19 address_discovery,
20 cid_generator::ConnectionIdGenerator,
21 cid_queue::CidQueue,
22 coding::{BufExt, BufMutExt, UnexpectedEnd},
23 config::{EndpointConfig, ServerConfig, TransportConfig},
24 shared::ConnectionId,
25 ResetToken, Side, TransportError, VarInt, LOC_CID_COUNT, MAX_CID_SIZE, MAX_STREAM_COUNT,
26 RESET_TOKEN_SIZE, TIMER_GRANULARITY,
27};
28
29macro_rules! apply_params {
35 ($macro:ident) => {
36 $macro! {
37 max_idle_timeout(MaxIdleTimeout) = 0,
40 max_udp_payload_size(MaxUdpPayloadSize) = 65527,
42
43 initial_max_data(InitialMaxData) = 0,
45 initial_max_stream_data_bidi_local(InitialMaxStreamDataBidiLocal) = 0,
47 initial_max_stream_data_bidi_remote(InitialMaxStreamDataBidiRemote) = 0,
49 initial_max_stream_data_uni(InitialMaxStreamDataUni) = 0,
51
52 initial_max_streams_bidi(InitialMaxStreamsBidi) = 0,
54 initial_max_streams_uni(InitialMaxStreamsUni) = 0,
56
57 ack_delay_exponent(AckDelayExponent) = 3,
59 max_ack_delay(MaxAckDelay) = 25,
62 active_connection_id_limit(ActiveConnectionIdLimit) = 2,
64 }
65 };
66}
67
68macro_rules! make_struct {
69 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
70 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
72 pub struct TransportParameters {
73 $($(#[$doc])* pub(crate) $name : VarInt,)*
74
75 pub(crate) disable_active_migration: bool,
77 pub(crate) max_datagram_frame_size: Option<VarInt>,
79 pub(crate) initial_src_cid: Option<ConnectionId>,
82 pub(crate) grease_quic_bit: bool,
85
86 pub(crate) min_ack_delay: Option<VarInt>,
92
93 pub(crate) original_dst_cid: Option<ConnectionId>,
97 pub(crate) retry_src_cid: Option<ConnectionId>,
100 pub(crate) stateless_reset_token: Option<ResetToken>,
102 pub(crate) preferred_address: Option<PreferredAddress>,
104
105 pub(crate) grease_transport_parameter: Option<ReservedTransportParameter>,
109
110 pub(crate) write_order: Option<[u8; TransportParameterId::SUPPORTED.len()]>,
115
116 pub(crate) address_discovery_role: address_discovery::Role,
118 }
119
120 impl TransportParameters {
124 pub(crate) fn default() -> Self {
126 Self {
127 $($name: VarInt::from_u32($default),)*
128
129 disable_active_migration: false,
130 max_datagram_frame_size: None,
131 initial_src_cid: None,
132 grease_quic_bit: false,
133 min_ack_delay: None,
134
135 original_dst_cid: None,
136 retry_src_cid: None,
137 stateless_reset_token: None,
138 preferred_address: None,
139 grease_transport_parameter: None,
140 write_order: None,
141 address_discovery_role: address_discovery::Role::Disabled,
142 }
143 }
144 }
145 }
146}
147
148apply_params!(make_struct);
149
150impl TransportParameters {
151 pub(crate) fn new(
152 config: &TransportConfig,
153 endpoint_config: &EndpointConfig,
154 cid_gen: &dyn ConnectionIdGenerator,
155 initial_src_cid: ConnectionId,
156 server_config: Option<&ServerConfig>,
157 rng: &mut impl RngCore,
158 ) -> Self {
159 Self {
160 initial_src_cid: Some(initial_src_cid),
161 initial_max_streams_bidi: config.max_concurrent_bidi_streams,
162 initial_max_streams_uni: config.max_concurrent_uni_streams,
163 initial_max_data: config.receive_window,
164 initial_max_stream_data_bidi_local: config.stream_receive_window,
165 initial_max_stream_data_bidi_remote: config.stream_receive_window,
166 initial_max_stream_data_uni: config.stream_receive_window,
167 max_udp_payload_size: endpoint_config.max_udp_payload_size,
168 max_idle_timeout: config.max_idle_timeout.unwrap_or(VarInt(0)),
169 disable_active_migration: server_config.is_some_and(|c| !c.migration),
170 active_connection_id_limit: if cid_gen.cid_len() == 0 {
171 2 } else {
173 CidQueue::LEN as u32
174 }
175 .into(),
176 max_datagram_frame_size: config
177 .datagram_receive_buffer_size
178 .map(|x| (x.min(u16::MAX.into()) as u16).into()),
179 grease_quic_bit: endpoint_config.grease_quic_bit,
180 min_ack_delay: Some(
181 VarInt::from_u64(u64::try_from(TIMER_GRANULARITY.as_micros()).unwrap()).unwrap(),
182 ),
183 grease_transport_parameter: Some(ReservedTransportParameter::random(rng)),
184 write_order: Some({
185 let mut order = std::array::from_fn(|i| i as u8);
186 order.shuffle(rng);
187 order
188 }),
189 address_discovery_role: config.address_discovery_role,
190 ..Self::default()
191 }
192 }
193
194 pub(crate) fn validate_resumption_from(&self, cached: &Self) -> Result<(), TransportError> {
197 if cached.active_connection_id_limit > self.active_connection_id_limit
198 || cached.initial_max_data > self.initial_max_data
199 || cached.initial_max_stream_data_bidi_local > self.initial_max_stream_data_bidi_local
200 || cached.initial_max_stream_data_bidi_remote > self.initial_max_stream_data_bidi_remote
201 || cached.initial_max_stream_data_uni > self.initial_max_stream_data_uni
202 || cached.initial_max_streams_bidi > self.initial_max_streams_bidi
203 || cached.initial_max_streams_uni > self.initial_max_streams_uni
204 || cached.max_datagram_frame_size > self.max_datagram_frame_size
205 || cached.grease_quic_bit && !self.grease_quic_bit
206 || cached.address_discovery_role != self.address_discovery_role
207 {
208 return Err(TransportError::PROTOCOL_VIOLATION(
209 "0-RTT accepted with incompatible transport parameters",
210 ));
211 }
212 Ok(())
213 }
214
215 pub(crate) fn issue_cids_limit(&self) -> u64 {
220 self.active_connection_id_limit.0.min(LOC_CID_COUNT)
221 }
222}
223
224#[derive(Debug, Copy, Clone, Eq, PartialEq)]
228pub(crate) struct PreferredAddress {
229 pub(crate) address_v4: Option<SocketAddrV4>,
230 pub(crate) address_v6: Option<SocketAddrV6>,
231 pub(crate) connection_id: ConnectionId,
232 pub(crate) stateless_reset_token: ResetToken,
233}
234
235impl PreferredAddress {
236 fn wire_size(&self) -> u16 {
237 4 + 2 + 16 + 2 + 1 + self.connection_id.len() as u16 + 16
238 }
239
240 fn write<W: BufMut>(&self, w: &mut W) {
241 w.write(self.address_v4.map_or(Ipv4Addr::UNSPECIFIED, |x| *x.ip()));
242 w.write::<u16>(self.address_v4.map_or(0, |x| x.port()));
243 w.write(self.address_v6.map_or(Ipv6Addr::UNSPECIFIED, |x| *x.ip()));
244 w.write::<u16>(self.address_v6.map_or(0, |x| x.port()));
245 w.write::<u8>(self.connection_id.len() as u8);
246 w.put_slice(&self.connection_id);
247 w.put_slice(&self.stateless_reset_token);
248 }
249
250 fn read<R: Buf>(r: &mut R) -> Result<Self, Error> {
251 let ip_v4 = r.get::<Ipv4Addr>()?;
252 let port_v4 = r.get::<u16>()?;
253 let ip_v6 = r.get::<Ipv6Addr>()?;
254 let port_v6 = r.get::<u16>()?;
255 let cid_len = r.get::<u8>()?;
256 if r.remaining() < cid_len as usize || cid_len > MAX_CID_SIZE as u8 {
257 return Err(Error::Malformed);
258 }
259 let mut stage = [0; MAX_CID_SIZE];
260 r.copy_to_slice(&mut stage[0..cid_len as usize]);
261 let cid = ConnectionId::new(&stage[0..cid_len as usize]);
262 if r.remaining() < 16 {
263 return Err(Error::Malformed);
264 }
265 let mut token = [0; RESET_TOKEN_SIZE];
266 r.copy_to_slice(&mut token);
267 let address_v4 = if ip_v4.is_unspecified() && port_v4 == 0 {
268 None
269 } else {
270 Some(SocketAddrV4::new(ip_v4, port_v4))
271 };
272 let address_v6 = if ip_v6.is_unspecified() && port_v6 == 0 {
273 None
274 } else {
275 Some(SocketAddrV6::new(ip_v6, port_v6, 0, 0))
276 };
277 if address_v4.is_none() && address_v6.is_none() {
278 return Err(Error::IllegalValue);
279 }
280 Ok(Self {
281 address_v4,
282 address_v6,
283 connection_id: cid,
284 stateless_reset_token: token.into(),
285 })
286 }
287}
288
289#[derive(Debug, Copy, Clone, Eq, PartialEq, Error)]
291pub enum Error {
292 #[error("parameter had illegal value")]
294 IllegalValue,
295 #[error("parameters were malformed")]
297 Malformed,
298}
299
300impl From<Error> for TransportError {
301 fn from(e: Error) -> Self {
302 match e {
303 Error::IllegalValue => Self::TRANSPORT_PARAMETER_ERROR("illegal value"),
304 Error::Malformed => Self::TRANSPORT_PARAMETER_ERROR("malformed"),
305 }
306 }
307}
308
309impl From<UnexpectedEnd> for Error {
310 fn from(_: UnexpectedEnd) -> Self {
311 Self::Malformed
312 }
313}
314
315impl TransportParameters {
316 pub fn write<W: BufMut>(&self, w: &mut W) {
318 for idx in self
319 .write_order
320 .as_ref()
321 .unwrap_or(&std::array::from_fn(|i| i as u8))
322 {
323 let id = TransportParameterId::SUPPORTED[*idx as usize];
324 match id {
325 TransportParameterId::ReservedTransportParameter => {
326 if let Some(param) = self.grease_transport_parameter {
327 param.write(w);
328 }
329 }
330 TransportParameterId::StatelessResetToken => {
331 if let Some(ref x) = self.stateless_reset_token {
332 w.write_var(id as u64);
333 w.write_var(16);
334 w.put_slice(x);
335 }
336 }
337 TransportParameterId::DisableActiveMigration => {
338 if self.disable_active_migration {
339 w.write_var(id as u64);
340 w.write_var(0);
341 }
342 }
343 TransportParameterId::MaxDatagramFrameSize => {
344 if let Some(x) = self.max_datagram_frame_size {
345 w.write_var(id as u64);
346 w.write_var(x.size() as u64);
347 w.write(x);
348 }
349 }
350 TransportParameterId::PreferredAddress => {
351 if let Some(ref x) = self.preferred_address {
352 w.write_var(id as u64);
353 w.write_var(x.wire_size() as u64);
354 x.write(w);
355 }
356 }
357 TransportParameterId::OriginalDestinationConnectionId => {
358 if let Some(ref cid) = self.original_dst_cid {
359 w.write_var(id as u64);
360 w.write_var(cid.len() as u64);
361 w.put_slice(cid);
362 }
363 }
364 TransportParameterId::InitialSourceConnectionId => {
365 if let Some(ref cid) = self.initial_src_cid {
366 w.write_var(id as u64);
367 w.write_var(cid.len() as u64);
368 w.put_slice(cid);
369 }
370 }
371 TransportParameterId::RetrySourceConnectionId => {
372 if let Some(ref cid) = self.retry_src_cid {
373 w.write_var(id as u64);
374 w.write_var(cid.len() as u64);
375 w.put_slice(cid);
376 }
377 }
378 TransportParameterId::GreaseQuicBit => {
379 if self.grease_quic_bit {
380 w.write_var(id as u64);
381 w.write_var(0);
382 }
383 }
384 TransportParameterId::MinAckDelayDraft07 => {
385 if let Some(x) = self.min_ack_delay {
386 w.write_var(id as u64);
387 w.write_var(x.size() as u64);
388 w.write(x);
389 }
390 }
391 TransportParameterId::ObservedAddr => {
392 if let Some(varint_role) = self.address_discovery_role.as_transport_parameter()
393 {
394 w.write_var(id as u64);
395 w.write_var(varint_role.size() as u64);
396 w.write(varint_role);
397 }
398 }
399 id => {
400 macro_rules! write_params {
401 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
402 match id {
403 $(TransportParameterId::$id => {
404 if self.$name.0 != $default {
405 w.write_var(id as u64);
406 w.write(VarInt::try_from(self.$name.size()).unwrap());
407 w.write(self.$name);
408 }
409 })*,
410 _ => {
411 unimplemented!("Missing implementation of write for transport parameter with code {id:?}");
412 }
413 }
414 }
415 }
416 apply_params!(write_params);
417 }
418 }
419 }
420 }
421
422 pub fn read<R: Buf>(side: Side, r: &mut R) -> Result<Self, Error> {
424 let mut params = Self::default();
426
427 macro_rules! param_state {
429 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {{
430 struct ParamState {
431 $($name: bool,)*
432 }
433
434 ParamState {
435 $($name: false,)*
436 }
437 }}
438 }
439 let mut got = apply_params!(param_state);
440
441 while r.has_remaining() {
442 let id = r.get_var()?;
443 let len = r.get_var()?;
444 if (r.remaining() as u64) < len {
445 return Err(Error::Malformed);
446 }
447 let len = len as usize;
448 let Ok(id) = TransportParameterId::try_from(id) else {
449 r.advance(len);
451 continue;
452 };
453
454 match id {
455 TransportParameterId::OriginalDestinationConnectionId => {
456 decode_cid(len, &mut params.original_dst_cid, r)?
457 }
458 TransportParameterId::StatelessResetToken => {
459 if len != 16 || params.stateless_reset_token.is_some() {
460 return Err(Error::Malformed);
461 }
462 let mut tok = [0; RESET_TOKEN_SIZE];
463 r.copy_to_slice(&mut tok);
464 params.stateless_reset_token = Some(tok.into());
465 }
466 TransportParameterId::DisableActiveMigration => {
467 if len != 0 || params.disable_active_migration {
468 return Err(Error::Malformed);
469 }
470 params.disable_active_migration = true;
471 }
472 TransportParameterId::PreferredAddress => {
473 if params.preferred_address.is_some() {
474 return Err(Error::Malformed);
475 }
476 params.preferred_address = Some(PreferredAddress::read(&mut r.take(len))?);
477 }
478 TransportParameterId::InitialSourceConnectionId => {
479 decode_cid(len, &mut params.initial_src_cid, r)?
480 }
481 TransportParameterId::RetrySourceConnectionId => {
482 decode_cid(len, &mut params.retry_src_cid, r)?
483 }
484 TransportParameterId::MaxDatagramFrameSize => {
485 if len > 8 || params.max_datagram_frame_size.is_some() {
486 return Err(Error::Malformed);
487 }
488 params.max_datagram_frame_size = Some(r.get().unwrap());
489 }
490 TransportParameterId::GreaseQuicBit => match len {
491 0 => params.grease_quic_bit = true,
492 _ => return Err(Error::Malformed),
493 },
494 TransportParameterId::MinAckDelayDraft07 => {
495 params.min_ack_delay = Some(r.get().unwrap())
496 }
497 TransportParameterId::ObservedAddr => {
498 if !params.address_discovery_role.is_disabled() {
499 return Err(Error::Malformed);
501 }
502 let value: VarInt = r.get()?;
503 if len != value.size() {
504 return Err(Error::Malformed);
505 }
506 params.address_discovery_role = value.try_into()?;
507 tracing::debug!(
508 role = ?params.address_discovery_role,
509 "address discovery enabled for peer"
510 );
511 }
512 _ => {
513 macro_rules! parse {
514 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
515 match id {
516 $(TransportParameterId::$id => {
517 let value = r.get::<VarInt>()?;
518 if len != value.size() || got.$name { return Err(Error::Malformed); }
519 params.$name = value.into();
520 got.$name = true;
521 })*
522 _ => r.advance(len),
523 }
524 }
525 }
526 apply_params!(parse);
527 }
528 }
529 }
530
531 if params.ack_delay_exponent.0 > 20
535 || params.max_ack_delay.0 >= 1 << 14
537 || params.active_connection_id_limit.0 < 2
539 || params.max_udp_payload_size.0 < 1200
541 || params.initial_max_streams_bidi.0 > MAX_STREAM_COUNT
543 || params.initial_max_streams_uni.0 > MAX_STREAM_COUNT
544 || params.min_ack_delay.is_some_and(|min_ack_delay| {
546 min_ack_delay.0 > params.max_ack_delay.0 * 1_000
548 })
549 || (side.is_server()
551 && (params.original_dst_cid.is_some()
552 || params.preferred_address.is_some()
553 || params.retry_src_cid.is_some()
554 || params.stateless_reset_token.is_some()))
555 || params
557 .preferred_address.is_some_and(|x| x.connection_id.is_empty())
558 {
559 return Err(Error::IllegalValue);
560 }
561
562 Ok(params)
563 }
564}
565
566#[derive(Debug, Copy, Clone, Eq, PartialEq)]
575pub(crate) struct ReservedTransportParameter {
576 id: VarInt,
578
579 payload: [u8; Self::MAX_PAYLOAD_LEN],
581
582 payload_len: usize,
584}
585
586impl ReservedTransportParameter {
587 fn random(rng: &mut impl RngCore) -> Self {
593 let id = Self::generate_reserved_id(rng);
594
595 let payload_len = rng.gen_range(0..Self::MAX_PAYLOAD_LEN);
596
597 let payload = {
598 let mut slice = [0u8; Self::MAX_PAYLOAD_LEN];
599 rng.fill_bytes(&mut slice[..payload_len]);
600 slice
601 };
602
603 Self {
604 id,
605 payload,
606 payload_len,
607 }
608 }
609
610 fn write(&self, w: &mut impl BufMut) {
611 w.write_var(self.id.0);
612 w.write_var(self.payload_len as u64);
613 w.put_slice(&self.payload[..self.payload_len]);
614 }
615
616 fn generate_reserved_id(rng: &mut impl RngCore) -> VarInt {
621 let id = {
622 let rand = rng.gen_range(0u64..(1 << 62) - 27);
623 let n = rand / 31;
624 31 * n + 27
625 };
626 debug_assert!(
627 id % 31 == 27,
628 "generated id does not have the form of 31 * N + 27"
629 );
630 VarInt::from_u64(id).expect(
631 "generated id does fit into range of allowed transport parameter IDs: [0; 2^62)",
632 )
633 }
634
635 const MAX_PAYLOAD_LEN: usize = 16;
639}
640
641#[repr(u64)]
642#[derive(Debug, Clone, Copy, PartialEq, Eq)]
643pub(crate) enum TransportParameterId {
644 OriginalDestinationConnectionId = 0x00,
646 MaxIdleTimeout = 0x01,
647 StatelessResetToken = 0x02,
648 MaxUdpPayloadSize = 0x03,
649 InitialMaxData = 0x04,
650 InitialMaxStreamDataBidiLocal = 0x05,
651 InitialMaxStreamDataBidiRemote = 0x06,
652 InitialMaxStreamDataUni = 0x07,
653 InitialMaxStreamsBidi = 0x08,
654 InitialMaxStreamsUni = 0x09,
655 AckDelayExponent = 0x0A,
656 MaxAckDelay = 0x0B,
657 DisableActiveMigration = 0x0C,
658 PreferredAddress = 0x0D,
659 ActiveConnectionIdLimit = 0x0E,
660 InitialSourceConnectionId = 0x0F,
661 RetrySourceConnectionId = 0x10,
662
663 ReservedTransportParameter = 0x1B,
665
666 MaxDatagramFrameSize = 0x20,
668
669 GreaseQuicBit = 0x2AB2,
671
672 MinAckDelayDraft07 = 0xFF04DE1B,
674
675 ObservedAddr = 0x9f81a176,
677}
678
679impl TransportParameterId {
680 const SUPPORTED: [Self; 22] = [
682 Self::MaxIdleTimeout,
683 Self::MaxUdpPayloadSize,
684 Self::InitialMaxData,
685 Self::InitialMaxStreamDataBidiLocal,
686 Self::InitialMaxStreamDataBidiRemote,
687 Self::InitialMaxStreamDataUni,
688 Self::InitialMaxStreamsBidi,
689 Self::InitialMaxStreamsUni,
690 Self::AckDelayExponent,
691 Self::MaxAckDelay,
692 Self::ActiveConnectionIdLimit,
693 Self::ReservedTransportParameter,
694 Self::StatelessResetToken,
695 Self::DisableActiveMigration,
696 Self::MaxDatagramFrameSize,
697 Self::PreferredAddress,
698 Self::OriginalDestinationConnectionId,
699 Self::InitialSourceConnectionId,
700 Self::RetrySourceConnectionId,
701 Self::GreaseQuicBit,
702 Self::MinAckDelayDraft07,
703 Self::ObservedAddr,
704 ];
705}
706
707impl std::cmp::PartialEq<u64> for TransportParameterId {
708 fn eq(&self, other: &u64) -> bool {
709 *other == (*self as u64)
710 }
711}
712
713impl TryFrom<u64> for TransportParameterId {
714 type Error = ();
715
716 fn try_from(value: u64) -> Result<Self, Self::Error> {
717 let param = match value {
718 id if Self::MaxIdleTimeout == id => Self::MaxIdleTimeout,
719 id if Self::MaxUdpPayloadSize == id => Self::MaxUdpPayloadSize,
720 id if Self::InitialMaxData == id => Self::InitialMaxData,
721 id if Self::InitialMaxStreamDataBidiLocal == id => Self::InitialMaxStreamDataBidiLocal,
722 id if Self::InitialMaxStreamDataBidiRemote == id => {
723 Self::InitialMaxStreamDataBidiRemote
724 }
725 id if Self::InitialMaxStreamDataUni == id => Self::InitialMaxStreamDataUni,
726 id if Self::InitialMaxStreamsBidi == id => Self::InitialMaxStreamsBidi,
727 id if Self::InitialMaxStreamsUni == id => Self::InitialMaxStreamsUni,
728 id if Self::AckDelayExponent == id => Self::AckDelayExponent,
729 id if Self::MaxAckDelay == id => Self::MaxAckDelay,
730 id if Self::ActiveConnectionIdLimit == id => Self::ActiveConnectionIdLimit,
731 id if Self::ReservedTransportParameter == id => Self::ReservedTransportParameter,
732 id if Self::StatelessResetToken == id => Self::StatelessResetToken,
733 id if Self::DisableActiveMigration == id => Self::DisableActiveMigration,
734 id if Self::MaxDatagramFrameSize == id => Self::MaxDatagramFrameSize,
735 id if Self::PreferredAddress == id => Self::PreferredAddress,
736 id if Self::OriginalDestinationConnectionId == id => {
737 Self::OriginalDestinationConnectionId
738 }
739 id if Self::InitialSourceConnectionId == id => Self::InitialSourceConnectionId,
740 id if Self::RetrySourceConnectionId == id => Self::RetrySourceConnectionId,
741 id if Self::GreaseQuicBit == id => Self::GreaseQuicBit,
742 id if Self::MinAckDelayDraft07 == id => Self::MinAckDelayDraft07,
743 id if Self::ObservedAddr == id => Self::ObservedAddr,
744 _ => return Err(()),
745 };
746 Ok(param)
747 }
748}
749
750fn decode_cid(len: usize, value: &mut Option<ConnectionId>, r: &mut impl Buf) -> Result<(), Error> {
751 if len > MAX_CID_SIZE || value.is_some() || r.remaining() < len {
752 return Err(Error::Malformed);
753 }
754
755 *value = Some(ConnectionId::from_buf(r, len));
756 Ok(())
757}
758
759#[cfg(test)]
760mod test {
761
762 use super::*;
763
764 #[test]
765 fn coding() {
766 let mut buf = Vec::new();
767 let params = TransportParameters {
768 initial_src_cid: Some(ConnectionId::new(&[])),
769 original_dst_cid: Some(ConnectionId::new(&[])),
770 initial_max_streams_bidi: 16u32.into(),
771 initial_max_streams_uni: 16u32.into(),
772 ack_delay_exponent: 2u32.into(),
773 max_udp_payload_size: 1200u32.into(),
774 preferred_address: Some(PreferredAddress {
775 address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
776 address_v6: Some(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 24, 0, 0)),
777 connection_id: ConnectionId::new(&[0x42]),
778 stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
779 }),
780 grease_quic_bit: true,
781 min_ack_delay: Some(2_000u32.into()),
782 address_discovery_role: address_discovery::Role::SendOnly,
783 ..TransportParameters::default()
784 };
785 params.write(&mut buf);
786 assert_eq!(
787 TransportParameters::read(Side::Client, &mut buf.as_slice()).unwrap(),
788 params
789 );
790 }
791
792 #[test]
793 fn reserved_transport_parameter_generate_reserved_id() {
794 use rand::rngs::mock::StepRng;
795 let mut rngs = [
796 StepRng::new(0, 1),
797 StepRng::new(1, 1),
798 StepRng::new(27, 1),
799 StepRng::new(31, 1),
800 StepRng::new(u32::MAX as u64, 1),
801 StepRng::new(u32::MAX as u64 - 1, 1),
802 StepRng::new(u32::MAX as u64 + 1, 1),
803 StepRng::new(u32::MAX as u64 - 27, 1),
804 StepRng::new(u32::MAX as u64 + 27, 1),
805 StepRng::new(u32::MAX as u64 - 31, 1),
806 StepRng::new(u32::MAX as u64 + 31, 1),
807 StepRng::new(u64::MAX, 1),
808 StepRng::new(u64::MAX - 1, 1),
809 StepRng::new(u64::MAX - 27, 1),
810 StepRng::new(u64::MAX - 31, 1),
811 StepRng::new(1 << 62, 1),
812 StepRng::new((1 << 62) - 1, 1),
813 StepRng::new((1 << 62) + 1, 1),
814 StepRng::new((1 << 62) - 27, 1),
815 StepRng::new((1 << 62) + 27, 1),
816 StepRng::new((1 << 62) - 31, 1),
817 StepRng::new((1 << 62) + 31, 1),
818 ];
819 for rng in &mut rngs {
820 let id = ReservedTransportParameter::generate_reserved_id(rng);
821 assert!(id.0 % 31 == 27)
822 }
823 }
824
825 #[test]
826 fn reserved_transport_parameter_ignored_when_read() {
827 let mut buf = Vec::new();
828 let reserved_parameter = ReservedTransportParameter::random(&mut rand::thread_rng());
829 assert!(reserved_parameter.payload_len < ReservedTransportParameter::MAX_PAYLOAD_LEN);
830 assert!(reserved_parameter.id.0 % 31 == 27);
831
832 reserved_parameter.write(&mut buf);
833 assert!(!buf.is_empty());
834 let read_params = TransportParameters::read(Side::Server, &mut buf.as_slice()).unwrap();
835 assert_eq!(read_params, TransportParameters::default());
836 }
837
838 #[test]
839 fn read_semantic_validation() {
840 #[allow(clippy::type_complexity)]
841 let illegal_params_builders: Vec<Box<dyn FnMut(&mut TransportParameters)>> = vec![
842 Box::new(|t| {
843 let min_ack_delay = t.max_ack_delay.0 * 1_000 + 1;
845 t.min_ack_delay = Some(VarInt::from_u64(min_ack_delay).unwrap())
846 }),
847 Box::new(|t| {
848 t.preferred_address = Some(PreferredAddress {
851 address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
852 address_v6: None,
853 connection_id: ConnectionId::new(&[]),
854 stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
855 })
856 }),
857 ];
858
859 for mut builder in illegal_params_builders {
860 let mut buf = Vec::new();
861 let mut params = TransportParameters::default();
862 builder(&mut params);
863 params.write(&mut buf);
864
865 assert_eq!(
866 TransportParameters::read(Side::Server, &mut buf.as_slice()),
867 Err(Error::IllegalValue)
868 );
869 }
870 }
871
872 #[test]
873 fn resumption_params_validation() {
874 let high_limit = TransportParameters {
875 initial_max_streams_uni: 32u32.into(),
876 ..TransportParameters::default()
877 };
878 let low_limit = TransportParameters {
879 initial_max_streams_uni: 16u32.into(),
880 ..TransportParameters::default()
881 };
882 high_limit.validate_resumption_from(&low_limit).unwrap();
883 low_limit.validate_resumption_from(&high_limit).unwrap_err();
884 }
885}