ant_quic/
transport_parameters.rs

1//! QUIC connection transport parameters
2//!
3//! The `TransportParameters` type is used to represent the transport parameters
4//! negotiated by peers while establishing a QUIC connection. This process
5//! happens as part of the establishment of the TLS session. As such, the types
6//! contained in this modules should generally only be referred to by custom
7//! implementations of the `crypto::Session` trait.
8
9use std::{
10    convert::TryFrom,
11    net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6},
12};
13
14use bytes::{Buf, BufMut};
15use rand::{Rng as _, RngCore, seq::SliceRandom as _};
16use thiserror::Error;
17
18use crate::{
19    LOC_CID_COUNT, MAX_CID_SIZE, MAX_STREAM_COUNT, RESET_TOKEN_SIZE, ResetToken, Side,
20    TIMER_GRANULARITY, TransportError, VarInt,
21    cid_generator::ConnectionIdGenerator,
22    cid_queue::CidQueue,
23    coding::{BufExt, BufMutExt, UnexpectedEnd},
24    config::{EndpointConfig, ServerConfig, TransportConfig},
25    shared::ConnectionId,
26};
27
28// Apply a given macro to a list of all the transport parameters having integer types, along with
29// their codes and default values. Using this helps us avoid error-prone duplication of the
30// contained information across decoding, encoding, and the `Default` impl. Whenever we want to do
31// something with transport parameters, we'll handle the bulk of cases by writing a macro that
32// takes a list of arguments in this form, then passing it to this macro.
33macro_rules! apply_params {
34    ($macro:ident) => {
35        $macro! {
36            // #[doc] name (id) = default,
37            /// Milliseconds, disabled if zero
38            max_idle_timeout(MaxIdleTimeout) = 0,
39            /// Limits the size of UDP payloads that the endpoint is willing to receive
40            max_udp_payload_size(MaxUdpPayloadSize) = 65527,
41
42            /// Initial value for the maximum amount of data that can be sent on the connection
43            initial_max_data(InitialMaxData) = 0,
44            /// Initial flow control limit for locally-initiated bidirectional streams
45            initial_max_stream_data_bidi_local(InitialMaxStreamDataBidiLocal) = 0,
46            /// Initial flow control limit for peer-initiated bidirectional streams
47            initial_max_stream_data_bidi_remote(InitialMaxStreamDataBidiRemote) = 0,
48            /// Initial flow control limit for unidirectional streams
49            initial_max_stream_data_uni(InitialMaxStreamDataUni) = 0,
50
51            /// Initial maximum number of bidirectional streams the peer may initiate
52            initial_max_streams_bidi(InitialMaxStreamsBidi) = 0,
53            /// Initial maximum number of unidirectional streams the peer may initiate
54            initial_max_streams_uni(InitialMaxStreamsUni) = 0,
55
56            /// Exponent used to decode the ACK Delay field in the ACK frame
57            ack_delay_exponent(AckDelayExponent) = 3,
58            /// Maximum amount of time in milliseconds by which the endpoint will delay sending
59            /// acknowledgments
60            max_ack_delay(MaxAckDelay) = 25,
61            /// Maximum number of connection IDs from the peer that an endpoint is willing to store
62            active_connection_id_limit(ActiveConnectionIdLimit) = 2,
63        }
64    };
65}
66
67macro_rules! make_struct {
68    {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
69        /// Transport parameters used to negotiate connection-level preferences between peers
70        #[derive(Debug, Clone, Eq, PartialEq)]
71        pub struct TransportParameters {
72            $($(#[$doc])* pub(crate) $name : VarInt,)*
73
74            /// Does the endpoint support active connection migration
75            pub(crate) disable_active_migration: bool,
76            /// Maximum size for datagram frames
77            pub(crate) max_datagram_frame_size: Option<VarInt>,
78            /// The value that the endpoint included in the Source Connection ID field of the first
79            /// Initial packet it sends for the connection
80            pub(crate) initial_src_cid: Option<ConnectionId>,
81            /// The endpoint is willing to receive QUIC packets containing any value for the fixed
82            /// bit
83            pub(crate) grease_quic_bit: bool,
84
85            /// Minimum amount of time in microseconds by which the endpoint is able to delay
86            /// sending acknowledgments
87            ///
88            /// If a value is provided, it implies that the endpoint supports QUIC Acknowledgement
89            /// Frequency
90            pub(crate) min_ack_delay: Option<VarInt>,
91
92            /// NAT traversal configuration for this connection
93            ///
94            /// NAT traversal configuration for this connection
95            ///
96            /// When present, indicates support for QUIC NAT traversal extension
97            pub(crate) nat_traversal: Option<NatTraversalConfig>,
98
99            /// Address discovery configuration for this connection
100            ///
101            /// When present, indicates support for QUIC Address Discovery extension
102            pub(crate) address_discovery: Option<AddressDiscoveryConfig>,
103
104            // Server-only
105            /// The value of the Destination Connection ID field from the first Initial packet sent
106            /// by the client
107            pub(crate) original_dst_cid: Option<ConnectionId>,
108            /// The value that the server included in the Source Connection ID field of a Retry
109            /// packet
110            pub(crate) retry_src_cid: Option<ConnectionId>,
111            /// Token used by the client to verify a stateless reset from the server
112            pub(crate) stateless_reset_token: Option<ResetToken>,
113            /// The server's preferred address for communication after handshake completion
114            pub(crate) preferred_address: Option<PreferredAddress>,
115            /// The randomly generated reserved transport parameter to sustain future extensibility
116            /// of transport parameter extensions.
117            /// When present, it is included during serialization but ignored during deserialization.
118            pub(crate) grease_transport_parameter: Option<ReservedTransportParameter>,
119
120            /// Defines the order in which transport parameters are serialized.
121            ///
122            /// This field is initialized only for outgoing `TransportParameters` instances and
123            /// is set to `None` for `TransportParameters` received from a peer.
124            pub(crate) write_order: Option<[u8; TransportParameterId::SUPPORTED.len()]>,
125        }
126
127        // We deliberately don't implement the `Default` trait, since that would be public, and
128        // downstream crates should never construct `TransportParameters` except by decoding those
129        // supplied by a peer.
130        impl TransportParameters {
131            /// Standard defaults, used if the peer does not supply a given parameter.
132            pub(crate) fn default() -> Self {
133                Self {
134                    $($name: VarInt::from_u32($default),)*
135
136                    disable_active_migration: false,
137                    max_datagram_frame_size: None,
138                    initial_src_cid: None,
139                    grease_quic_bit: false,
140                    min_ack_delay: None,
141                    nat_traversal: None,
142                    address_discovery: None,
143
144                    original_dst_cid: None,
145                    retry_src_cid: None,
146                    stateless_reset_token: None,
147                    preferred_address: None,
148                    grease_transport_parameter: None,
149                    write_order: None,
150                }
151            }
152        }
153    }
154}
155
156apply_params!(make_struct);
157
158impl TransportParameters {
159    pub(crate) fn new(
160        config: &TransportConfig,
161        endpoint_config: &EndpointConfig,
162        cid_gen: &dyn ConnectionIdGenerator,
163        initial_src_cid: ConnectionId,
164        server_config: Option<&ServerConfig>,
165        rng: &mut impl RngCore,
166    ) -> Self {
167        Self {
168            initial_src_cid: Some(initial_src_cid),
169            initial_max_streams_bidi: config.max_concurrent_bidi_streams,
170            initial_max_streams_uni: config.max_concurrent_uni_streams,
171            initial_max_data: config.receive_window,
172            initial_max_stream_data_bidi_local: config.stream_receive_window,
173            initial_max_stream_data_bidi_remote: config.stream_receive_window,
174            initial_max_stream_data_uni: config.stream_receive_window,
175            max_udp_payload_size: endpoint_config.max_udp_payload_size,
176            max_idle_timeout: config.max_idle_timeout.unwrap_or(VarInt(0)),
177            disable_active_migration: server_config.is_some_and(|c| !c.migration),
178            active_connection_id_limit: if cid_gen.cid_len() == 0 {
179                2 // i.e. default, i.e. unsent
180            } else {
181                CidQueue::LEN as u32
182            }
183            .into(),
184            max_datagram_frame_size: config
185                .datagram_receive_buffer_size
186                .map(|x| (x.min(u16::MAX.into()) as u16).into()),
187            grease_quic_bit: endpoint_config.grease_quic_bit,
188            min_ack_delay: Some(
189                VarInt::from_u64(u64::try_from(TIMER_GRANULARITY.as_micros()).unwrap()).unwrap(),
190            ),
191            grease_transport_parameter: Some(ReservedTransportParameter::random(rng)),
192            write_order: Some({
193                let mut order = std::array::from_fn(|i| i as u8);
194                order.shuffle(rng);
195                order
196            }),
197            nat_traversal: config.nat_traversal_config.clone(),
198            address_discovery: None, // TODO: Wire up to config when needed
199            ..Self::default()
200        }
201    }
202
203    /// Check that these parameters are legal when resuming from
204    /// certain cached parameters
205    pub(crate) fn validate_resumption_from(&self, cached: &Self) -> Result<(), TransportError> {
206        if cached.active_connection_id_limit > self.active_connection_id_limit
207            || cached.initial_max_data > self.initial_max_data
208            || cached.initial_max_stream_data_bidi_local > self.initial_max_stream_data_bidi_local
209            || cached.initial_max_stream_data_bidi_remote > self.initial_max_stream_data_bidi_remote
210            || cached.initial_max_stream_data_uni > self.initial_max_stream_data_uni
211            || cached.initial_max_streams_bidi > self.initial_max_streams_bidi
212            || cached.initial_max_streams_uni > self.initial_max_streams_uni
213            || cached.max_datagram_frame_size > self.max_datagram_frame_size
214            || cached.grease_quic_bit && !self.grease_quic_bit
215        {
216            return Err(TransportError::PROTOCOL_VIOLATION(
217                "0-RTT accepted with incompatible transport parameters",
218            ));
219        }
220        Ok(())
221    }
222
223    /// Maximum number of CIDs to issue to this peer
224    ///
225    /// Consider both a) the active_connection_id_limit from the other end; and
226    /// b) LOC_CID_COUNT used locally
227    pub(crate) fn issue_cids_limit(&self) -> u64 {
228        self.active_connection_id_limit.0.min(LOC_CID_COUNT)
229    }
230
231    /// Get the NAT traversal configuration for this connection
232    ///
233    /// This is a public accessor method for tests and external code that need to
234    /// examine the negotiated NAT traversal parameters.
235    pub fn nat_traversal_config(&self) -> Option<&NatTraversalConfig> {
236        self.nat_traversal.as_ref()
237    }
238}
239
240/// NAT traversal configuration for a QUIC connection
241///
242/// This configuration is negotiated as part of the transport parameters and
243/// enables QUIC NAT traversal extension functionality.
244#[derive(Debug, Clone, Eq, PartialEq)]
245pub struct NatTraversalConfig {
246    /// Role of this endpoint in NAT traversal coordination
247    pub(crate) role: NatTraversalRole,
248    /// Maximum number of candidate addresses to exchange
249    pub(crate) max_candidates: VarInt,
250    /// Timeout for coordination protocol in milliseconds
251    pub(crate) coordination_timeout: VarInt,
252    /// Maximum number of concurrent traversal attempts
253    pub(crate) max_concurrent_attempts: VarInt,
254    /// Peer ID for this endpoint (used for relay functionality)
255    pub(crate) peer_id: Option<[u8; 32]>,
256}
257
258// Note: NatTraversalConfig is encoded/decoded according to draft-seemann-quic-nat-traversal-01
259// which uses a simple format (empty value from client, 1-byte concurrency limit from server)
260// rather than a complex custom encoding.
261impl NatTraversalConfig {
262    /// Create a new NAT traversal configuration
263    ///
264    /// This is a public constructor for creating NAT traversal configurations
265    /// in tests and external code.
266    pub fn new(
267        role: NatTraversalRole,
268        max_candidates: VarInt,
269        coordination_timeout: VarInt,
270        max_concurrent_attempts: VarInt,
271        peer_id: Option<[u8; 32]>,
272    ) -> Self {
273        Self {
274            role,
275            max_candidates,
276            coordination_timeout,
277            max_concurrent_attempts,
278            peer_id,
279        }
280    }
281
282    /// Get the role for this NAT traversal configuration
283    pub fn role(&self) -> NatTraversalRole {
284        self.role
285    }
286
287    /// Get the maximum number of candidates
288    pub fn max_candidates(&self) -> VarInt {
289        self.max_candidates
290    }
291
292    /// Get the coordination timeout
293    pub fn coordination_timeout(&self) -> VarInt {
294        self.coordination_timeout
295    }
296
297    /// Get the maximum concurrent attempts
298    pub fn max_concurrent_attempts(&self) -> VarInt {
299        self.max_concurrent_attempts
300    }
301
302    /// Get the peer ID
303    pub fn peer_id(&self) -> Option<[u8; 32]> {
304        self.peer_id
305    }
306
307    /// Validate NAT traversal configuration for consistency
308    pub fn validate(&self) -> Result<(), Error> {
309        // Validate max_candidates is reasonable
310        if self.max_candidates.0 == 0 || self.max_candidates.0 > 100 {
311            return Err(Error::IllegalValue);
312        }
313
314        // Validate coordination timeout is reasonable (1s to 60s)
315        if self.coordination_timeout.0 < 1000 || self.coordination_timeout.0 > 60000 {
316            return Err(Error::IllegalValue);
317        }
318
319        // Validate max_concurrent_attempts is reasonable
320        if self.max_concurrent_attempts.0 == 0 || self.max_concurrent_attempts.0 > 10 {
321            return Err(Error::IllegalValue);
322        }
323
324        Ok(())
325    }
326}
327
328impl Default for NatTraversalConfig {
329    fn default() -> Self {
330        Self {
331            role: NatTraversalRole::Client,
332            max_candidates: VarInt::from_u32(8),
333            coordination_timeout: VarInt::from_u32(10000), // 10 seconds
334            max_concurrent_attempts: VarInt::from_u32(3),
335            peer_id: None,
336        }
337    }
338}
339
340/// Configuration for QUIC Address Discovery extension
341#[derive(Debug, Clone, Copy, PartialEq, Eq)]
342pub struct AddressDiscoveryConfig {
343    /// Whether address discovery is enabled
344    pub(crate) enabled: bool,
345    /// Maximum rate of OBSERVED_ADDRESS frames per path (per second)
346    /// Value is limited to 6 bits (0-63)
347    pub(crate) max_observation_rate: u8,
348    /// Whether to observe addresses for all paths or just primary
349    pub(crate) observe_all_paths: bool,
350}
351
352impl AddressDiscoveryConfig {
353    /// Create a new address discovery configuration
354    pub fn new(enabled: bool, max_observation_rate: u8, observe_all_paths: bool) -> Self {
355        Self {
356            enabled,
357            max_observation_rate: max_observation_rate.min(63), // Limit to 6 bits
358            observe_all_paths,
359        }
360    }
361    
362    /// Apply bootstrap settings for more aggressive observation
363    pub fn apply_bootstrap_settings(&mut self) {
364        // Enable address discovery if not already enabled
365        self.enabled = true;
366        // Set maximum allowed observation rate
367        self.max_observation_rate = 63; // Maximum 6-bit value
368        // Observe all paths for bootstrap nodes
369        self.observe_all_paths = true;
370    }
371}
372
373impl Default for AddressDiscoveryConfig {
374    fn default() -> Self {
375        Self {
376            enabled: true, // Enabled by default
377            max_observation_rate: 10,
378            observe_all_paths: false,
379        }
380    }
381}
382
383/// Role of an endpoint in NAT traversal coordination
384#[derive(Debug, Copy, Clone, Eq, PartialEq)]
385pub enum NatTraversalRole {
386    /// Client endpoint (initiates connections, on-demand)
387    Client,
388    /// Server endpoint (accepts connections, always reachable)
389    Server {
390        /// Whether this server can act as a relay for other connections
391        can_relay: bool,
392    },
393    /// Bootstrap/relay endpoint (publicly reachable, coordinates traversal)
394    Bootstrap,
395}
396
397/// A server's preferred address
398///
399/// This is communicated as a transport parameter during TLS session establishment.
400#[derive(Debug, Copy, Clone, Eq, PartialEq)]
401pub(crate) struct PreferredAddress {
402    pub(crate) address_v4: Option<SocketAddrV4>,
403    pub(crate) address_v6: Option<SocketAddrV6>,
404    pub(crate) connection_id: ConnectionId,
405    pub(crate) stateless_reset_token: ResetToken,
406}
407
408impl PreferredAddress {
409    fn wire_size(&self) -> u16 {
410        4 + 2 + 16 + 2 + 1 + self.connection_id.len() as u16 + 16
411    }
412
413    fn write<W: BufMut>(&self, w: &mut W) {
414        w.write(self.address_v4.map_or(Ipv4Addr::UNSPECIFIED, |x| *x.ip()));
415        w.write::<u16>(self.address_v4.map_or(0, |x| x.port()));
416        w.write(self.address_v6.map_or(Ipv6Addr::UNSPECIFIED, |x| *x.ip()));
417        w.write::<u16>(self.address_v6.map_or(0, |x| x.port()));
418        w.write::<u8>(self.connection_id.len() as u8);
419        w.put_slice(&self.connection_id);
420        w.put_slice(&self.stateless_reset_token);
421    }
422
423    fn read<R: Buf>(r: &mut R) -> Result<Self, Error> {
424        let ip_v4 = r.get::<Ipv4Addr>()?;
425        let port_v4 = r.get::<u16>()?;
426        let ip_v6 = r.get::<Ipv6Addr>()?;
427        let port_v6 = r.get::<u16>()?;
428        let cid_len = r.get::<u8>()?;
429        if r.remaining() < cid_len as usize || cid_len > MAX_CID_SIZE as u8 {
430            return Err(Error::Malformed);
431        }
432        let mut stage = [0; MAX_CID_SIZE];
433        r.copy_to_slice(&mut stage[0..cid_len as usize]);
434        let cid = ConnectionId::new(&stage[0..cid_len as usize]);
435        if r.remaining() < 16 {
436            return Err(Error::Malformed);
437        }
438        let mut token = [0; RESET_TOKEN_SIZE];
439        r.copy_to_slice(&mut token);
440        let address_v4 = if ip_v4.is_unspecified() && port_v4 == 0 {
441            None
442        } else {
443            Some(SocketAddrV4::new(ip_v4, port_v4))
444        };
445        let address_v6 = if ip_v6.is_unspecified() && port_v6 == 0 {
446            None
447        } else {
448            Some(SocketAddrV6::new(ip_v6, port_v6, 0, 0))
449        };
450        if address_v4.is_none() && address_v6.is_none() {
451            return Err(Error::IllegalValue);
452        }
453        Ok(Self {
454            address_v4,
455            address_v6,
456            connection_id: cid,
457            stateless_reset_token: token.into(),
458        })
459    }
460}
461
462/// Errors encountered while decoding `TransportParameters`
463#[derive(Debug, Copy, Clone, Eq, PartialEq, Error)]
464pub enum Error {
465    /// Parameters that are semantically invalid
466    #[error("parameter had illegal value")]
467    IllegalValue,
468    /// Catch-all error for problems while decoding transport parameters
469    #[error("parameters were malformed")]
470    Malformed,
471}
472
473impl From<Error> for TransportError {
474    fn from(e: Error) -> Self {
475        match e {
476            Error::IllegalValue => Self::TRANSPORT_PARAMETER_ERROR("illegal value"),
477            Error::Malformed => Self::TRANSPORT_PARAMETER_ERROR("malformed"),
478        }
479    }
480}
481
482impl From<UnexpectedEnd> for Error {
483    fn from(_: UnexpectedEnd) -> Self {
484        Self::Malformed
485    }
486}
487
488impl TransportParameters {
489    /// Encode `TransportParameters` into buffer
490    pub fn write<W: BufMut>(&self, w: &mut W) {
491        for idx in self
492            .write_order
493            .as_ref()
494            .unwrap_or(&std::array::from_fn(|i| i as u8))
495        {
496            let id = TransportParameterId::SUPPORTED[*idx as usize];
497            match id {
498                TransportParameterId::ReservedTransportParameter => {
499                    if let Some(param) = self.grease_transport_parameter {
500                        param.write(w);
501                    }
502                }
503                TransportParameterId::StatelessResetToken => {
504                    if let Some(ref x) = self.stateless_reset_token {
505                        w.write_var(id as u64);
506                        w.write_var(16);
507                        w.put_slice(x);
508                    }
509                }
510                TransportParameterId::DisableActiveMigration => {
511                    if self.disable_active_migration {
512                        w.write_var(id as u64);
513                        w.write_var(0);
514                    }
515                }
516                TransportParameterId::MaxDatagramFrameSize => {
517                    if let Some(x) = self.max_datagram_frame_size {
518                        w.write_var(id as u64);
519                        w.write_var(x.size() as u64);
520                        w.write(x);
521                    }
522                }
523                TransportParameterId::PreferredAddress => {
524                    if let Some(ref x) = self.preferred_address {
525                        w.write_var(id as u64);
526                        w.write_var(x.wire_size() as u64);
527                        x.write(w);
528                    }
529                }
530                TransportParameterId::OriginalDestinationConnectionId => {
531                    if let Some(ref cid) = self.original_dst_cid {
532                        w.write_var(id as u64);
533                        w.write_var(cid.len() as u64);
534                        w.put_slice(cid);
535                    }
536                }
537                TransportParameterId::InitialSourceConnectionId => {
538                    if let Some(ref cid) = self.initial_src_cid {
539                        w.write_var(id as u64);
540                        w.write_var(cid.len() as u64);
541                        w.put_slice(cid);
542                    }
543                }
544                TransportParameterId::RetrySourceConnectionId => {
545                    if let Some(ref cid) = self.retry_src_cid {
546                        w.write_var(id as u64);
547                        w.write_var(cid.len() as u64);
548                        w.put_slice(cid);
549                    }
550                }
551                TransportParameterId::GreaseQuicBit => {
552                    if self.grease_quic_bit {
553                        w.write_var(id as u64);
554                        w.write_var(0);
555                    }
556                }
557                TransportParameterId::MinAckDelayDraft07 => {
558                    if let Some(x) = self.min_ack_delay {
559                        w.write_var(id as u64);
560                        w.write_var(x.size() as u64);
561                        w.write(x);
562                    }
563                }
564                TransportParameterId::NatTraversal => {
565                    if let Some(ref config) = self.nat_traversal {
566                        // Per draft-seemann-quic-nat-traversal-01:
567                        // - Client sends empty value to indicate support
568                        // - Server sends concurrency limit (1 byte)
569                        match config.role {
570                            NatTraversalRole::Client => {
571                                // Client sends empty value
572                                w.write_var(id as u64);
573                                w.write_var(0); // Empty value
574                            }
575                            NatTraversalRole::Server { can_relay: _ } => {
576                                // Server sends concurrency limit
577                                w.write_var(id as u64);
578                                w.write_var(1); // 1 byte for concurrency limit
579                                // Use max_concurrent_attempts as concurrency limit
580                                let limit = config.max_concurrent_attempts.0.min(255) as u8;
581                                w.put_u8(limit);
582                            }
583                            NatTraversalRole::Bootstrap => {
584                                // Bootstrap endpoints act as servers
585                                w.write_var(id as u64);
586                                w.write_var(1); // 1 byte for concurrency limit
587                                let limit = config.max_concurrent_attempts.0.min(255) as u8;
588                                w.put_u8(limit);
589                            }
590                        }
591                    }
592                }
593                TransportParameterId::AddressDiscovery => {
594                    if let Some(ref config) = self.address_discovery {
595                        if config.enabled {
596                            w.write_var(id as u64);
597                            w.write_var(1); // 1 byte for config
598                            // Encode as: enabled(1 bit) | observe_all_paths(1 bit) | max_rate(6 bits)
599                            let config_byte = 0x80 | // enabled bit always set when writing
600                                              (if config.observe_all_paths { 0x40 } else { 0 }) |
601                                              (config.max_observation_rate & 0x3F);
602                            w.put_u8(config_byte);
603                        }
604                    }
605                }
606                id => {
607                    macro_rules! write_params {
608                        {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
609                            match id {
610                                $(TransportParameterId::$id => {
611                                    if self.$name.0 != $default {
612                                        w.write_var(id as u64);
613                                        w.write(VarInt::try_from(self.$name.size()).unwrap());
614                                        w.write(self.$name);
615                                    }
616                                })*,
617                                _ => {
618                                    // This should never be reached for supported parameters
619                                    // All supported parameters should be handled in specific match arms above
620                                    panic!("Unsupported transport parameter reached write implementation: {id:?}");
621                                }
622                            }
623                        }
624                    }
625                    apply_params!(write_params);
626                }
627            }
628        }
629    }
630
631    /// Decode `TransportParameters` from buffer
632    pub fn read<R: Buf>(side: Side, r: &mut R) -> Result<Self, Error> {
633        // Initialize to protocol-specified defaults
634        let mut params = Self::default();
635
636        // State to check for duplicate transport parameters.
637        macro_rules! param_state {
638            {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {{
639                struct ParamState {
640                    $($name: bool,)*
641                }
642
643                ParamState {
644                    $($name: false,)*
645                }
646            }}
647        }
648        let mut got = apply_params!(param_state);
649
650        while r.has_remaining() {
651            let id = r.get_var()?;
652            let len = r.get_var()?;
653            if (r.remaining() as u64) < len {
654                return Err(Error::Malformed);
655            }
656            let len = len as usize;
657            let Ok(id) = TransportParameterId::try_from(id) else {
658                // unknown transport parameters are ignored
659                r.advance(len);
660                continue;
661            };
662
663            match id {
664                TransportParameterId::OriginalDestinationConnectionId => {
665                    decode_cid(len, &mut params.original_dst_cid, r)?
666                }
667                TransportParameterId::StatelessResetToken => {
668                    if len != 16 || params.stateless_reset_token.is_some() {
669                        return Err(Error::Malformed);
670                    }
671                    let mut tok = [0; RESET_TOKEN_SIZE];
672                    r.copy_to_slice(&mut tok);
673                    params.stateless_reset_token = Some(tok.into());
674                }
675                TransportParameterId::DisableActiveMigration => {
676                    if len != 0 || params.disable_active_migration {
677                        return Err(Error::Malformed);
678                    }
679                    params.disable_active_migration = true;
680                }
681                TransportParameterId::PreferredAddress => {
682                    if params.preferred_address.is_some() {
683                        return Err(Error::Malformed);
684                    }
685                    params.preferred_address = Some(PreferredAddress::read(&mut r.take(len))?);
686                }
687                TransportParameterId::InitialSourceConnectionId => {
688                    decode_cid(len, &mut params.initial_src_cid, r)?
689                }
690                TransportParameterId::RetrySourceConnectionId => {
691                    decode_cid(len, &mut params.retry_src_cid, r)?
692                }
693                TransportParameterId::MaxDatagramFrameSize => {
694                    if len > 8 || params.max_datagram_frame_size.is_some() {
695                        return Err(Error::Malformed);
696                    }
697                    params.max_datagram_frame_size = Some(r.get().unwrap());
698                }
699                TransportParameterId::GreaseQuicBit => match len {
700                    0 => params.grease_quic_bit = true,
701                    _ => return Err(Error::Malformed),
702                },
703                TransportParameterId::MinAckDelayDraft07 => {
704                    params.min_ack_delay = Some(r.get().unwrap())
705                }
706                TransportParameterId::NatTraversal => {
707                    if params.nat_traversal.is_some() {
708                        return Err(Error::Malformed);
709                    }
710                    // Per draft-seemann-quic-nat-traversal-01:
711                    // - Empty value (len=0) from client indicates support
712                    // - 1 byte value from server is concurrency limit
713                    match (side, len) {
714                        (Side::Server, 0) => {
715                            // Client sent empty value - they support NAT traversal
716                            params.nat_traversal = Some(NatTraversalConfig {
717                                role: NatTraversalRole::Client,
718                                max_candidates: VarInt::from_u32(8), // Default
719                                coordination_timeout: VarInt::from_u32(10000), // Default 10s
720                                max_concurrent_attempts: VarInt::from_u32(3), // Default
721                                peer_id: None,
722                            });
723                        }
724                        (Side::Client, 1) => {
725                            // Server sent concurrency limit
726                            let limit = r.get::<u8>()?;
727                            params.nat_traversal = Some(NatTraversalConfig {
728                                role: NatTraversalRole::Server { can_relay: false }, // Determined later
729                                max_candidates: VarInt::from_u32(8),                 // Default
730                                coordination_timeout: VarInt::from_u32(10000),       // Default 10s
731                                max_concurrent_attempts: VarInt::from_u32(limit as u32),
732                                peer_id: None,
733                            });
734                        }
735                        _ => {
736                            // Invalid combination
737                            return Err(Error::Malformed);
738                        }
739                    }
740                }
741                TransportParameterId::AddressDiscovery => {
742                    if params.address_discovery.is_some() {
743                        return Err(Error::Malformed);
744                    }
745                    // Address discovery sends 1 byte config
746                    if len != 1 {
747                        return Err(Error::Malformed);
748                    }
749                    let config_byte = r.get::<u8>()?;
750                    // Decode: enabled(1 bit) | observe_all_paths(1 bit) | max_rate(6 bits)
751                    params.address_discovery = Some(AddressDiscoveryConfig {
752                        enabled: (config_byte & 0x80) != 0,
753                        max_observation_rate: config_byte & 0x3F,
754                        observe_all_paths: (config_byte & 0x40) != 0,
755                    });
756                }
757                _ => {
758                    macro_rules! parse {
759                        {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
760                            match id {
761                                $(TransportParameterId::$id => {
762                                    let value = r.get::<VarInt>()?;
763                                    if len != value.size() || got.$name { return Err(Error::Malformed); }
764                                    params.$name = value.into();
765                                    got.$name = true;
766                                })*
767                                _ => r.advance(len),
768                            }
769                        }
770                    }
771                    apply_params!(parse);
772                }
773            }
774        }
775
776        // Semantic validation
777
778        // https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.26.1
779        if params.ack_delay_exponent.0 > 20
780            // https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.28.1
781            || params.max_ack_delay.0 >= 1 << 14
782            // https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-6.2.1
783            || params.active_connection_id_limit.0 < 2
784            // https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.10.1
785            || params.max_udp_payload_size.0 < 1200
786            // https://www.rfc-editor.org/rfc/rfc9000.html#section-4.6-2
787            || params.initial_max_streams_bidi.0 > MAX_STREAM_COUNT
788            || params.initial_max_streams_uni.0 > MAX_STREAM_COUNT
789            // https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-08.html#section-3-4
790            || params.min_ack_delay.is_some_and(|min_ack_delay| {
791                // min_ack_delay uses microseconds, whereas max_ack_delay uses milliseconds
792                min_ack_delay.0 > params.max_ack_delay.0 * 1_000
793            })
794            // https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-8
795            || (side.is_server()
796                && (params.original_dst_cid.is_some()
797                    || params.preferred_address.is_some()
798                    || params.retry_src_cid.is_some()
799                    || params.stateless_reset_token.is_some()))
800            // https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.38.1
801            || params
802                .preferred_address.is_some_and(|x| x.connection_id.is_empty())
803        {
804            return Err(Error::IllegalValue);
805        }
806
807        // NAT traversal parameter validation
808        if let Some(ref nat_config) = params.nat_traversal {
809            // Validate NAT traversal configuration
810            if let Err(_) = nat_config.validate() {
811                return Err(Error::IllegalValue);
812            }
813
814            // Validate role-specific constraints
815            match nat_config.role {
816                NatTraversalRole::Server { .. } | NatTraversalRole::Bootstrap => {
817                    // Server/Bootstrap roles should only be received by clients
818                    if side.is_server() {
819                        return Err(Error::IllegalValue);
820                    }
821                }
822                NatTraversalRole::Client => {
823                    // Client role should only be received by servers
824                    if side.is_client() {
825                        return Err(Error::IllegalValue);
826                    }
827                }
828            }
829        }
830
831        Ok(params)
832    }
833}
834
835/// A reserved transport parameter.
836///
837/// It has an identifier of the form 31 * N + 27 for the integer value of N.
838/// Such identifiers are reserved to exercise the requirement that unknown transport parameters be ignored.
839/// The reserved transport parameter has no semantics and can carry arbitrary values.
840/// It may be included in transport parameters sent to the peer, and should be ignored when received.
841///
842/// See spec: <https://www.rfc-editor.org/rfc/rfc9000.html#section-18.1>
843#[derive(Debug, Copy, Clone, Eq, PartialEq)]
844pub(crate) struct ReservedTransportParameter {
845    /// The reserved identifier of the transport parameter
846    id: VarInt,
847
848    /// Buffer to store the parameter payload
849    payload: [u8; Self::MAX_PAYLOAD_LEN],
850
851    /// The number of bytes to include in the wire format from the `payload` buffer
852    payload_len: usize,
853}
854
855impl ReservedTransportParameter {
856    /// Generates a transport parameter with a random payload and a reserved ID.
857    ///
858    /// The implementation is inspired by quic-go and quiche:
859    /// 1. <https://github.com/quic-go/quic-go/blob/3e0a67b2476e1819752f04d75968de042b197b56/internal/wire/transport_parameters.go#L338-L344>
860    /// 2. <https://github.com/google/quiche/blob/cb1090b20c40e2f0815107857324e99acf6ec567/quiche/quic/core/crypto/transport_parameters.cc#L843-L860>
861    fn random(rng: &mut impl RngCore) -> Self {
862        let id = Self::generate_reserved_id(rng);
863
864        let payload_len = rng.gen_range(0..Self::MAX_PAYLOAD_LEN);
865
866        let payload = {
867            let mut slice = [0u8; Self::MAX_PAYLOAD_LEN];
868            rng.fill_bytes(&mut slice[..payload_len]);
869            slice
870        };
871
872        Self {
873            id,
874            payload,
875            payload_len,
876        }
877    }
878
879    fn write(&self, w: &mut impl BufMut) {
880        w.write_var(self.id.0);
881        w.write_var(self.payload_len as u64);
882        w.put_slice(&self.payload[..self.payload_len]);
883    }
884
885    /// Generates a random reserved identifier of the form `31 * N + 27`, as required by RFC 9000.
886    /// Reserved transport parameter identifiers are used to test compliance with the requirement
887    /// that unknown transport parameters must be ignored by peers.
888    /// See: <https://www.rfc-editor.org/rfc/rfc9000.html#section-18.1> and <https://www.rfc-editor.org/rfc/rfc9000.html#section-22.3>
889    fn generate_reserved_id(rng: &mut impl RngCore) -> VarInt {
890        let id = {
891            let rand = rng.gen_range(0u64..(1 << 62) - 27);
892            let n = rand / 31;
893            31 * n + 27
894        };
895        debug_assert!(
896            id % 31 == 27,
897            "generated id does not have the form of 31 * N + 27"
898        );
899        VarInt::from_u64(id).expect(
900            "generated id does fit into range of allowed transport parameter IDs: [0; 2^62)",
901        )
902    }
903
904    /// The maximum length of the payload to include as the parameter payload.
905    /// This value is not a specification-imposed limit but is chosen to match
906    /// the limit used by other implementations of QUIC, e.g., quic-go and quiche.
907    const MAX_PAYLOAD_LEN: usize = 16;
908}
909
910#[repr(u64)]
911#[derive(Debug, Clone, Copy, PartialEq, Eq)]
912pub(crate) enum TransportParameterId {
913    // https://www.rfc-editor.org/rfc/rfc9000.html#iana-tp-table
914    OriginalDestinationConnectionId = 0x00,
915    MaxIdleTimeout = 0x01,
916    StatelessResetToken = 0x02,
917    MaxUdpPayloadSize = 0x03,
918    InitialMaxData = 0x04,
919    InitialMaxStreamDataBidiLocal = 0x05,
920    InitialMaxStreamDataBidiRemote = 0x06,
921    InitialMaxStreamDataUni = 0x07,
922    InitialMaxStreamsBidi = 0x08,
923    InitialMaxStreamsUni = 0x09,
924    AckDelayExponent = 0x0A,
925    MaxAckDelay = 0x0B,
926    DisableActiveMigration = 0x0C,
927    PreferredAddress = 0x0D,
928    ActiveConnectionIdLimit = 0x0E,
929    InitialSourceConnectionId = 0x0F,
930    RetrySourceConnectionId = 0x10,
931
932    // Smallest possible ID of reserved transport parameter https://datatracker.ietf.org/doc/html/rfc9000#section-22.3
933    ReservedTransportParameter = 0x1B,
934
935    // https://www.rfc-editor.org/rfc/rfc9221.html#section-3
936    MaxDatagramFrameSize = 0x20,
937
938    // https://www.rfc-editor.org/rfc/rfc9287.html#section-3
939    GreaseQuicBit = 0x2AB2,
940
941    // https://datatracker.ietf.org/doc/html/draft-ietf-quic-ack-frequency#section-10.1
942    MinAckDelayDraft07 = 0xFF04DE1B,
943
944    // NAT Traversal Extension - draft-seemann-quic-nat-traversal-01
945    // Transport parameter ID from the IETF draft specification
946    NatTraversal = 0x3d7e9f0bca12fea6,
947
948    // Address Discovery Extension - draft-ietf-quic-address-discovery-00
949    // Transport parameter ID in experimental range
950    AddressDiscovery = 0x1f00,
951}
952
953impl TransportParameterId {
954    /// Array with all supported transport parameter IDs
955    const SUPPORTED: [Self; 23] = [
956        Self::MaxIdleTimeout,
957        Self::MaxUdpPayloadSize,
958        Self::InitialMaxData,
959        Self::InitialMaxStreamDataBidiLocal,
960        Self::InitialMaxStreamDataBidiRemote,
961        Self::InitialMaxStreamDataUni,
962        Self::InitialMaxStreamsBidi,
963        Self::InitialMaxStreamsUni,
964        Self::AckDelayExponent,
965        Self::MaxAckDelay,
966        Self::ActiveConnectionIdLimit,
967        Self::ReservedTransportParameter,
968        Self::StatelessResetToken,
969        Self::DisableActiveMigration,
970        Self::MaxDatagramFrameSize,
971        Self::PreferredAddress,
972        Self::OriginalDestinationConnectionId,
973        Self::InitialSourceConnectionId,
974        Self::RetrySourceConnectionId,
975        Self::GreaseQuicBit,
976        Self::MinAckDelayDraft07,
977        Self::NatTraversal,
978        Self::AddressDiscovery,
979    ];
980}
981
982impl std::cmp::PartialEq<u64> for TransportParameterId {
983    fn eq(&self, other: &u64) -> bool {
984        *other == (*self as u64)
985    }
986}
987
988impl TryFrom<u64> for TransportParameterId {
989    type Error = ();
990
991    fn try_from(value: u64) -> Result<Self, Self::Error> {
992        let param = match value {
993            id if Self::MaxIdleTimeout == id => Self::MaxIdleTimeout,
994            id if Self::MaxUdpPayloadSize == id => Self::MaxUdpPayloadSize,
995            id if Self::InitialMaxData == id => Self::InitialMaxData,
996            id if Self::InitialMaxStreamDataBidiLocal == id => Self::InitialMaxStreamDataBidiLocal,
997            id if Self::InitialMaxStreamDataBidiRemote == id => {
998                Self::InitialMaxStreamDataBidiRemote
999            }
1000            id if Self::InitialMaxStreamDataUni == id => Self::InitialMaxStreamDataUni,
1001            id if Self::InitialMaxStreamsBidi == id => Self::InitialMaxStreamsBidi,
1002            id if Self::InitialMaxStreamsUni == id => Self::InitialMaxStreamsUni,
1003            id if Self::AckDelayExponent == id => Self::AckDelayExponent,
1004            id if Self::MaxAckDelay == id => Self::MaxAckDelay,
1005            id if Self::ActiveConnectionIdLimit == id => Self::ActiveConnectionIdLimit,
1006            id if Self::ReservedTransportParameter == id => Self::ReservedTransportParameter,
1007            id if Self::StatelessResetToken == id => Self::StatelessResetToken,
1008            id if Self::DisableActiveMigration == id => Self::DisableActiveMigration,
1009            id if Self::MaxDatagramFrameSize == id => Self::MaxDatagramFrameSize,
1010            id if Self::PreferredAddress == id => Self::PreferredAddress,
1011            id if Self::OriginalDestinationConnectionId == id => {
1012                Self::OriginalDestinationConnectionId
1013            }
1014            id if Self::InitialSourceConnectionId == id => Self::InitialSourceConnectionId,
1015            id if Self::RetrySourceConnectionId == id => Self::RetrySourceConnectionId,
1016            id if Self::GreaseQuicBit == id => Self::GreaseQuicBit,
1017            id if Self::MinAckDelayDraft07 == id => Self::MinAckDelayDraft07,
1018            id if Self::NatTraversal == id => Self::NatTraversal,
1019            id if Self::AddressDiscovery == id => Self::AddressDiscovery,
1020            _ => return Err(()),
1021        };
1022        Ok(param)
1023    }
1024}
1025
1026fn decode_cid(len: usize, value: &mut Option<ConnectionId>, r: &mut impl Buf) -> Result<(), Error> {
1027    if len > MAX_CID_SIZE || value.is_some() || r.remaining() < len {
1028        return Err(Error::Malformed);
1029    }
1030
1031    *value = Some(ConnectionId::from_buf(r, len));
1032    Ok(())
1033}
1034
1035#[cfg(test)]
1036mod test {
1037    use super::*;
1038
1039    #[test]
1040    fn test_nat_traversal_transport_parameter_encoding_decoding() {
1041        // Test draft-compliant NAT traversal parameter encoding/decoding
1042
1043        // Test 1: Client sends empty value, server reads it
1044        let client_config = NatTraversalConfig {
1045            role: NatTraversalRole::Client,
1046            max_candidates: VarInt::from_u32(8),
1047            coordination_timeout: VarInt::from_u32(5000),
1048            max_concurrent_attempts: VarInt::from_u32(3),
1049            peer_id: None,
1050        };
1051
1052        let mut client_params = TransportParameters::default();
1053        client_params.nat_traversal = Some(client_config);
1054
1055        let mut encoded = Vec::new();
1056        client_params.write(&mut encoded);
1057
1058        // Server reads client params
1059        let server_decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1060            .expect("Failed to decode client transport parameters");
1061
1062        // Server should see that client supports NAT traversal
1063        assert!(server_decoded.nat_traversal.is_some());
1064        let server_view = server_decoded.nat_traversal.unwrap();
1065        assert!(matches!(server_view.role, NatTraversalRole::Client));
1066
1067        // Test 2: Server sends concurrency limit, client reads it
1068        let server_config = NatTraversalConfig {
1069            role: NatTraversalRole::Server { can_relay: false },
1070            max_candidates: VarInt::from_u32(16),
1071            coordination_timeout: VarInt::from_u32(10000),
1072            max_concurrent_attempts: VarInt::from_u32(5),
1073            peer_id: None,
1074        };
1075
1076        let mut server_params = TransportParameters::default();
1077        server_params.nat_traversal = Some(server_config);
1078
1079        let mut encoded = Vec::new();
1080        server_params.write(&mut encoded);
1081
1082        // Client reads server params
1083        let client_decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1084            .expect("Failed to decode server transport parameters");
1085
1086        // Client should see server's concurrency limit
1087        assert!(client_decoded.nat_traversal.is_some());
1088        let client_view = client_decoded.nat_traversal.unwrap();
1089        assert!(matches!(client_view.role, NatTraversalRole::Server { .. }));
1090        assert_eq!(client_view.max_concurrent_attempts, VarInt::from_u32(5));
1091    }
1092
1093    #[test]
1094    fn test_nat_traversal_parameter_without_peer_id() {
1095        // Test client-side NAT traversal config (sends empty value)
1096        let config = NatTraversalConfig {
1097            role: NatTraversalRole::Client,
1098            max_candidates: VarInt::from_u32(4),
1099            coordination_timeout: VarInt::from_u32(3000),
1100            max_concurrent_attempts: VarInt::from_u32(2),
1101            peer_id: None,
1102        };
1103
1104        let mut params = TransportParameters::default();
1105        params.nat_traversal = Some(config);
1106
1107        let mut encoded = Vec::new();
1108        params.write(&mut encoded);
1109
1110        // Server reads client's parameters
1111        let decoded_params = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1112            .expect("Failed to decode transport parameters");
1113
1114        let decoded_config = decoded_params
1115            .nat_traversal
1116            .expect("NAT traversal config should be present");
1117
1118        assert_eq!(decoded_config.role, NatTraversalRole::Client);
1119        assert!(decoded_config.peer_id.is_none());
1120
1121        // Test server-side NAT traversal config (sends concurrency limit)
1122        let server_config = NatTraversalConfig {
1123            role: NatTraversalRole::Server { can_relay: true },
1124            max_candidates: VarInt::from_u32(8),
1125            coordination_timeout: VarInt::from_u32(5000),
1126            max_concurrent_attempts: VarInt::from_u32(4),
1127            peer_id: None,
1128        };
1129
1130        let mut server_params = TransportParameters::default();
1131        server_params.nat_traversal = Some(server_config);
1132
1133        let mut server_encoded = Vec::new();
1134        server_params.write(&mut server_encoded);
1135
1136        // Client reads server's parameters
1137        let decoded_server_params =
1138            TransportParameters::read(Side::Client, &mut server_encoded.as_slice())
1139                .expect("Failed to decode server transport parameters");
1140
1141        let decoded_server_config = decoded_server_params
1142            .nat_traversal
1143            .expect("Server NAT traversal config should be present");
1144
1145        match decoded_server_config.role {
1146            NatTraversalRole::Server { can_relay } => {
1147                // The protocol doesn't encode can_relay, so it's always false when decoded
1148                assert!(!can_relay);
1149            }
1150            _ => panic!("Expected server role"),
1151        }
1152        assert_eq!(
1153            decoded_server_config.max_concurrent_attempts,
1154            VarInt::from_u32(4)
1155        );
1156    }
1157
1158    #[test]
1159    fn test_transport_parameters_without_nat_traversal() {
1160        // Test that transport parameters work without NAT traversal config
1161        let mut params = TransportParameters::default();
1162        params.nat_traversal = None;
1163
1164        let mut encoded = Vec::new();
1165        params.write(&mut encoded);
1166
1167        let decoded_params = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1168            .expect("Failed to decode transport parameters");
1169
1170        assert!(decoded_params.nat_traversal.is_none());
1171    }
1172
1173    #[test]
1174    fn test_nat_traversal_draft_compliant_encoding() {
1175        // Test draft-seemann-quic-nat-traversal-01 compliant encoding
1176
1177        // Test 1: Client sends empty value
1178        let client_config = NatTraversalConfig {
1179            role: NatTraversalRole::Client,
1180            max_candidates: VarInt::from_u32(8),
1181            coordination_timeout: VarInt::from_u32(10000),
1182            max_concurrent_attempts: VarInt::from_u32(3),
1183            peer_id: None,
1184        };
1185
1186        let mut client_params = TransportParameters::default();
1187        client_params.nat_traversal = Some(client_config);
1188
1189        let mut encoded = Vec::new();
1190        client_params.write(&mut encoded);
1191
1192        // Verify the encoded data contains empty value for client
1193        // Find the NAT traversal parameter in the encoded data
1194        use bytes::Buf;
1195        let mut cursor = &encoded[..];
1196        while cursor.has_remaining() {
1197            let id = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1198            let len = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1199            if id.0 == 0x3d7e9f0bca12fea6 {
1200                // Found NAT traversal parameter
1201                assert_eq!(len.0, 0, "Client should send empty value");
1202                break;
1203            }
1204            // Skip this parameter
1205            cursor.advance(len.0 as usize);
1206        }
1207
1208        // Test 2: Server sends 1-byte concurrency limit
1209        let server_config = NatTraversalConfig {
1210            role: NatTraversalRole::Server { can_relay: true },
1211            max_candidates: VarInt::from_u32(16),
1212            coordination_timeout: VarInt::from_u32(10000),
1213            max_concurrent_attempts: VarInt::from_u32(5),
1214            peer_id: None,
1215        };
1216
1217        let mut server_params = TransportParameters::default();
1218        server_params.nat_traversal = Some(server_config);
1219
1220        let mut encoded = Vec::new();
1221        server_params.write(&mut encoded);
1222
1223        // Verify the encoded data contains 1-byte value for server
1224        let mut cursor = &encoded[..];
1225        while cursor.has_remaining() {
1226            let id = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1227            let len = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1228            if id.0 == 0x3d7e9f0bca12fea6 {
1229                // Found NAT traversal parameter
1230                assert_eq!(len.0, 1, "Server should send 1-byte value");
1231                let limit = cursor.chunk()[0];
1232                assert_eq!(limit, 5, "Server should send concurrency limit");
1233                break;
1234            }
1235            // Skip this parameter
1236            cursor.advance(len.0 as usize);
1237        }
1238    }
1239
1240    #[test]
1241    fn test_nat_traversal_draft_compliant_decoding() {
1242        use bytes::BufMut;
1243
1244        // Test 1: Decode empty value from client
1245        let mut buf = Vec::new();
1246        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1247        buf.write_var(0); // Empty value
1248
1249        let params = TransportParameters::read(Side::Server, &mut buf.as_slice())
1250            .expect("Failed to decode transport parameters");
1251
1252        let config = params
1253            .nat_traversal
1254            .expect("NAT traversal should be present");
1255        assert_eq!(config.role, NatTraversalRole::Client);
1256        assert_eq!(config.max_candidates, VarInt::from_u32(8)); // Default value
1257        assert_eq!(config.coordination_timeout, VarInt::from_u32(10000)); // Default value
1258        assert_eq!(config.max_concurrent_attempts, VarInt::from_u32(3)); // Default value
1259
1260        // Test 2: Decode 1-byte concurrency limit from server
1261        let mut buf = Vec::new();
1262        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1263        buf.write_var(1); // 1-byte value
1264        buf.put_u8(7); // Concurrency limit of 7
1265
1266        let params = TransportParameters::read(Side::Client, &mut buf.as_slice())
1267            .expect("Failed to decode transport parameters");
1268
1269        let config = params
1270            .nat_traversal
1271            .expect("NAT traversal should be present");
1272        match config.role {
1273            NatTraversalRole::Server { can_relay } => {
1274                assert!(!can_relay); // Default to false
1275            }
1276            _ => panic!("Expected Server role"),
1277        }
1278        assert_eq!(config.max_concurrent_attempts, VarInt::from_u32(7));
1279
1280        // Test 3: Invalid length should fail
1281        let mut buf = Vec::new();
1282        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1283        buf.write_var(2); // Invalid 2-byte value
1284        buf.put_u8(7);
1285        buf.put_u8(8);
1286
1287        let result = TransportParameters::read(Side::Client, &mut buf.as_slice());
1288        assert!(result.is_err(), "Should fail with invalid length");
1289    }
1290
1291    #[test]
1292    fn test_nat_traversal_parameter_id() {
1293        // Verify the correct parameter ID is used
1294        assert_eq!(
1295            TransportParameterId::NatTraversal as u64,
1296            0x3d7e9f0bca12fea6
1297        );
1298    }
1299
1300    #[test]
1301    fn test_nat_traversal_config_validation() {
1302        // Test valid configuration
1303        let valid_config = NatTraversalConfig {
1304            role: NatTraversalRole::Client,
1305            max_candidates: VarInt::from_u32(8),
1306            coordination_timeout: VarInt::from_u32(5000),
1307            max_concurrent_attempts: VarInt::from_u32(3),
1308            peer_id: None,
1309        };
1310        assert!(valid_config.validate().is_ok());
1311
1312        // Test invalid max_candidates (too low)
1313        let invalid_config = NatTraversalConfig {
1314            max_candidates: VarInt::from_u32(0),
1315            ..valid_config
1316        };
1317        assert!(invalid_config.validate().is_err());
1318
1319        // Test invalid max_candidates (too high)
1320        let invalid_config = NatTraversalConfig {
1321            max_candidates: VarInt::from_u32(101),
1322            ..valid_config
1323        };
1324        assert!(invalid_config.validate().is_err());
1325
1326        // Test invalid coordination_timeout (too low)
1327        let invalid_config = NatTraversalConfig {
1328            coordination_timeout: VarInt::from_u32(500),
1329            ..valid_config
1330        };
1331        assert!(invalid_config.validate().is_err());
1332
1333        // Test invalid coordination_timeout (too high)
1334        let invalid_config = NatTraversalConfig {
1335            coordination_timeout: VarInt::from_u32(70000),
1336            ..valid_config
1337        };
1338        assert!(invalid_config.validate().is_err());
1339
1340        // Test invalid max_concurrent_attempts (too low)
1341        let invalid_config = NatTraversalConfig {
1342            max_concurrent_attempts: VarInt::from_u32(0),
1343            ..valid_config
1344        };
1345        assert!(invalid_config.validate().is_err());
1346
1347        // Test invalid max_concurrent_attempts (too high)
1348        let invalid_config = NatTraversalConfig {
1349            max_concurrent_attempts: VarInt::from_u32(11),
1350            ..valid_config
1351        };
1352        assert!(invalid_config.validate().is_err());
1353    }
1354
1355    #[test]
1356    fn test_nat_traversal_role_validation() {
1357        use bytes::BufMut;
1358
1359        // Test client role validation - should fail when received by client
1360        let mut buf = Vec::new();
1361        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1362        buf.write_var(0); // Empty value (client role)
1363
1364        // Client receiving client role should fail
1365        let result = TransportParameters::read(Side::Client, &mut buf.as_slice());
1366        assert!(
1367            result.is_err(),
1368            "Client should not accept client role from peer"
1369        );
1370
1371        // Server receiving client role should succeed
1372        let result = TransportParameters::read(Side::Server, &mut buf.as_slice());
1373        assert!(result.is_ok(), "Server should accept client role from peer");
1374
1375        // Test server role validation - should fail when received by server
1376        let mut buf = Vec::new();
1377        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1378        buf.write_var(1); // 1-byte value (server role)
1379        buf.put_u8(5); // Concurrency limit
1380
1381        // Server receiving server role should fail
1382        let result = TransportParameters::read(Side::Server, &mut buf.as_slice());
1383        assert!(
1384            result.is_err(),
1385            "Server should not accept server role from peer"
1386        );
1387
1388        // Client receiving server role should succeed
1389        let result = TransportParameters::read(Side::Client, &mut buf.as_slice());
1390        assert!(result.is_ok(), "Client should accept server role from peer");
1391    }
1392
1393    #[test]
1394    fn test_nat_traversal_parameter_combinations() {
1395        // Test that NAT traversal works with other transport parameters
1396        let nat_config = NatTraversalConfig {
1397            role: NatTraversalRole::Client,
1398            max_candidates: VarInt::from_u32(10),
1399            coordination_timeout: VarInt::from_u32(8000),
1400            max_concurrent_attempts: VarInt::from_u32(4),
1401            peer_id: Some([42u8; 32]),
1402        };
1403
1404        let mut params = TransportParameters::default();
1405        params.nat_traversal = Some(nat_config);
1406        params.max_idle_timeout = VarInt::from_u32(30000);
1407        params.initial_max_data = VarInt::from_u32(1048576);
1408        params.grease_quic_bit = true;
1409
1410        // Test encoding
1411        let mut encoded = Vec::new();
1412        params.write(&mut encoded);
1413        assert!(!encoded.is_empty());
1414
1415        // Test decoding
1416        let decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1417            .expect("Should decode successfully");
1418
1419        // Verify NAT traversal config is preserved
1420        let decoded_config = decoded
1421            .nat_traversal
1422            .expect("NAT traversal should be present");
1423        assert_eq!(decoded_config.role, NatTraversalRole::Client);
1424        assert_eq!(decoded_config.max_candidates, VarInt::from_u32(8)); // Default value
1425
1426        // Verify other parameters are preserved
1427        assert_eq!(decoded.max_idle_timeout, VarInt::from_u32(30000));
1428        assert_eq!(decoded.initial_max_data, VarInt::from_u32(1048576));
1429        assert!(decoded.grease_quic_bit);
1430    }
1431
1432    #[test]
1433    fn test_nat_traversal_default_config() {
1434        let default_config = NatTraversalConfig::default();
1435
1436        assert_eq!(default_config.role, NatTraversalRole::Client);
1437        assert_eq!(default_config.max_candidates, VarInt::from_u32(8));
1438        assert_eq!(default_config.coordination_timeout, VarInt::from_u32(10000));
1439        assert_eq!(default_config.max_concurrent_attempts, VarInt::from_u32(3));
1440        assert!(default_config.peer_id.is_none());
1441
1442        // Default config should be valid
1443        assert!(default_config.validate().is_ok());
1444    }
1445
1446    #[test]
1447    fn test_nat_traversal_endpoint_role_negotiation() {
1448        // Test complete client-server negotiation
1449
1450        // 1. Client creates parameters with NAT traversal support
1451        let client_config = NatTraversalConfig {
1452            role: NatTraversalRole::Client,
1453            max_candidates: VarInt::from_u32(12),
1454            coordination_timeout: VarInt::from_u32(7000),
1455            max_concurrent_attempts: VarInt::from_u32(5),
1456            peer_id: None,
1457        };
1458
1459        let mut client_params = TransportParameters::default();
1460        client_params.nat_traversal = Some(client_config);
1461
1462        // 2. Client encodes and sends to server
1463        let mut client_encoded = Vec::new();
1464        client_params.write(&mut client_encoded);
1465
1466        // 3. Server receives and decodes client parameters
1467        let server_received =
1468            TransportParameters::read(Side::Server, &mut client_encoded.as_slice())
1469                .expect("Server should decode client params");
1470
1471        // Server should see client role
1472        let server_view = server_received
1473            .nat_traversal
1474            .expect("NAT traversal should be present");
1475        assert_eq!(server_view.role, NatTraversalRole::Client);
1476
1477        // 4. Server creates response with server role
1478        let server_config = NatTraversalConfig {
1479            role: NatTraversalRole::Server { can_relay: true },
1480            max_candidates: VarInt::from_u32(16),
1481            coordination_timeout: VarInt::from_u32(12000),
1482            max_concurrent_attempts: VarInt::from_u32(8),
1483            peer_id: Some([123u8; 32]),
1484        };
1485
1486        let mut server_params = TransportParameters::default();
1487        server_params.nat_traversal = Some(server_config);
1488
1489        // 5. Server encodes and sends to client
1490        let mut server_encoded = Vec::new();
1491        server_params.write(&mut server_encoded);
1492
1493        // 6. Client receives and decodes server parameters
1494        let client_received =
1495            TransportParameters::read(Side::Client, &mut server_encoded.as_slice())
1496                .expect("Client should decode server params");
1497
1498        // Client should see server role with concurrency limit
1499        let client_view = client_received
1500            .nat_traversal
1501            .expect("NAT traversal should be present");
1502        match client_view.role {
1503            NatTraversalRole::Server { can_relay } => {
1504                assert!(!can_relay); // Default to false in decoded params
1505            }
1506            _ => panic!("Expected server role"),
1507        }
1508        assert_eq!(client_view.max_concurrent_attempts, VarInt::from_u32(8));
1509    }
1510
1511    #[test]
1512    fn coding() {
1513        let mut buf = Vec::new();
1514        let params = TransportParameters {
1515            initial_src_cid: Some(ConnectionId::new(&[])),
1516            original_dst_cid: Some(ConnectionId::new(&[])),
1517            initial_max_streams_bidi: 16u32.into(),
1518            initial_max_streams_uni: 16u32.into(),
1519            ack_delay_exponent: 2u32.into(),
1520            max_udp_payload_size: 1200u32.into(),
1521            preferred_address: Some(PreferredAddress {
1522                address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
1523                address_v6: Some(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 24, 0, 0)),
1524                connection_id: ConnectionId::new(&[0x42]),
1525                stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
1526            }),
1527            grease_quic_bit: true,
1528            min_ack_delay: Some(2_000u32.into()),
1529            ..TransportParameters::default()
1530        };
1531        params.write(&mut buf);
1532        assert_eq!(
1533            TransportParameters::read(Side::Client, &mut buf.as_slice()).unwrap(),
1534            params
1535        );
1536    }
1537
1538    #[test]
1539    fn reserved_transport_parameter_generate_reserved_id() {
1540        use rand::rngs::mock::StepRng;
1541        let mut rngs = [
1542            StepRng::new(0, 1),
1543            StepRng::new(1, 1),
1544            StepRng::new(27, 1),
1545            StepRng::new(31, 1),
1546            StepRng::new(u32::MAX as u64, 1),
1547            StepRng::new(u32::MAX as u64 - 1, 1),
1548            StepRng::new(u32::MAX as u64 + 1, 1),
1549            StepRng::new(u32::MAX as u64 - 27, 1),
1550            StepRng::new(u32::MAX as u64 + 27, 1),
1551            StepRng::new(u32::MAX as u64 - 31, 1),
1552            StepRng::new(u32::MAX as u64 + 31, 1),
1553            StepRng::new(u64::MAX, 1),
1554            StepRng::new(u64::MAX - 1, 1),
1555            StepRng::new(u64::MAX - 27, 1),
1556            StepRng::new(u64::MAX - 31, 1),
1557            StepRng::new(1 << 62, 1),
1558            StepRng::new((1 << 62) - 1, 1),
1559            StepRng::new((1 << 62) + 1, 1),
1560            StepRng::new((1 << 62) - 27, 1),
1561            StepRng::new((1 << 62) + 27, 1),
1562            StepRng::new((1 << 62) - 31, 1),
1563            StepRng::new((1 << 62) + 31, 1),
1564        ];
1565        for rng in &mut rngs {
1566            let id = ReservedTransportParameter::generate_reserved_id(rng);
1567            assert!(id.0 % 31 == 27)
1568        }
1569    }
1570
1571    #[test]
1572    fn reserved_transport_parameter_ignored_when_read() {
1573        let mut buf = Vec::new();
1574        let reserved_parameter = ReservedTransportParameter::random(&mut rand::thread_rng());
1575        assert!(reserved_parameter.payload_len < ReservedTransportParameter::MAX_PAYLOAD_LEN);
1576        assert!(reserved_parameter.id.0 % 31 == 27);
1577
1578        reserved_parameter.write(&mut buf);
1579        assert!(!buf.is_empty());
1580        let read_params = TransportParameters::read(Side::Server, &mut buf.as_slice()).unwrap();
1581        assert_eq!(read_params, TransportParameters::default());
1582    }
1583
1584    #[test]
1585    fn read_semantic_validation() {
1586        #[allow(clippy::type_complexity)]
1587        let illegal_params_builders: Vec<Box<dyn FnMut(&mut TransportParameters)>> = vec![
1588            Box::new(|t| {
1589                // This min_ack_delay is bigger than max_ack_delay!
1590                let min_ack_delay = t.max_ack_delay.0 * 1_000 + 1;
1591                t.min_ack_delay = Some(VarInt::from_u64(min_ack_delay).unwrap())
1592            }),
1593            Box::new(|t| {
1594                // Preferred address can only be sent by senders (and we are reading the transport
1595                // params as a client)
1596                t.preferred_address = Some(PreferredAddress {
1597                    address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
1598                    address_v6: None,
1599                    connection_id: ConnectionId::new(&[]),
1600                    stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
1601                })
1602            }),
1603        ];
1604
1605        for mut builder in illegal_params_builders {
1606            let mut buf = Vec::new();
1607            let mut params = TransportParameters::default();
1608            builder(&mut params);
1609            params.write(&mut buf);
1610
1611            assert_eq!(
1612                TransportParameters::read(Side::Server, &mut buf.as_slice()),
1613                Err(Error::IllegalValue)
1614            );
1615        }
1616    }
1617
1618    #[test]
1619    fn resumption_params_validation() {
1620        let high_limit = TransportParameters {
1621            initial_max_streams_uni: 32u32.into(),
1622            ..TransportParameters::default()
1623        };
1624        let low_limit = TransportParameters {
1625            initial_max_streams_uni: 16u32.into(),
1626            ..TransportParameters::default()
1627        };
1628        high_limit.validate_resumption_from(&low_limit).unwrap();
1629        low_limit.validate_resumption_from(&high_limit).unwrap_err();
1630    }
1631
1632    #[test]
1633    fn test_address_discovery_parameter_id() {
1634        // Test that ADDRESS_DISCOVERY parameter ID is defined correctly
1635        assert_eq!(TransportParameterId::AddressDiscovery as u64, 0x1f00);
1636    }
1637
1638    #[test]
1639    fn test_address_discovery_config_struct() {
1640        // Test AddressDiscoveryConfig struct creation and fields
1641        let config = AddressDiscoveryConfig {
1642            enabled: true,
1643            max_observation_rate: 10,
1644            observe_all_paths: false,
1645        };
1646        
1647        assert!(config.enabled);
1648        assert_eq!(config.max_observation_rate, 10);
1649        assert!(!config.observe_all_paths);
1650    }
1651
1652    #[test]
1653    fn test_address_discovery_config_new() {
1654        // Test constructor with rate limiting
1655        let config = AddressDiscoveryConfig::new(true, 100, true);
1656        assert!(config.enabled);
1657        assert_eq!(config.max_observation_rate, 63); // Should be clamped to 63
1658        assert!(config.observe_all_paths);
1659    }
1660
1661    #[test]
1662    fn test_transport_parameters_with_address_discovery() {
1663        // Test that TransportParameters can hold address_discovery field
1664        let mut params = TransportParameters::default();
1665        assert!(params.address_discovery.is_none());
1666        
1667        let config = AddressDiscoveryConfig {
1668            enabled: true,
1669            max_observation_rate: 5,
1670            observe_all_paths: true,
1671        };
1672        
1673        params.address_discovery = Some(config);
1674        assert!(params.address_discovery.is_some());
1675        
1676        let stored_config = params.address_discovery.as_ref().unwrap();
1677        assert!(stored_config.enabled);
1678        assert_eq!(stored_config.max_observation_rate, 5);
1679        assert!(stored_config.observe_all_paths);
1680    }
1681
1682    #[test]
1683    fn test_address_discovery_parameter_encoding() {
1684        // Test encoding of address discovery transport parameter
1685        let config = AddressDiscoveryConfig {
1686            enabled: true,
1687            max_observation_rate: 10,
1688            observe_all_paths: false,
1689        };
1690        
1691        let mut params = TransportParameters::default();
1692        params.address_discovery = Some(config);
1693        
1694        let mut encoded = Vec::new();
1695        params.write(&mut encoded);
1696        
1697        // The encoded data should contain our parameter
1698        assert!(!encoded.is_empty());
1699    }
1700
1701    #[test]
1702    fn test_address_discovery_parameter_roundtrip() {
1703        // Test encoding and decoding of address discovery parameter
1704        let config = AddressDiscoveryConfig {
1705            enabled: true,
1706            max_observation_rate: 15,
1707            observe_all_paths: true,
1708        };
1709        
1710        let mut params = TransportParameters::default();
1711        params.address_discovery = Some(config);
1712        
1713        let mut encoded = Vec::new();
1714        params.write(&mut encoded);
1715        
1716        // Decode as peer
1717        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1718            .expect("Failed to decode transport parameters");
1719        
1720        assert!(decoded.address_discovery.is_some());
1721        let decoded_config = decoded.address_discovery.as_ref().unwrap();
1722        assert!(decoded_config.enabled);
1723        assert_eq!(decoded_config.max_observation_rate, 15);
1724        assert!(decoded_config.observe_all_paths);
1725    }
1726
1727    #[test]
1728    fn test_address_discovery_disabled_by_default() {
1729        // Test that address discovery is disabled by default
1730        let params = TransportParameters::default();
1731        assert!(params.address_discovery.is_none());
1732    }
1733
1734    #[test]
1735    fn test_address_discovery_max_rate_limits() {
1736        // Test that max_observation_rate is limited to valid range (0-63)
1737        let config = AddressDiscoveryConfig {
1738            enabled: true,
1739            max_observation_rate: 63, // Maximum 6-bit value
1740            observe_all_paths: false,
1741        };
1742        
1743        let mut params = TransportParameters::default();
1744        params.address_discovery = Some(config);
1745        
1746        let mut encoded = Vec::new();
1747        params.write(&mut encoded);
1748        
1749        let decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1750            .expect("Failed to decode");
1751        
1752        let decoded_config = decoded.address_discovery.as_ref().unwrap();
1753        assert_eq!(decoded_config.max_observation_rate, 63);
1754    }
1755
1756    #[test]
1757    fn test_address_discovery_disabled_not_encoded() {
1758        // Test that disabled address discovery is not encoded
1759        let config = AddressDiscoveryConfig {
1760            enabled: false,
1761            max_observation_rate: 10,
1762            observe_all_paths: false,
1763        };
1764        
1765        let mut params = TransportParameters::default();
1766        params.address_discovery = Some(config);
1767        
1768        let mut encoded = Vec::new();
1769        params.write(&mut encoded);
1770        
1771        // Should decode with no address discovery since enabled=false
1772        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1773            .expect("Failed to decode");
1774        
1775        // Since we don't encode when disabled, it should be None after decoding
1776        assert!(decoded.address_discovery.is_none());
1777    }
1778
1779    #[test]
1780    fn test_address_discovery_serialization_roundtrip() {
1781        let config = AddressDiscoveryConfig {
1782            enabled: true,
1783            max_observation_rate: 42,
1784            observe_all_paths: true,
1785        };
1786        
1787        let mut params = TransportParameters::default();
1788        params.address_discovery = Some(config);
1789        
1790        let mut encoded = Vec::new();
1791        params.write(&mut encoded);
1792        
1793        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1794            .expect("Failed to decode");
1795        
1796        assert!(decoded.address_discovery.is_some());
1797        let decoded_config = decoded.address_discovery.unwrap();
1798        assert_eq!(decoded_config.enabled, config.enabled);
1799        assert_eq!(decoded_config.max_observation_rate, config.max_observation_rate);
1800        assert_eq!(decoded_config.observe_all_paths, config.observe_all_paths);
1801    }
1802
1803    #[test]
1804    fn test_address_discovery_rate_truncation() {
1805        // Test that values > 63 are truncated to 6 bits
1806        let config = AddressDiscoveryConfig {
1807            enabled: true,
1808            max_observation_rate: 255, // Will be truncated to 63 (0x3F)
1809            observe_all_paths: true,
1810        };
1811        
1812        let mut params = TransportParameters::default();
1813        params.address_discovery = Some(config);
1814        
1815        let mut encoded = Vec::new();
1816        params.write(&mut encoded);
1817        
1818        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1819            .expect("Failed to decode");
1820        
1821        let decoded_config = decoded.address_discovery.unwrap();
1822        assert_eq!(decoded_config.max_observation_rate, 63); // 255 & 0x3F = 63
1823    }
1824
1825    #[test]
1826    fn test_address_discovery_bit_encoding() {
1827        // Test all combinations of flags
1828        let test_cases = vec![
1829            (true, false, 0),    // enabled only
1830            (true, true, 0),     // enabled + observe_all_paths
1831            (true, false, 25),   // enabled + rate
1832            (true, true, 50),    // all flags + rate
1833        ];
1834        
1835        for (enabled, observe_all, rate) in test_cases {
1836            let config = AddressDiscoveryConfig {
1837                enabled,
1838                max_observation_rate: rate,
1839                observe_all_paths: observe_all,
1840            };
1841            
1842            let mut params = TransportParameters::default();
1843            params.address_discovery = Some(config);
1844            
1845            let mut encoded = Vec::new();
1846            params.write(&mut encoded);
1847            
1848            let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1849                .expect("Failed to decode");
1850            
1851            let decoded_config = decoded.address_discovery.unwrap();
1852            assert_eq!(decoded_config.enabled, enabled);
1853            assert_eq!(decoded_config.observe_all_paths, observe_all);
1854            assert_eq!(decoded_config.max_observation_rate, rate);
1855        }
1856    }
1857
1858    #[test]
1859    fn test_address_discovery_malformed_length() {
1860        use bytes::BufMut;
1861        
1862        // Create a malformed parameter with wrong length
1863        let mut encoded = Vec::new();
1864        encoded.write_var(TransportParameterId::AddressDiscovery as u64);
1865        encoded.write_var(2); // Wrong length - should be 1
1866        encoded.put_u8(0x80); // Some data
1867        encoded.put_u8(0x00); // Extra byte
1868        
1869        let result = TransportParameters::read(Side::Client, &mut encoded.as_slice());
1870        assert!(result.is_err());
1871        assert!(matches!(result.unwrap_err(), Error::Malformed));
1872    }
1873
1874    #[test]
1875    fn test_address_discovery_duplicate_parameter() {
1876        use bytes::BufMut;
1877        
1878        // Create parameters with duplicate address discovery
1879        let mut encoded = Vec::new();
1880        
1881        // First occurrence
1882        encoded.write_var(TransportParameterId::AddressDiscovery as u64);
1883        encoded.write_var(1);
1884        encoded.put_u8(0x80); // enabled=true
1885        
1886        // Duplicate occurrence
1887        encoded.write_var(TransportParameterId::AddressDiscovery as u64);
1888        encoded.write_var(1);
1889        encoded.put_u8(0xC0); // Different config
1890        
1891        let result = TransportParameters::read(Side::Client, &mut encoded.as_slice());
1892        assert!(result.is_err());
1893        assert!(matches!(result.unwrap_err(), Error::Malformed));
1894    }
1895
1896    #[test]
1897    fn test_address_discovery_with_other_parameters() {
1898        // Test that address discovery works alongside other transport parameters
1899        let mut params = TransportParameters::default();
1900        params.max_idle_timeout = VarInt::from_u32(30000);
1901        params.initial_max_data = VarInt::from_u32(1_000_000);
1902        params.address_discovery = Some(AddressDiscoveryConfig {
1903            enabled: true,
1904            max_observation_rate: 15,
1905            observe_all_paths: true,
1906        });
1907        
1908        let mut encoded = Vec::new();
1909        params.write(&mut encoded);
1910        
1911        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1912            .expect("Failed to decode");
1913        
1914        // Check all parameters are preserved
1915        assert_eq!(decoded.max_idle_timeout, params.max_idle_timeout);
1916        assert_eq!(decoded.initial_max_data, params.initial_max_data);
1917        assert!(decoded.address_discovery.is_some());
1918        
1919        let decoded_config = decoded.address_discovery.unwrap();
1920        assert_eq!(decoded_config.enabled, true);
1921        assert_eq!(decoded_config.max_observation_rate, 15);
1922        assert_eq!(decoded_config.observe_all_paths, true);
1923    }
1924    
1925    // Include comprehensive tests module
1926    mod comprehensive_tests {
1927        include!("transport_parameters/tests.rs");
1928    }
1929}