ant_quic/
transport_parameters.rs

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