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    // v0.2: Hybrid fields removed - pure PQC only
375}
376
377impl AddressDiscoveryConfig {
378    /// Get the numeric value for this configuration as per IETF spec
379    pub fn to_value(&self) -> VarInt {
380        match self {
381            Self::SendOnly => VarInt::from_u32(0),
382            Self::ReceiveOnly => VarInt::from_u32(1),
383            Self::SendAndReceive => VarInt::from_u32(2),
384        }
385    }
386
387    /// Create from numeric value as per IETF spec
388    pub fn from_value(value: VarInt) -> Result<Self, Error> {
389        match value.into_inner() {
390            0 => Ok(Self::SendOnly),
391            1 => Ok(Self::ReceiveOnly),
392            2 => Ok(Self::SendAndReceive),
393            _ => Err(Error::Malformed),
394        }
395    }
396}
397
398/// Role of an endpoint in NAT traversal coordination
399#[derive(Debug, Copy, Clone, Eq, PartialEq)]
400pub enum NatTraversalRole {
401    /// Client endpoint (initiates connections, on-demand)
402    Client,
403    /// Server endpoint (accepts connections, always reachable)
404    Server {
405        /// Whether this server can act as a relay for other connections
406        can_relay: bool,
407    },
408    /// Bootstrap/relay endpoint (publicly reachable, coordinates traversal)
409    Bootstrap,
410}
411
412/// A server's preferred address
413///
414/// This is communicated as a transport parameter during TLS session establishment.
415#[derive(Debug, Copy, Clone, Eq, PartialEq)]
416pub(crate) struct PreferredAddress {
417    pub(crate) address_v4: Option<SocketAddrV4>,
418    pub(crate) address_v6: Option<SocketAddrV6>,
419    pub(crate) connection_id: ConnectionId,
420    pub(crate) stateless_reset_token: ResetToken,
421}
422
423impl PreferredAddress {
424    fn wire_size(&self) -> u16 {
425        4 + 2 + 16 + 2 + 1 + self.connection_id.len() as u16 + 16
426    }
427
428    fn write<W: BufMut>(&self, w: &mut W) {
429        w.write(self.address_v4.map_or(Ipv4Addr::UNSPECIFIED, |x| *x.ip()));
430        w.write::<u16>(self.address_v4.map_or(0, |x| x.port()));
431        w.write(self.address_v6.map_or(Ipv6Addr::UNSPECIFIED, |x| *x.ip()));
432        w.write::<u16>(self.address_v6.map_or(0, |x| x.port()));
433        w.write::<u8>(self.connection_id.len() as u8);
434        w.put_slice(&self.connection_id);
435        w.put_slice(&self.stateless_reset_token);
436    }
437
438    fn read<R: Buf>(r: &mut R) -> Result<Self, Error> {
439        let ip_v4 = r.get::<Ipv4Addr>()?;
440        let port_v4 = r.get::<u16>()?;
441        let ip_v6 = r.get::<Ipv6Addr>()?;
442        let port_v6 = r.get::<u16>()?;
443        let cid_len = r.get::<u8>()?;
444        if r.remaining() < cid_len as usize || cid_len > MAX_CID_SIZE as u8 {
445            return Err(Error::Malformed);
446        }
447        let mut stage = [0; MAX_CID_SIZE];
448        r.copy_to_slice(&mut stage[0..cid_len as usize]);
449        let cid = ConnectionId::new(&stage[0..cid_len as usize]);
450        if r.remaining() < 16 {
451            return Err(Error::Malformed);
452        }
453        let mut token = [0; RESET_TOKEN_SIZE];
454        r.copy_to_slice(&mut token);
455        let address_v4 = if ip_v4.is_unspecified() && port_v4 == 0 {
456            None
457        } else {
458            Some(SocketAddrV4::new(ip_v4, port_v4))
459        };
460        let address_v6 = if ip_v6.is_unspecified() && port_v6 == 0 {
461            None
462        } else {
463            Some(SocketAddrV6::new(ip_v6, port_v6, 0, 0))
464        };
465        if address_v4.is_none() && address_v6.is_none() {
466            return Err(Error::IllegalValue);
467        }
468        Ok(Self {
469            address_v4,
470            address_v6,
471            connection_id: cid,
472            stateless_reset_token: token.into(),
473        })
474    }
475}
476
477/// Errors encountered while decoding `TransportParameters`
478#[derive(Debug, Copy, Clone, Eq, PartialEq, Error)]
479pub enum Error {
480    /// Parameters that are semantically invalid
481    #[error("parameter had illegal value")]
482    IllegalValue,
483    /// Catch-all error for problems while decoding transport parameters
484    #[error("parameters were malformed")]
485    Malformed,
486}
487
488impl From<Error> for TransportError {
489    fn from(e: Error) -> Self {
490        match e {
491            Error::IllegalValue => Self::TRANSPORT_PARAMETER_ERROR("illegal value"),
492            Error::Malformed => Self::TRANSPORT_PARAMETER_ERROR("malformed"),
493        }
494    }
495}
496
497impl From<UnexpectedEnd> for Error {
498    fn from(_: UnexpectedEnd) -> Self {
499        Self::Malformed
500    }
501}
502
503impl TransportParameters {
504    /// Encode `TransportParameters` into buffer
505    pub fn write<W: BufMut>(&self, w: &mut W) {
506        for idx in self
507            .write_order
508            .as_ref()
509            .unwrap_or(&std::array::from_fn(|i| i as u8))
510        {
511            let id = TransportParameterId::SUPPORTED[*idx as usize];
512            match id {
513                TransportParameterId::ReservedTransportParameter => {
514                    if let Some(param) = self.grease_transport_parameter {
515                        param.write(w);
516                    }
517                }
518                TransportParameterId::StatelessResetToken => {
519                    if let Some(ref x) = self.stateless_reset_token {
520                        w.write_var(id as u64);
521                        w.write_var(16);
522                        w.put_slice(x);
523                    }
524                }
525                TransportParameterId::DisableActiveMigration => {
526                    if self.disable_active_migration {
527                        w.write_var(id as u64);
528                        w.write_var(0);
529                    }
530                }
531                TransportParameterId::MaxDatagramFrameSize => {
532                    if let Some(x) = self.max_datagram_frame_size {
533                        w.write_var(id as u64);
534                        w.write_var(x.size() as u64);
535                        w.write(x);
536                    }
537                }
538                TransportParameterId::PreferredAddress => {
539                    if let Some(ref x) = self.preferred_address {
540                        w.write_var(id as u64);
541                        w.write_var(x.wire_size() as u64);
542                        x.write(w);
543                    }
544                }
545                TransportParameterId::OriginalDestinationConnectionId => {
546                    if let Some(ref cid) = self.original_dst_cid {
547                        w.write_var(id as u64);
548                        w.write_var(cid.len() as u64);
549                        w.put_slice(cid);
550                    }
551                }
552                TransportParameterId::InitialSourceConnectionId => {
553                    if let Some(ref cid) = self.initial_src_cid {
554                        w.write_var(id as u64);
555                        w.write_var(cid.len() as u64);
556                        w.put_slice(cid);
557                    }
558                }
559                TransportParameterId::RetrySourceConnectionId => {
560                    if let Some(ref cid) = self.retry_src_cid {
561                        w.write_var(id as u64);
562                        w.write_var(cid.len() as u64);
563                        w.put_slice(cid);
564                    }
565                }
566                TransportParameterId::GreaseQuicBit => {
567                    if self.grease_quic_bit {
568                        w.write_var(id as u64);
569                        w.write_var(0);
570                    }
571                }
572                TransportParameterId::MinAckDelayDraft07 => {
573                    if let Some(x) = self.min_ack_delay {
574                        w.write_var(id as u64);
575                        w.write_var(x.size() as u64);
576                        w.write(x);
577                    }
578                }
579                TransportParameterId::NatTraversal => {
580                    if let Some(ref config) = self.nat_traversal {
581                        // Per draft-seemann-quic-nat-traversal-02:
582                        // - Client sends empty value to indicate support
583                        // - Server sends VarInt concurrency limit
584                        match config {
585                            NatTraversalConfig::ClientSupport => {
586                                // Client sends empty value
587                                w.write_var(id as u64);
588                                w.write_var(0); // Empty value
589                            }
590                            NatTraversalConfig::ServerSupport { concurrency_limit } => {
591                                // Server sends concurrency limit as VarInt
592                                w.write_var(id as u64);
593                                w.write_var(concurrency_limit.size() as u64);
594                                w.write_var(concurrency_limit.0);
595                            }
596                        }
597                    }
598                }
599                TransportParameterId::AddressDiscovery => {
600                    if let Some(ref config) = self.address_discovery {
601                        w.write_var(id as u64);
602                        let value = config.to_value();
603                        w.write_var(value.size() as u64);
604                        w.write_var(value.into_inner());
605                    }
606                }
607                TransportParameterId::RfcNatTraversal => {
608                    if self.rfc_nat_traversal {
609                        // Send empty parameter to indicate support
610                        w.write_var(id as u64);
611                        w.write_var(0); // Empty value
612                    }
613                }
614                TransportParameterId::PqcAlgorithms => {
615                    if let Some(ref algorithms) = self.pqc_algorithms {
616                        w.write_var(id as u64);
617                        // Encode as bit field: 2 bits for pure PQC algorithms (v0.2)
618                        let mut value = 0u8;
619                        if algorithms.ml_kem_768 {
620                            value |= 1 << 0;
621                        }
622                        if algorithms.ml_dsa_65 {
623                            value |= 1 << 1;
624                        }
625                        // v0.2: Bits 2-3 reserved (hybrid removed)
626                        w.write_var(1u64); // Length is always 1 byte
627                        w.write(value);
628                    }
629                }
630                id => {
631                    macro_rules! write_params {
632                        {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr_2021,)*} => {
633                            match id {
634                                $(TransportParameterId::$id => {
635                                    if self.$name.0 != $default {
636                                        w.write_var(id as u64);
637                                        w.write(VarInt::try_from(self.$name.size()).unwrap());
638                                        w.write(self.$name);
639                                    }
640                                })*,
641                                _ => {
642                                    // This should never be reached for supported parameters
643                                    // All supported parameters should be handled in specific match arms above
644                                    panic!("Unsupported transport parameter reached write implementation: {id:?}");
645                                }
646                            }
647                        }
648                    }
649                    apply_params!(write_params);
650                }
651            }
652        }
653    }
654
655    /// Decode `TransportParameters` from buffer
656    pub fn read<R: Buf>(side: Side, r: &mut R) -> Result<Self, Error> {
657        // Initialize to protocol-specified defaults
658        let mut params = Self::default();
659
660        // State to check for duplicate transport parameters.
661        macro_rules! param_state {
662            {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr_2021,)*} => {{
663                struct ParamState {
664                    $($name: bool,)*
665                }
666
667                ParamState {
668                    $($name: false,)*
669                }
670            }}
671        }
672        let mut got = apply_params!(param_state);
673
674        while r.has_remaining() {
675            let id = r.get_var()?;
676            let len = r.get_var()?;
677            if (r.remaining() as u64) < len {
678                return Err(Error::Malformed);
679            }
680            let len = len as usize;
681            let Ok(id) = TransportParameterId::try_from(id) else {
682                // unknown transport parameters are ignored
683                r.advance(len);
684                continue;
685            };
686
687            match id {
688                TransportParameterId::OriginalDestinationConnectionId => {
689                    decode_cid(len, &mut params.original_dst_cid, r)?
690                }
691                TransportParameterId::StatelessResetToken => {
692                    if len != 16 || params.stateless_reset_token.is_some() {
693                        return Err(Error::Malformed);
694                    }
695                    let mut tok = [0; RESET_TOKEN_SIZE];
696                    r.copy_to_slice(&mut tok);
697                    params.stateless_reset_token = Some(tok.into());
698                }
699                TransportParameterId::DisableActiveMigration => {
700                    if len != 0 || params.disable_active_migration {
701                        return Err(Error::Malformed);
702                    }
703                    params.disable_active_migration = true;
704                }
705                TransportParameterId::PreferredAddress => {
706                    if params.preferred_address.is_some() {
707                        return Err(Error::Malformed);
708                    }
709                    params.preferred_address = Some(PreferredAddress::read(&mut r.take(len))?);
710                }
711                TransportParameterId::InitialSourceConnectionId => {
712                    decode_cid(len, &mut params.initial_src_cid, r)?
713                }
714                TransportParameterId::RetrySourceConnectionId => {
715                    decode_cid(len, &mut params.retry_src_cid, r)?
716                }
717                TransportParameterId::MaxDatagramFrameSize => {
718                    if len > 8 || params.max_datagram_frame_size.is_some() {
719                        return Err(Error::Malformed);
720                    }
721                    params.max_datagram_frame_size = Some(r.get().map_err(|_| Error::Malformed)?);
722                }
723                TransportParameterId::GreaseQuicBit => match len {
724                    0 => params.grease_quic_bit = true,
725                    _ => return Err(Error::Malformed),
726                },
727                TransportParameterId::MinAckDelayDraft07 => {
728                    params.min_ack_delay = Some(r.get().map_err(|_| Error::Malformed)?)
729                }
730                TransportParameterId::NatTraversal => {
731                    if params.nat_traversal.is_some() {
732                        return Err(Error::Malformed);
733                    }
734                    // Per draft-seemann-quic-nat-traversal-02:
735                    // - Empty value (len=0) indicates ClientSupport
736                    // - VarInt value indicates ServerSupport with concurrency limit
737                    // P2P support: Either side can send either parameter type
738                    match len {
739                        0 => {
740                            // Empty value - ClientSupport
741                            // Traditional: Client -> Server
742                            // P2P: Either peer can send this
743                            params.nat_traversal = Some(NatTraversalConfig::ClientSupport);
744                        }
745                        _ if len > 0 => {
746                            // VarInt value - ServerSupport with concurrency limit
747                            // Traditional: Server -> Client
748                            // P2P: Either peer can send this
749                            let limit = r.get_var()?;
750                            if limit == 0 {
751                                return Err(Error::IllegalValue);
752                            }
753                            params.nat_traversal = Some(NatTraversalConfig::ServerSupport {
754                                concurrency_limit: VarInt::from_u64(limit)
755                                    .map_err(|_| Error::IllegalValue)?,
756                            });
757                        }
758                        _ => {
759                            // This should be unreachable, but included for safety
760                            return Err(Error::IllegalValue);
761                        }
762                    }
763                }
764                TransportParameterId::AddressDiscovery => {
765                    if params.address_discovery.is_some() {
766                        return Err(Error::Malformed);
767                    }
768                    let value = r.get_var()?;
769                    let varint = VarInt::from_u64(value).map_err(|_| Error::Malformed)?;
770                    params.address_discovery = Some(AddressDiscoveryConfig::from_value(varint)?);
771                }
772                TransportParameterId::RfcNatTraversal => {
773                    if params.rfc_nat_traversal {
774                        return Err(Error::Malformed);
775                    }
776                    if len != 0 {
777                        // Must be empty parameter
778                        return Err(Error::Malformed);
779                    }
780                    params.rfc_nat_traversal = true;
781                }
782                TransportParameterId::PqcAlgorithms => {
783                    if params.pqc_algorithms.is_some() {
784                        return Err(Error::Malformed);
785                    }
786                    if len != 1 {
787                        return Err(Error::Malformed);
788                    }
789                    let value = r.get::<u8>()?;
790                    // v0.2: Only decode pure PQC algorithms (bits 2-3 reserved)
791                    params.pqc_algorithms = Some(PqcAlgorithms {
792                        ml_kem_768: (value & (1 << 0)) != 0,
793                        ml_dsa_65: (value & (1 << 1)) != 0,
794                    });
795                }
796                _ => {
797                    macro_rules! parse {
798                        {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr_2021,)*} => {
799                            match id {
800                                $(TransportParameterId::$id => {
801                                    let value = r.get::<VarInt>()?;
802                                    if len != value.size() || got.$name { return Err(Error::Malformed); }
803                                    params.$name = value.into();
804                                    got.$name = true;
805                                })*
806                                _ => r.advance(len),
807                            }
808                        }
809                    }
810                    apply_params!(parse);
811                }
812            }
813        }
814
815        // Semantic validation with detailed error reporting
816
817        // Validate individual parameters
818        validate_ack_delay_exponent(params.ack_delay_exponent.0 as u8)
819            .map_err(|_| Error::IllegalValue)?;
820
821        validate_max_ack_delay(params.max_ack_delay).map_err(|_| Error::IllegalValue)?;
822
823        validate_active_connection_id_limit(params.active_connection_id_limit)
824            .map_err(|_| Error::IllegalValue)?;
825
826        validate_max_udp_payload_size(params.max_udp_payload_size)
827            .map_err(|_| Error::IllegalValue)?;
828
829        // Stream count validation
830        if params.initial_max_streams_bidi.0 > MAX_STREAM_COUNT {
831            TransportParameterErrorHandler::log_validation_failure(
832                "initial_max_streams_bidi",
833                params.initial_max_streams_bidi.0,
834                &format!("must be <= {MAX_STREAM_COUNT}"),
835                "RFC 9000 Section 4.6-2",
836            );
837            return Err(Error::IllegalValue);
838        }
839        if params.initial_max_streams_uni.0 > MAX_STREAM_COUNT {
840            TransportParameterErrorHandler::log_validation_failure(
841                "initial_max_streams_uni",
842                params.initial_max_streams_uni.0,
843                &format!("must be <= {MAX_STREAM_COUNT}"),
844                "RFC 9000 Section 4.6-2",
845            );
846            return Err(Error::IllegalValue);
847        }
848
849        // Min/max ack delay validation
850        validate_min_ack_delay(params.min_ack_delay, params.max_ack_delay)
851            .map_err(|_| Error::IllegalValue)?;
852
853        // Server-only parameter validation
854        validate_server_only_params(side, &params).map_err(|_| Error::IllegalValue)?;
855
856        // Preferred address validation
857        if let Some(ref pref_addr) = params.preferred_address {
858            if pref_addr.connection_id.is_empty() {
859                TransportParameterErrorHandler::log_semantic_error(
860                    "preferred_address with empty connection_id",
861                    "RFC 9000 Section 18.2-4.38.1",
862                );
863                return Err(Error::IllegalValue);
864            }
865        }
866
867        // NAT traversal parameter validation with detailed logging
868        if let Some(ref nat_config) = params.nat_traversal {
869            // Validate NAT traversal configuration based on side
870            match (side, nat_config) {
871                // Traditional: Server receives ClientSupport from client
872                (Side::Server, NatTraversalConfig::ClientSupport) => {
873                    tracing::debug!("Server received valid ClientSupport NAT traversal parameter");
874                }
875                // Traditional: Client receives ServerSupport from server
876                (Side::Client, NatTraversalConfig::ServerSupport { concurrency_limit }) => {
877                    tracing::debug!(
878                        "Client received valid ServerSupport with concurrency_limit: {}",
879                        concurrency_limit
880                    );
881                }
882                // P2P: Server receives ServerSupport from peer (symmetric P2P)
883                (Side::Server, NatTraversalConfig::ServerSupport { concurrency_limit }) => {
884                    tracing::debug!(
885                        "P2P: Server received ServerSupport with concurrency_limit: {} (symmetric P2P)",
886                        concurrency_limit
887                    );
888                    // Validate concurrency limit (1-100 per draft-seemann-quic-nat-traversal-02)
889                    if concurrency_limit.0 == 0 || concurrency_limit.0 > 100 {
890                        TransportParameterErrorHandler::log_validation_failure(
891                            "nat_traversal_concurrency_limit",
892                            concurrency_limit.0,
893                            "1-100",
894                            "draft-seemann-quic-nat-traversal-02",
895                        );
896                        return Err(Error::IllegalValue);
897                    }
898                }
899                // P2P: Client receives ClientSupport from peer (symmetric P2P)
900                (Side::Client, NatTraversalConfig::ClientSupport) => {
901                    tracing::debug!("P2P: Client received ClientSupport (symmetric P2P)");
902                    // Valid for P2P - both peers have client capabilities
903                }
904            }
905        }
906
907        Ok(params)
908    }
909
910    /// Negotiate effective NAT traversal concurrency limit for this connection
911    ///
912    /// Returns the effective concurrency limit based on local and remote NAT traversal
913    /// configurations. For P2P connections where both peers have `ServerSupport`,
914    /// returns the minimum of the two limits. For traditional client/server, returns
915    /// the server's limit. Returns `None` if NAT traversal is not configured.
916    ///
917    /// # Examples
918    ///
919    /// ```ignore
920    /// use ant_quic::VarInt;
921    /// use ant_quic::TransportParameters;
922    /// use ant_quic::NatTraversalConfig;
923    ///
924    /// // P2P: Both peers have ServerSupport - use minimum
925    /// let local = NatTraversalConfig::ServerSupport {
926    ///     concurrency_limit: VarInt::from_u32(10),
927    /// };
928    /// let mut remote_params = TransportParameters::default();
929    /// remote_params.nat_traversal = Some(NatTraversalConfig::ServerSupport {
930    ///     concurrency_limit: VarInt::from_u32(5),
931    /// });
932    /// assert_eq!(remote_params.negotiated_nat_concurrency_limit(&local), Some(5));
933    /// ```
934    pub fn negotiated_nat_concurrency_limit(
935        &self,
936        local_config: &NatTraversalConfig,
937    ) -> Option<u64> {
938        match (&self.nat_traversal, local_config) {
939            // P2P: Both sides have ServerSupport - use minimum for fairness
940            (
941                Some(NatTraversalConfig::ServerSupport {
942                    concurrency_limit: remote,
943                }),
944                NatTraversalConfig::ServerSupport {
945                    concurrency_limit: local,
946                },
947            ) => Some(local.0.min(remote.0)),
948
949            // Traditional: One side server, one side client - use server's limit
950            (
951                Some(NatTraversalConfig::ServerSupport { concurrency_limit }),
952                NatTraversalConfig::ClientSupport,
953            )
954            | (
955                Some(NatTraversalConfig::ClientSupport),
956                NatTraversalConfig::ServerSupport { concurrency_limit },
957            ) => Some(concurrency_limit.0),
958
959            // Both clients or no NAT traversal - no concurrency limit
960            _ => None,
961        }
962    }
963
964    /// Check if this connection supports bidirectional NAT traversal (P2P)
965    ///
966    /// Returns `true` if the remote peer sent `ServerSupport`, indicating they
967    /// can accept NAT traversal path validation requests. This is used to detect
968    /// P2P connections where both peers have equal capabilities.
969    ///
970    /// # Examples
971    ///
972    /// ```ignore
973    /// use ant_quic::VarInt;
974    /// use ant_quic::TransportParameters;
975    /// use ant_quic::NatTraversalConfig;
976    ///
977    /// let mut params = TransportParameters::default();
978    /// params.nat_traversal = Some(NatTraversalConfig::ServerSupport {
979    ///     concurrency_limit: VarInt::from_u32(5),
980    /// });
981    /// assert!(params.supports_bidirectional_nat_traversal());
982    ///
983    /// let mut client_params = TransportParameters::default();
984    /// client_params.nat_traversal = Some(NatTraversalConfig::ClientSupport);
985    /// assert!(!client_params.supports_bidirectional_nat_traversal());
986    /// ```
987    pub fn supports_bidirectional_nat_traversal(&self) -> bool {
988        matches!(
989            &self.nat_traversal,
990            Some(NatTraversalConfig::ServerSupport { .. })
991        )
992    }
993}
994
995/// A reserved transport parameter.
996///
997/// It has an identifier of the form 31 * N + 27 for the integer value of N.
998/// Such identifiers are reserved to exercise the requirement that unknown transport parameters be ignored.
999/// The reserved transport parameter has no semantics and can carry arbitrary values.
1000/// It may be included in transport parameters sent to the peer, and should be ignored when received.
1001///
1002/// See spec: <https://www.rfc-editor.org/rfc/rfc9000.html#section-18.1>
1003#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1004pub(crate) struct ReservedTransportParameter {
1005    /// The reserved identifier of the transport parameter
1006    id: VarInt,
1007
1008    /// Buffer to store the parameter payload
1009    payload: [u8; Self::MAX_PAYLOAD_LEN],
1010
1011    /// The number of bytes to include in the wire format from the `payload` buffer
1012    payload_len: usize,
1013}
1014
1015impl ReservedTransportParameter {
1016    /// Generates a transport parameter with a random payload and a reserved ID.
1017    ///
1018    /// The implementation is inspired by quic-go and quiche:
1019    /// 1. <https://github.com/quic-go/quic-go/blob/3e0a67b2476e1819752f04d75968de042b197b56/internal/wire/transport_parameters.go#L338-L344>
1020    /// 2. <https://github.com/google/quiche/blob/cb1090b20c40e2f0815107857324e99acf6ec567/quiche/quic/core/crypto/transport_parameters.cc#L843-L860>
1021    fn random(rng: &mut impl RngCore) -> Result<Self, TransportError> {
1022        let id = Self::generate_reserved_id(rng)?;
1023
1024        let payload_len = rng.gen_range(0..Self::MAX_PAYLOAD_LEN);
1025
1026        let payload = {
1027            let mut slice = [0u8; Self::MAX_PAYLOAD_LEN];
1028            rng.fill_bytes(&mut slice[..payload_len]);
1029            slice
1030        };
1031
1032        Ok(Self {
1033            id,
1034            payload,
1035            payload_len,
1036        })
1037    }
1038
1039    fn write(&self, w: &mut impl BufMut) {
1040        w.write_var(self.id.0);
1041        w.write_var(self.payload_len as u64);
1042        w.put_slice(&self.payload[..self.payload_len]);
1043    }
1044
1045    /// Generates a random reserved identifier of the form `31 * N + 27`, as required by RFC 9000.
1046    /// Reserved transport parameter identifiers are used to test compliance with the requirement
1047    /// that unknown transport parameters must be ignored by peers.
1048    /// See: <https://www.rfc-editor.org/rfc/rfc9000.html#section-18.1> and <https://www.rfc-editor.org/rfc/rfc9000.html#section-22.3>
1049    fn generate_reserved_id(rng: &mut impl RngCore) -> Result<VarInt, TransportError> {
1050        let id = {
1051            let rand = rng.gen_range(0u64..(1 << 62) - 27);
1052            let n = rand / 31;
1053            31 * n + 27
1054        };
1055        debug_assert!(
1056            id % 31 == 27,
1057            "generated id does not have the form of 31 * N + 27"
1058        );
1059        VarInt::from_u64(id).map_err(|_| TransportError {
1060            code: TransportErrorCode::INTERNAL_ERROR,
1061            frame: None,
1062            reason: "generated id does not fit into range of allowed transport parameter IDs"
1063                .to_string(),
1064        })
1065    }
1066
1067    /// The maximum length of the payload to include as the parameter payload.
1068    /// This value is not a specification-imposed limit but is chosen to match
1069    /// the limit used by other implementations of QUIC, e.g., quic-go and quiche.
1070    const MAX_PAYLOAD_LEN: usize = 16;
1071}
1072
1073#[repr(u64)]
1074#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1075pub(crate) enum TransportParameterId {
1076    // https://www.rfc-editor.org/rfc/rfc9000.html#iana-tp-table
1077    OriginalDestinationConnectionId = 0x00,
1078    MaxIdleTimeout = 0x01,
1079    StatelessResetToken = 0x02,
1080    MaxUdpPayloadSize = 0x03,
1081    InitialMaxData = 0x04,
1082    InitialMaxStreamDataBidiLocal = 0x05,
1083    InitialMaxStreamDataBidiRemote = 0x06,
1084    InitialMaxStreamDataUni = 0x07,
1085    InitialMaxStreamsBidi = 0x08,
1086    InitialMaxStreamsUni = 0x09,
1087    AckDelayExponent = 0x0A,
1088    MaxAckDelay = 0x0B,
1089    DisableActiveMigration = 0x0C,
1090    PreferredAddress = 0x0D,
1091    ActiveConnectionIdLimit = 0x0E,
1092    InitialSourceConnectionId = 0x0F,
1093    RetrySourceConnectionId = 0x10,
1094
1095    // Smallest possible ID of reserved transport parameter https://datatracker.ietf.org/doc/html/rfc9000#section-22.3
1096    ReservedTransportParameter = 0x1B,
1097
1098    // https://www.rfc-editor.org/rfc/rfc9221.html#section-3
1099    MaxDatagramFrameSize = 0x20,
1100
1101    // https://www.rfc-editor.org/rfc/rfc9287.html#section-3
1102    GreaseQuicBit = 0x2AB2,
1103
1104    // https://datatracker.ietf.org/doc/html/draft-ietf-quic-ack-frequency#section-10.1
1105    MinAckDelayDraft07 = 0xFF04DE1B,
1106
1107    // NAT Traversal Extension - draft-seemann-quic-nat-traversal-01
1108    // Transport parameter ID from the IETF draft specification
1109    NatTraversal = 0x3d7e9f0bca12fea6,
1110
1111    // RFC NAT Traversal Format Support
1112    // Indicates support for RFC-compliant NAT traversal frame formats
1113    RfcNatTraversal = 0x3d7e9f0bca12fea8,
1114
1115    // Address Discovery Extension - draft-ietf-quic-address-discovery-00
1116    // Transport parameter ID from the specification
1117    AddressDiscovery = 0x9f81a176,
1118    // Post-Quantum Cryptography Algorithms
1119    // Using experimental range for now (will be assigned by IANA)
1120    PqcAlgorithms = 0x50C0,
1121}
1122
1123impl TransportParameterId {
1124    /// Array with all supported transport parameter IDs
1125    const SUPPORTED: [Self; 25] = [
1126        Self::MaxIdleTimeout,
1127        Self::MaxUdpPayloadSize,
1128        Self::InitialMaxData,
1129        Self::InitialMaxStreamDataBidiLocal,
1130        Self::InitialMaxStreamDataBidiRemote,
1131        Self::InitialMaxStreamDataUni,
1132        Self::InitialMaxStreamsBidi,
1133        Self::InitialMaxStreamsUni,
1134        Self::AckDelayExponent,
1135        Self::MaxAckDelay,
1136        Self::ActiveConnectionIdLimit,
1137        Self::ReservedTransportParameter,
1138        Self::StatelessResetToken,
1139        Self::DisableActiveMigration,
1140        Self::MaxDatagramFrameSize,
1141        Self::PreferredAddress,
1142        Self::OriginalDestinationConnectionId,
1143        Self::InitialSourceConnectionId,
1144        Self::RetrySourceConnectionId,
1145        Self::GreaseQuicBit,
1146        Self::MinAckDelayDraft07,
1147        Self::NatTraversal,
1148        Self::RfcNatTraversal,
1149        Self::AddressDiscovery,
1150        Self::PqcAlgorithms,
1151    ];
1152}
1153
1154impl std::cmp::PartialEq<u64> for TransportParameterId {
1155    fn eq(&self, other: &u64) -> bool {
1156        *other == (*self as u64)
1157    }
1158}
1159
1160impl TryFrom<u64> for TransportParameterId {
1161    type Error = ();
1162
1163    fn try_from(value: u64) -> Result<Self, Self::Error> {
1164        let param = match value {
1165            id if Self::MaxIdleTimeout == id => Self::MaxIdleTimeout,
1166            id if Self::MaxUdpPayloadSize == id => Self::MaxUdpPayloadSize,
1167            id if Self::InitialMaxData == id => Self::InitialMaxData,
1168            id if Self::InitialMaxStreamDataBidiLocal == id => Self::InitialMaxStreamDataBidiLocal,
1169            id if Self::InitialMaxStreamDataBidiRemote == id => {
1170                Self::InitialMaxStreamDataBidiRemote
1171            }
1172            id if Self::InitialMaxStreamDataUni == id => Self::InitialMaxStreamDataUni,
1173            id if Self::InitialMaxStreamsBidi == id => Self::InitialMaxStreamsBidi,
1174            id if Self::InitialMaxStreamsUni == id => Self::InitialMaxStreamsUni,
1175            id if Self::AckDelayExponent == id => Self::AckDelayExponent,
1176            id if Self::MaxAckDelay == id => Self::MaxAckDelay,
1177            id if Self::ActiveConnectionIdLimit == id => Self::ActiveConnectionIdLimit,
1178            id if Self::ReservedTransportParameter == id => Self::ReservedTransportParameter,
1179            id if Self::StatelessResetToken == id => Self::StatelessResetToken,
1180            id if Self::DisableActiveMigration == id => Self::DisableActiveMigration,
1181            id if Self::MaxDatagramFrameSize == id => Self::MaxDatagramFrameSize,
1182            id if Self::PreferredAddress == id => Self::PreferredAddress,
1183            id if Self::OriginalDestinationConnectionId == id => {
1184                Self::OriginalDestinationConnectionId
1185            }
1186            id if Self::InitialSourceConnectionId == id => Self::InitialSourceConnectionId,
1187            id if Self::RetrySourceConnectionId == id => Self::RetrySourceConnectionId,
1188            id if Self::GreaseQuicBit == id => Self::GreaseQuicBit,
1189            id if Self::MinAckDelayDraft07 == id => Self::MinAckDelayDraft07,
1190            id if Self::NatTraversal == id => Self::NatTraversal,
1191            id if Self::RfcNatTraversal == id => Self::RfcNatTraversal,
1192            id if Self::AddressDiscovery == id => Self::AddressDiscovery,
1193            id if Self::PqcAlgorithms == id => Self::PqcAlgorithms,
1194            _ => return Err(()),
1195        };
1196        Ok(param)
1197    }
1198}
1199
1200fn decode_cid(len: usize, value: &mut Option<ConnectionId>, r: &mut impl Buf) -> Result<(), Error> {
1201    if len > MAX_CID_SIZE || value.is_some() || r.remaining() < len {
1202        return Err(Error::Malformed);
1203    }
1204
1205    *value = Some(ConnectionId::from_buf(r, len));
1206    Ok(())
1207}
1208
1209#[cfg(test)]
1210mod test {
1211    use super::*;
1212
1213    #[test]
1214    fn test_nat_traversal_transport_parameter_encoding_decoding() {
1215        // Test draft-compliant NAT traversal parameter encoding/decoding
1216
1217        // Test 1: Client sends empty value, server reads it
1218        let client_config = NatTraversalConfig::ClientSupport;
1219
1220        let mut client_params = TransportParameters::default();
1221        client_params.nat_traversal = Some(client_config);
1222
1223        let mut encoded = Vec::new();
1224        client_params.write(&mut encoded);
1225
1226        // Server reads client params
1227        let server_decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1228            .expect("Failed to decode client transport parameters");
1229
1230        // Server should see that client supports NAT traversal
1231        assert!(server_decoded.nat_traversal.is_some());
1232        let server_view = server_decoded.nat_traversal.unwrap();
1233        assert!(matches!(server_view, NatTraversalConfig::ClientSupport));
1234
1235        // Test 2: Server sends concurrency limit, client reads it
1236        let server_config = NatTraversalConfig::ServerSupport {
1237            concurrency_limit: VarInt::from_u32(5),
1238        };
1239
1240        let mut server_params = TransportParameters::default();
1241        server_params.nat_traversal = Some(server_config);
1242
1243        let mut encoded = Vec::new();
1244        server_params.write(&mut encoded);
1245
1246        // Client reads server params
1247        let client_decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1248            .expect("Failed to decode server transport parameters");
1249
1250        // Client should see server's concurrency limit
1251        assert!(client_decoded.nat_traversal.is_some());
1252        let client_view = client_decoded.nat_traversal.unwrap();
1253        assert!(matches!(
1254            client_view,
1255            NatTraversalConfig::ServerSupport { .. }
1256        ));
1257        assert_eq!(client_view.concurrency_limit(), Some(VarInt::from_u32(5)));
1258    }
1259
1260    #[test]
1261    fn test_nat_traversal_parameter_without_peer_id() {
1262        // Test client-side NAT traversal config (sends empty value)
1263        let config = NatTraversalConfig::ClientSupport;
1264
1265        let mut params = TransportParameters::default();
1266        params.nat_traversal = Some(config);
1267
1268        let mut encoded = Vec::new();
1269        params.write(&mut encoded);
1270
1271        // Server reads client's parameters
1272        let decoded_params = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1273            .expect("Failed to decode transport parameters");
1274
1275        let decoded_config = decoded_params
1276            .nat_traversal
1277            .expect("NAT traversal config should be present");
1278
1279        assert!(matches!(decoded_config, NatTraversalConfig::ClientSupport));
1280
1281        // Test server-side NAT traversal config (sends concurrency limit)
1282        let server_config = NatTraversalConfig::ServerSupport {
1283            concurrency_limit: VarInt::from_u32(4),
1284        };
1285
1286        let mut server_params = TransportParameters::default();
1287        server_params.nat_traversal = Some(server_config);
1288
1289        let mut server_encoded = Vec::new();
1290        server_params.write(&mut server_encoded);
1291
1292        // Client reads server's parameters
1293        let decoded_server_params =
1294            TransportParameters::read(Side::Client, &mut server_encoded.as_slice())
1295                .expect("Failed to decode server transport parameters");
1296
1297        let decoded_server_config = decoded_server_params
1298            .nat_traversal
1299            .expect("Server NAT traversal config should be present");
1300
1301        assert!(matches!(
1302            decoded_server_config,
1303            NatTraversalConfig::ServerSupport { concurrency_limit } if concurrency_limit == VarInt::from_u32(4)
1304        ));
1305    }
1306
1307    #[test]
1308    fn test_transport_parameters_without_nat_traversal() {
1309        // Test that transport parameters work without NAT traversal config
1310        let mut params = TransportParameters::default();
1311        params.nat_traversal = None;
1312
1313        let mut encoded = Vec::new();
1314        params.write(&mut encoded);
1315
1316        let decoded_params = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1317            .expect("Failed to decode transport parameters");
1318
1319        assert!(decoded_params.nat_traversal.is_none());
1320    }
1321
1322    #[test]
1323    fn test_nat_traversal_draft_compliant_encoding() {
1324        // Test draft-seemann-quic-nat-traversal-01 compliant encoding
1325
1326        // Test 1: Client sends empty value
1327        let client_config = NatTraversalConfig::ClientSupport;
1328
1329        let mut client_params = TransportParameters::default();
1330        client_params.nat_traversal = Some(client_config);
1331
1332        let mut encoded = Vec::new();
1333        client_params.write(&mut encoded);
1334
1335        // Verify the encoded data contains empty value for client
1336        // Find the NAT traversal parameter in the encoded data
1337        use bytes::Buf;
1338        let mut cursor = &encoded[..];
1339        while cursor.has_remaining() {
1340            let id = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1341            let len = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1342            if id.0 == 0x3d7e9f0bca12fea6 {
1343                // Found NAT traversal parameter
1344                assert_eq!(len.0, 0, "Client should send empty value");
1345                break;
1346            }
1347            // Skip this parameter
1348            cursor.advance(len.0 as usize);
1349        }
1350
1351        // Test 2: Server sends 1-byte concurrency limit
1352        let server_config = NatTraversalConfig::ServerSupport {
1353            concurrency_limit: VarInt::from_u32(5),
1354        };
1355
1356        let mut server_params = TransportParameters::default();
1357        server_params.nat_traversal = Some(server_config);
1358
1359        let mut encoded = Vec::new();
1360        server_params.write(&mut encoded);
1361
1362        // Verify the encoded data contains 1-byte value for server
1363        let mut cursor = &encoded[..];
1364        while cursor.has_remaining() {
1365            let id = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1366            let len = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1367            if id.0 == 0x3d7e9f0bca12fea6 {
1368                // Found NAT traversal parameter
1369                assert_eq!(len.0, 1, "Server should send 1-byte value");
1370                let limit = cursor.chunk()[0];
1371                assert_eq!(limit, 5, "Server should send concurrency limit");
1372                break;
1373            }
1374            // Skip this parameter
1375            cursor.advance(len.0 as usize);
1376        }
1377    }
1378
1379    #[test]
1380    fn test_nat_traversal_draft_compliant_decoding() {
1381        // Test 1: Decode empty value from client
1382        let mut buf = Vec::new();
1383        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1384        buf.write_var(0); // Empty value
1385
1386        let params = TransportParameters::read(Side::Server, &mut buf.as_slice())
1387            .expect("Failed to decode transport parameters");
1388
1389        let config = params
1390            .nat_traversal
1391            .expect("NAT traversal should be present");
1392        assert!(matches!(config, NatTraversalConfig::ClientSupport));
1393
1394        // Test 2: Decode 1-byte concurrency limit from server
1395        let mut buf = Vec::new();
1396        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1397        buf.write_var(1); // 1-byte value
1398        buf.put_u8(7); // Concurrency limit of 7
1399
1400        let params = TransportParameters::read(Side::Client, &mut buf.as_slice())
1401            .expect("Failed to decode transport parameters");
1402
1403        let config = params
1404            .nat_traversal
1405            .expect("NAT traversal should be present");
1406        assert!(matches!(
1407            config,
1408            NatTraversalConfig::ServerSupport { concurrency_limit } if concurrency_limit == VarInt::from_u32(7)
1409        ));
1410
1411        // Test 3: Invalid length should fail
1412        let mut buf = Vec::new();
1413        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1414        buf.write_var(2); // Invalid 2-byte value
1415        buf.put_u8(7);
1416        buf.put_u8(8);
1417
1418        let result = TransportParameters::read(Side::Client, &mut buf.as_slice());
1419        assert!(result.is_err(), "Should fail with invalid length");
1420    }
1421
1422    #[test]
1423    fn test_nat_traversal_parameter_id() {
1424        // Verify the correct parameter ID is used
1425        assert_eq!(
1426            TransportParameterId::NatTraversal as u64,
1427            0x3d7e9f0bca12fea6
1428        );
1429    }
1430
1431    #[test]
1432    fn test_nat_traversal_simple_encoding() {
1433        // Test the simplified NAT traversal encoding per draft-seemann-quic-nat-traversal-02
1434
1435        // Test 1: Client sends empty parameter
1436        let mut client_params = TransportParameters::default();
1437        client_params.nat_traversal = Some(NatTraversalConfig::ClientSupport);
1438
1439        let mut encoded = Vec::new();
1440        client_params.write(&mut encoded);
1441
1442        // Verify it can be decoded by server
1443        let decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1444            .expect("Should decode client params");
1445        assert!(matches!(
1446            decoded.nat_traversal,
1447            Some(NatTraversalConfig::ClientSupport)
1448        ));
1449
1450        // Test 2: Server sends concurrency limit
1451        let mut server_params = TransportParameters::default();
1452        server_params.nat_traversal = Some(NatTraversalConfig::ServerSupport {
1453            concurrency_limit: VarInt::from_u32(10),
1454        });
1455
1456        let mut encoded = Vec::new();
1457        server_params.write(&mut encoded);
1458
1459        // Verify it can be decoded by client
1460        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1461            .expect("Should decode server params");
1462
1463        match decoded.nat_traversal {
1464            Some(NatTraversalConfig::ServerSupport { concurrency_limit }) => {
1465                assert_eq!(concurrency_limit, VarInt::from_u32(10));
1466            }
1467            _ => panic!("Expected ServerSupport variant"),
1468        }
1469    }
1470
1471    #[test]
1472    fn test_nat_traversal_config_validation() {
1473        // Test valid client configuration
1474        let client_config = NatTraversalConfig::ClientSupport;
1475        assert!(client_config.is_client());
1476        assert_eq!(client_config.concurrency_limit(), None);
1477
1478        // Test valid server configuration
1479        let server_config = NatTraversalConfig::server(VarInt::from_u32(5)).unwrap();
1480        assert!(server_config.is_server());
1481        assert_eq!(server_config.concurrency_limit(), Some(VarInt::from_u32(5)));
1482
1483        // Test invalid server configuration (concurrency limit = 0)
1484        let result = NatTraversalConfig::server(VarInt::from_u32(0));
1485        assert!(result.is_err());
1486
1487        // Test invalid server configuration (concurrency limit > 100)
1488        let result = NatTraversalConfig::server(VarInt::from_u32(101));
1489        assert!(result.is_err());
1490
1491        // Test valid server configurations at boundaries
1492        let min_server = NatTraversalConfig::server(VarInt::from_u32(1)).unwrap();
1493        assert_eq!(min_server.concurrency_limit(), Some(VarInt::from_u32(1)));
1494
1495        let max_server = NatTraversalConfig::server(VarInt::from_u32(100)).unwrap();
1496        assert_eq!(max_server.concurrency_limit(), Some(VarInt::from_u32(100)));
1497    }
1498
1499    #[test]
1500    fn test_nat_traversal_role_validation() {
1501        // Test client role validation - should fail when received by client
1502        let mut buf = Vec::new();
1503        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1504        buf.write_var(0); // Empty value (client role)
1505
1506        // P2P: Client receiving client role should succeed (symmetric P2P connection)
1507        let result = TransportParameters::read(Side::Client, &mut buf.as_slice());
1508        assert!(
1509            result.is_ok(),
1510            "P2P: Client should accept ClientSupport from peer for symmetric P2P"
1511        );
1512
1513        // Traditional: Server receiving client role should succeed
1514        let result = TransportParameters::read(Side::Server, &mut buf.as_slice());
1515        assert!(
1516            result.is_ok(),
1517            "Server should accept ClientSupport from client"
1518        );
1519
1520        // Test server role validation
1521        let mut buf = Vec::new();
1522        buf.write_var(0x3d7e9f0bca12fea6); // NAT traversal parameter ID
1523        buf.write_var(1); // 1-byte value (server role)
1524        buf.put_u8(5); // Concurrency limit
1525
1526        // P2P: Server receiving server role should succeed (symmetric P2P connection)
1527        let result = TransportParameters::read(Side::Server, &mut buf.as_slice());
1528        assert!(
1529            result.is_ok(),
1530            "P2P: Server should accept ServerSupport from peer for symmetric P2P"
1531        );
1532
1533        // Traditional: Client receiving server role should succeed
1534        let result = TransportParameters::read(Side::Client, &mut buf.as_slice());
1535        assert!(
1536            result.is_ok(),
1537            "Client should accept ServerSupport from server"
1538        );
1539    }
1540
1541    #[test]
1542    fn test_nat_traversal_parameter_combinations() {
1543        // Test that NAT traversal works with other transport parameters
1544        let nat_config = NatTraversalConfig::ClientSupport;
1545
1546        let mut params = TransportParameters::default();
1547        params.nat_traversal = Some(nat_config);
1548        params.max_idle_timeout = VarInt::from_u32(30000);
1549        params.initial_max_data = VarInt::from_u32(1048576);
1550        params.grease_quic_bit = true;
1551
1552        // Test encoding
1553        let mut encoded = Vec::new();
1554        params.write(&mut encoded);
1555        assert!(!encoded.is_empty());
1556
1557        // Test decoding
1558        let decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1559            .expect("Should decode successfully");
1560
1561        // Verify NAT traversal config is preserved
1562        let decoded_config = decoded
1563            .nat_traversal
1564            .expect("NAT traversal should be present");
1565        assert!(matches!(decoded_config, NatTraversalConfig::ClientSupport));
1566
1567        // Verify other parameters are preserved
1568        assert_eq!(decoded.max_idle_timeout, VarInt::from_u32(30000));
1569        assert_eq!(decoded.initial_max_data, VarInt::from_u32(1048576));
1570        assert!(decoded.grease_quic_bit);
1571    }
1572
1573    #[test]
1574    fn test_nat_traversal_default_config() {
1575        let default_config = NatTraversalConfig::default();
1576
1577        assert!(matches!(default_config, NatTraversalConfig::ClientSupport));
1578        assert!(default_config.is_client());
1579        assert_eq!(default_config.concurrency_limit(), None);
1580    }
1581
1582    #[test]
1583    fn test_nat_traversal_endpoint_role_negotiation() {
1584        // Test complete client-server negotiation
1585
1586        // 1. Client creates parameters with NAT traversal support
1587        let client_config = NatTraversalConfig::ClientSupport;
1588
1589        let mut client_params = TransportParameters::default();
1590        client_params.nat_traversal = Some(client_config);
1591
1592        // 2. Client encodes and sends to server
1593        let mut client_encoded = Vec::new();
1594        client_params.write(&mut client_encoded);
1595
1596        // 3. Server receives and decodes client parameters
1597        let server_received =
1598            TransportParameters::read(Side::Server, &mut client_encoded.as_slice())
1599                .expect("Server should decode client params");
1600
1601        // Server should see client role
1602        let server_view = server_received
1603            .nat_traversal
1604            .expect("NAT traversal should be present");
1605        assert!(matches!(server_view, NatTraversalConfig::ClientSupport));
1606
1607        // 4. Server creates response with server role
1608        let server_config = NatTraversalConfig::ServerSupport {
1609            concurrency_limit: VarInt::from_u32(8),
1610        };
1611
1612        let mut server_params = TransportParameters::default();
1613        server_params.nat_traversal = Some(server_config);
1614
1615        // 5. Server encodes and sends to client
1616        let mut server_encoded = Vec::new();
1617        server_params.write(&mut server_encoded);
1618
1619        // 6. Client receives and decodes server parameters
1620        let client_received =
1621            TransportParameters::read(Side::Client, &mut server_encoded.as_slice())
1622                .expect("Client should decode server params");
1623
1624        // Client should see server role with concurrency limit
1625        let client_view = client_received
1626            .nat_traversal
1627            .expect("NAT traversal should be present");
1628        assert!(matches!(
1629            client_view,
1630            NatTraversalConfig::ServerSupport { concurrency_limit } if concurrency_limit == VarInt::from_u32(8)
1631        ));
1632    }
1633
1634    // ===== P2P NAT Traversal Tests =====
1635
1636    #[test]
1637    fn test_p2p_nat_traversal_both_server_support() {
1638        // Test P2P scenario: Both peers send ServerSupport with concurrency limits
1639        // This should now PASS after implementing P2P support
1640
1641        let peer1_config = NatTraversalConfig::ServerSupport {
1642            concurrency_limit: VarInt::from_u32(10),
1643        };
1644        let _peer2_config = NatTraversalConfig::ServerSupport {
1645            concurrency_limit: VarInt::from_u32(5),
1646        };
1647
1648        // Peer 1 sends its ServerSupport config
1649        let mut peer1_params = TransportParameters::default();
1650        peer1_params.nat_traversal = Some(peer1_config);
1651
1652        let mut encoded = Vec::new();
1653        peer1_params.write(&mut encoded);
1654
1655        // Peer 2 (acting as server side) receives peer 1's ServerSupport
1656        // This currently FAILS but should PASS after P2P fix
1657        let decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1658            .expect("P2P: Server should accept ServerSupport from peer");
1659
1660        // Should preserve peer's ServerSupport config
1661        assert!(matches!(
1662            decoded.nat_traversal,
1663            Some(NatTraversalConfig::ServerSupport { concurrency_limit })
1664            if concurrency_limit == VarInt::from_u32(10)
1665        ));
1666    }
1667
1668    #[test]
1669    fn test_p2p_nat_traversal_concurrency_negotiation() {
1670        // Test that P2P connections negotiate minimum concurrency limit
1671
1672        let local = NatTraversalConfig::ServerSupport {
1673            concurrency_limit: VarInt::from_u32(10),
1674        };
1675        let mut remote_params = TransportParameters::default();
1676        remote_params.nat_traversal = Some(NatTraversalConfig::ServerSupport {
1677            concurrency_limit: VarInt::from_u32(5),
1678        });
1679
1680        // Negotiated limit should be minimum of both
1681        let negotiated = remote_params.negotiated_nat_concurrency_limit(&local);
1682        assert_eq!(negotiated, Some(5));
1683
1684        // Test opposite direction
1685        let local2 = NatTraversalConfig::ServerSupport {
1686            concurrency_limit: VarInt::from_u32(3),
1687        };
1688        let mut remote_params2 = TransportParameters::default();
1689        remote_params2.nat_traversal = Some(NatTraversalConfig::ServerSupport {
1690            concurrency_limit: VarInt::from_u32(8),
1691        });
1692
1693        let negotiated2 = remote_params2.negotiated_nat_concurrency_limit(&local2);
1694        assert_eq!(negotiated2, Some(3));
1695    }
1696
1697    #[test]
1698    fn test_p2p_nat_traversal_invalid_concurrency() {
1699        // Test that P2P connections reject zero concurrency limit
1700
1701        let config = NatTraversalConfig::ServerSupport {
1702            concurrency_limit: VarInt::from_u32(0), // Invalid - must be > 0
1703        };
1704
1705        let mut params = TransportParameters::default();
1706        params.nat_traversal = Some(config);
1707
1708        let mut encoded = Vec::new();
1709        params.write(&mut encoded);
1710
1711        // Should reject zero concurrency limit
1712        let result = TransportParameters::read(Side::Server, &mut encoded.as_slice());
1713        assert!(
1714            matches!(result, Err(Error::IllegalValue)),
1715            "Should reject concurrency_limit = 0"
1716        );
1717    }
1718
1719    #[test]
1720    fn test_p2p_nat_traversal_max_concurrency() {
1721        // Test that P2P connections reject excessive concurrency limit
1722
1723        let config = NatTraversalConfig::ServerSupport {
1724            concurrency_limit: VarInt::from_u32(101), // Exceeds max of 100
1725        };
1726
1727        let mut params = TransportParameters::default();
1728        params.nat_traversal = Some(config);
1729
1730        let mut encoded = Vec::new();
1731        params.write(&mut encoded);
1732
1733        // Should reject concurrency limit > 100
1734        let result = TransportParameters::read(Side::Server, &mut encoded.as_slice());
1735        assert!(
1736            matches!(result, Err(Error::IllegalValue)),
1737            "Should reject concurrency_limit > 100"
1738        );
1739    }
1740
1741    #[test]
1742    fn test_p2p_both_client_support() {
1743        // Test P2P scenario: Client receiving ClientSupport from peer
1744        // This means both peers have client-only capabilities
1745
1746        let config = NatTraversalConfig::ClientSupport;
1747
1748        let mut params = TransportParameters::default();
1749        params.nat_traversal = Some(config);
1750
1751        let mut encoded = Vec::new();
1752        params.write(&mut encoded);
1753
1754        // Client receiving ClientSupport (currently FAILS, should PASS after P2P fix)
1755        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1756            .expect("P2P: Client should accept ClientSupport from peer");
1757
1758        assert!(matches!(
1759            decoded.nat_traversal,
1760            Some(NatTraversalConfig::ClientSupport)
1761        ));
1762    }
1763
1764    #[test]
1765    fn test_p2p_helper_methods() {
1766        // Test helper methods for P2P capability detection
1767
1768        // Test supports_bidirectional_nat_traversal
1769        let mut params_with_server = TransportParameters::default();
1770        params_with_server.nat_traversal = Some(NatTraversalConfig::ServerSupport {
1771            concurrency_limit: VarInt::from_u32(5),
1772        });
1773        assert!(params_with_server.supports_bidirectional_nat_traversal());
1774
1775        let mut params_with_client = TransportParameters::default();
1776        params_with_client.nat_traversal = Some(NatTraversalConfig::ClientSupport);
1777        assert!(!params_with_client.supports_bidirectional_nat_traversal());
1778
1779        let params_without_nat = TransportParameters::default();
1780        assert!(!params_without_nat.supports_bidirectional_nat_traversal());
1781
1782        // Test mixed client/server negotiation
1783        let local = NatTraversalConfig::ClientSupport;
1784        let mut remote_params = TransportParameters::default();
1785        remote_params.nat_traversal = Some(NatTraversalConfig::ServerSupport {
1786            concurrency_limit: VarInt::from_u32(10),
1787        });
1788
1789        // Should use server's limit
1790        let negotiated = remote_params.negotiated_nat_concurrency_limit(&local);
1791        assert_eq!(negotiated, Some(10));
1792    }
1793
1794    // ===== Regression Tests =====
1795
1796    #[test]
1797    fn test_traditional_client_server_unchanged() {
1798        // Verify that traditional client/server NAT traversal still works
1799        // after P2P changes (regression test)
1800
1801        // Client sends empty value (ClientSupport)
1802        let client_config = NatTraversalConfig::ClientSupport;
1803        let mut client_params = TransportParameters::default();
1804        client_params.nat_traversal = Some(client_config);
1805
1806        let mut encoded = Vec::new();
1807        client_params.write(&mut encoded);
1808
1809        // Server decodes client's parameters
1810        let server_decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1811            .expect("Traditional client/server should still work");
1812
1813        assert!(matches!(
1814            server_decoded.nat_traversal,
1815            Some(NatTraversalConfig::ClientSupport)
1816        ));
1817    }
1818
1819    #[test]
1820    fn test_traditional_server_client_unchanged() {
1821        // Verify that traditional server/client NAT traversal still works
1822        // after P2P changes (regression test)
1823
1824        // Server sends concurrency limit (ServerSupport)
1825        let server_config = NatTraversalConfig::ServerSupport {
1826            concurrency_limit: VarInt::from_u32(10),
1827        };
1828        let mut server_params = TransportParameters::default();
1829        server_params.nat_traversal = Some(server_config);
1830
1831        let mut encoded = Vec::new();
1832        server_params.write(&mut encoded);
1833
1834        // Client decodes server's parameters
1835        let client_decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1836            .expect("Traditional server/client should still work");
1837
1838        assert!(matches!(
1839            client_decoded.nat_traversal,
1840            Some(NatTraversalConfig::ServerSupport { concurrency_limit })
1841            if concurrency_limit == VarInt::from_u32(10)
1842        ));
1843    }
1844
1845    #[test]
1846    fn coding() {
1847        let mut buf = Vec::new();
1848        let params = TransportParameters {
1849            initial_src_cid: Some(ConnectionId::new(&[])),
1850            original_dst_cid: Some(ConnectionId::new(&[])),
1851            initial_max_streams_bidi: 16u32.into(),
1852            initial_max_streams_uni: 16u32.into(),
1853            ack_delay_exponent: 2u32.into(),
1854            max_udp_payload_size: 1200u32.into(),
1855            preferred_address: Some(PreferredAddress {
1856                address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
1857                address_v6: Some(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 24, 0, 0)),
1858                connection_id: ConnectionId::new(&[0x42]),
1859                stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
1860            }),
1861            grease_quic_bit: true,
1862            min_ack_delay: Some(2_000u32.into()),
1863            ..TransportParameters::default()
1864        };
1865        params.write(&mut buf);
1866        assert_eq!(
1867            TransportParameters::read(Side::Client, &mut buf.as_slice()).unwrap(),
1868            params
1869        );
1870    }
1871
1872    #[test]
1873    fn reserved_transport_parameter_generate_reserved_id() {
1874        use rand::rngs::mock::StepRng;
1875        let mut rngs = [
1876            StepRng::new(0, 1),
1877            StepRng::new(1, 1),
1878            StepRng::new(27, 1),
1879            StepRng::new(31, 1),
1880            StepRng::new(u32::MAX as u64, 1),
1881            StepRng::new(u32::MAX as u64 - 1, 1),
1882            StepRng::new(u32::MAX as u64 + 1, 1),
1883            StepRng::new(u32::MAX as u64 - 27, 1),
1884            StepRng::new(u32::MAX as u64 + 27, 1),
1885            StepRng::new(u32::MAX as u64 - 31, 1),
1886            StepRng::new(u32::MAX as u64 + 31, 1),
1887            StepRng::new(u64::MAX, 1),
1888            StepRng::new(u64::MAX - 1, 1),
1889            StepRng::new(u64::MAX - 27, 1),
1890            StepRng::new(u64::MAX - 31, 1),
1891            StepRng::new(1 << 62, 1),
1892            StepRng::new((1 << 62) - 1, 1),
1893            StepRng::new((1 << 62) + 1, 1),
1894            StepRng::new((1 << 62) - 27, 1),
1895            StepRng::new((1 << 62) + 27, 1),
1896            StepRng::new((1 << 62) - 31, 1),
1897            StepRng::new((1 << 62) + 31, 1),
1898        ];
1899        for rng in &mut rngs {
1900            let id = ReservedTransportParameter::generate_reserved_id(rng).unwrap();
1901            assert!(id.0 % 31 == 27)
1902        }
1903    }
1904
1905    #[test]
1906    fn reserved_transport_parameter_ignored_when_read() {
1907        let mut buf = Vec::new();
1908        let reserved_parameter =
1909            ReservedTransportParameter::random(&mut rand::thread_rng()).unwrap();
1910        assert!(reserved_parameter.payload_len < ReservedTransportParameter::MAX_PAYLOAD_LEN);
1911        assert!(reserved_parameter.id.0 % 31 == 27);
1912
1913        reserved_parameter.write(&mut buf);
1914        assert!(!buf.is_empty());
1915        let read_params = TransportParameters::read(Side::Server, &mut buf.as_slice()).unwrap();
1916        assert_eq!(read_params, TransportParameters::default());
1917    }
1918
1919    #[test]
1920    fn read_semantic_validation() {
1921        #[allow(clippy::type_complexity)]
1922        let illegal_params_builders: Vec<Box<dyn FnMut(&mut TransportParameters)>> = vec![
1923            Box::new(|t| {
1924                // This min_ack_delay is bigger than max_ack_delay!
1925                let min_ack_delay = t.max_ack_delay.0 * 1_000 + 1;
1926                t.min_ack_delay = Some(VarInt::from_u64(min_ack_delay).unwrap())
1927            }),
1928            Box::new(|t| {
1929                // Preferred address can only be sent by senders (and we are reading the transport
1930                // params as a client)
1931                t.preferred_address = Some(PreferredAddress {
1932                    address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
1933                    address_v6: None,
1934                    connection_id: ConnectionId::new(&[]),
1935                    stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
1936                })
1937            }),
1938        ];
1939
1940        for mut builder in illegal_params_builders {
1941            let mut buf = Vec::new();
1942            let mut params = TransportParameters::default();
1943            builder(&mut params);
1944            params.write(&mut buf);
1945
1946            assert_eq!(
1947                TransportParameters::read(Side::Server, &mut buf.as_slice()),
1948                Err(Error::IllegalValue)
1949            );
1950        }
1951    }
1952
1953    #[test]
1954    fn resumption_params_validation() {
1955        let high_limit = TransportParameters {
1956            initial_max_streams_uni: 32u32.into(),
1957            ..TransportParameters::default()
1958        };
1959        let low_limit = TransportParameters {
1960            initial_max_streams_uni: 16u32.into(),
1961            ..TransportParameters::default()
1962        };
1963        high_limit.validate_resumption_from(&low_limit).unwrap();
1964        low_limit.validate_resumption_from(&high_limit).unwrap_err();
1965    }
1966
1967    #[test]
1968    fn test_address_discovery_parameter_id() {
1969        // Test that ADDRESS_DISCOVERY parameter ID is defined correctly
1970        assert_eq!(TransportParameterId::AddressDiscovery as u64, 0x9f81a176);
1971    }
1972
1973    #[test]
1974    fn test_address_discovery_config_struct() {
1975        // Test AddressDiscoveryConfig enum variants
1976        let send_only = AddressDiscoveryConfig::SendOnly;
1977        let receive_only = AddressDiscoveryConfig::ReceiveOnly;
1978        let send_receive = AddressDiscoveryConfig::SendAndReceive;
1979
1980        assert_eq!(send_only.to_value(), VarInt::from_u32(0));
1981        assert_eq!(receive_only.to_value(), VarInt::from_u32(1));
1982        assert_eq!(send_receive.to_value(), VarInt::from_u32(2));
1983    }
1984
1985    #[test]
1986    fn test_address_discovery_config_from_value() {
1987        // Test from_value conversion
1988        assert_eq!(
1989            AddressDiscoveryConfig::from_value(VarInt::from_u32(0)).unwrap(),
1990            AddressDiscoveryConfig::SendOnly
1991        );
1992        assert_eq!(
1993            AddressDiscoveryConfig::from_value(VarInt::from_u32(1)).unwrap(),
1994            AddressDiscoveryConfig::ReceiveOnly
1995        );
1996        assert_eq!(
1997            AddressDiscoveryConfig::from_value(VarInt::from_u32(2)).unwrap(),
1998            AddressDiscoveryConfig::SendAndReceive
1999        );
2000        assert!(AddressDiscoveryConfig::from_value(VarInt::from_u32(3)).is_err());
2001    }
2002
2003    #[test]
2004    fn test_transport_parameters_with_address_discovery() {
2005        // Test that TransportParameters can hold address_discovery field
2006        let mut params = TransportParameters::default();
2007        assert!(params.address_discovery.is_none());
2008
2009        let config = AddressDiscoveryConfig::SendAndReceive;
2010
2011        params.address_discovery = Some(config);
2012        assert!(params.address_discovery.is_some());
2013
2014        let stored_config = params.address_discovery.as_ref().unwrap();
2015        assert_eq!(*stored_config, AddressDiscoveryConfig::SendAndReceive);
2016    }
2017
2018    #[test]
2019    fn test_address_discovery_parameter_encoding() {
2020        // Test encoding of address discovery transport parameter
2021        let config = AddressDiscoveryConfig::SendAndReceive;
2022
2023        let mut params = TransportParameters::default();
2024        params.address_discovery = Some(config);
2025
2026        let mut encoded = Vec::new();
2027        params.write(&mut encoded);
2028
2029        // The encoded data should contain our parameter
2030        assert!(!encoded.is_empty());
2031    }
2032
2033    #[test]
2034    fn test_address_discovery_parameter_roundtrip() {
2035        // Test encoding and decoding of address discovery parameter
2036        let config = AddressDiscoveryConfig::ReceiveOnly;
2037
2038        let mut params = TransportParameters::default();
2039        params.address_discovery = Some(config);
2040
2041        let mut encoded = Vec::new();
2042        params.write(&mut encoded);
2043
2044        // Decode as peer
2045        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
2046            .expect("Failed to decode transport parameters");
2047
2048        assert!(decoded.address_discovery.is_some());
2049        let decoded_config = decoded.address_discovery.as_ref().unwrap();
2050        assert_eq!(*decoded_config, AddressDiscoveryConfig::ReceiveOnly);
2051    }
2052
2053    #[test]
2054    fn test_address_discovery_disabled_by_default() {
2055        // Test that address discovery is disabled by default
2056        let params = TransportParameters::default();
2057        assert!(params.address_discovery.is_none());
2058    }
2059
2060    #[test]
2061    fn test_address_discovery_all_variants() {
2062        // Test all address discovery variants roundtrip correctly
2063        for variant in [
2064            AddressDiscoveryConfig::SendOnly,
2065            AddressDiscoveryConfig::ReceiveOnly,
2066            AddressDiscoveryConfig::SendAndReceive,
2067        ] {
2068            let mut params = TransportParameters::default();
2069            params.address_discovery = Some(variant);
2070
2071            let mut encoded = Vec::new();
2072            params.write(&mut encoded);
2073
2074            let decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
2075                .expect("Failed to decode");
2076
2077            assert_eq!(decoded.address_discovery, Some(variant));
2078        }
2079    }
2080
2081    #[test]
2082    fn test_address_discovery_none_not_encoded() {
2083        // Test that None address discovery is not encoded
2084        let mut params = TransportParameters::default();
2085        params.address_discovery = None;
2086
2087        let mut encoded = Vec::new();
2088        params.write(&mut encoded);
2089
2090        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
2091            .expect("Failed to decode");
2092        assert!(decoded.address_discovery.is_none());
2093    }
2094
2095    #[test]
2096    fn test_address_discovery_serialization_roundtrip() {
2097        let config = AddressDiscoveryConfig::SendOnly;
2098
2099        let mut params = TransportParameters::default();
2100        params.address_discovery = Some(config);
2101        params.initial_max_data = VarInt::from_u32(1_000_000);
2102
2103        let mut encoded = Vec::new();
2104        params.write(&mut encoded);
2105
2106        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
2107            .expect("Failed to decode");
2108
2109        assert_eq!(
2110            decoded.address_discovery,
2111            Some(AddressDiscoveryConfig::SendOnly)
2112        );
2113        assert_eq!(decoded.initial_max_data, VarInt::from_u32(1_000_000));
2114    }
2115
2116    #[test]
2117    fn test_address_discovery_invalid_value() {
2118        // Test that invalid values are rejected
2119
2120        let mut encoded = Vec::new();
2121        encoded.write_var(TransportParameterId::AddressDiscovery as u64);
2122        encoded.write_var(1); // Length
2123        encoded.write_var(3); // Invalid value (only 0, 1, 2 are valid)
2124
2125        let result = TransportParameters::read(Side::Client, &mut encoded.as_slice());
2126        assert!(result.is_err());
2127    }
2128
2129    #[test]
2130    fn test_address_discovery_edge_cases() {
2131        // Test edge cases for address discovery
2132
2133        // Test empty parameter (zero-length)
2134        let mut encoded = Vec::new();
2135        encoded.write_var(TransportParameterId::AddressDiscovery as u64);
2136        encoded.write_var(0); // Zero length
2137
2138        let result = TransportParameters::read(Side::Client, &mut encoded.as_slice());
2139        assert!(result.is_err());
2140
2141        // Test value too large
2142        let mut encoded = Vec::new();
2143        encoded.write_var(TransportParameterId::AddressDiscovery as u64);
2144        encoded.write_var(1); // Length
2145        encoded.put_u8(255); // Invalid value (only 0, 1, 2 are valid)
2146
2147        let result = TransportParameters::read(Side::Client, &mut encoded.as_slice());
2148        assert!(result.is_err());
2149    }
2150
2151    #[test]
2152    fn test_address_discovery_malformed_length() {
2153        // Create a malformed parameter with wrong length
2154        let mut encoded = Vec::new();
2155        encoded.write_var(TransportParameterId::AddressDiscovery as u64);
2156        encoded.write_var(1); // Says 1 byte but no data follows
2157
2158        let result = TransportParameters::read(Side::Client, &mut encoded.as_slice());
2159        assert!(result.is_err());
2160        assert!(matches!(result.unwrap_err(), Error::Malformed));
2161    }
2162
2163    #[test]
2164    fn test_address_discovery_duplicate_parameter() {
2165        // Create parameters with duplicate address discovery
2166        let mut encoded = Vec::new();
2167
2168        // First occurrence
2169        encoded.write_var(TransportParameterId::AddressDiscovery as u64);
2170        encoded.write_var(1);
2171        encoded.put_u8(0x80); // enabled=true
2172
2173        // Duplicate occurrence
2174        encoded.write_var(TransportParameterId::AddressDiscovery as u64);
2175        encoded.write_var(1);
2176        encoded.put_u8(0xC0); // Different config
2177
2178        let result = TransportParameters::read(Side::Client, &mut encoded.as_slice());
2179        assert!(result.is_err());
2180        assert!(matches!(result.unwrap_err(), Error::Malformed));
2181    }
2182
2183    #[test]
2184    fn test_address_discovery_with_other_parameters() {
2185        // Test that address discovery works alongside other transport parameters
2186        let mut params = TransportParameters::default();
2187        params.max_idle_timeout = VarInt::from_u32(30000);
2188        params.initial_max_data = VarInt::from_u32(1_000_000);
2189        params.address_discovery = Some(AddressDiscoveryConfig::SendAndReceive);
2190
2191        let mut encoded = Vec::new();
2192        params.write(&mut encoded);
2193
2194        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
2195            .expect("Failed to decode");
2196
2197        // Check all parameters are preserved
2198        assert_eq!(decoded.max_idle_timeout, params.max_idle_timeout);
2199        assert_eq!(decoded.initial_max_data, params.initial_max_data);
2200        assert_eq!(
2201            decoded.address_discovery,
2202            Some(AddressDiscoveryConfig::SendAndReceive)
2203        );
2204    }
2205
2206    #[test]
2207    fn test_pqc_algorithms_transport_parameter() {
2208        // v0.2: Test pure PQC algorithms encoding/decoding
2209        let mut params = TransportParameters::default();
2210        params.pqc_algorithms = Some(PqcAlgorithms {
2211            ml_kem_768: true,
2212            ml_dsa_65: true,
2213        });
2214
2215        // Encode
2216        let mut encoded = Vec::new();
2217        params.write(&mut encoded);
2218
2219        // Decode
2220        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
2221            .expect("Failed to decode");
2222
2223        // Verify
2224        assert!(decoded.pqc_algorithms.is_some());
2225        let pqc = decoded.pqc_algorithms.unwrap();
2226        assert!(pqc.ml_kem_768);
2227        assert!(pqc.ml_dsa_65);
2228    }
2229
2230    #[test]
2231    fn test_pqc_algorithms_all_combinations() {
2232        // v0.2: Test all combinations of pure PQC algorithm flags
2233        for ml_kem in [false, true] {
2234            for ml_dsa in [false, true] {
2235                let mut params = TransportParameters::default();
2236                params.pqc_algorithms = Some(PqcAlgorithms {
2237                    ml_kem_768: ml_kem,
2238                    ml_dsa_65: ml_dsa,
2239                });
2240
2241                // Encode and decode
2242                let mut encoded = Vec::new();
2243                params.write(&mut encoded);
2244                let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
2245                    .expect("Failed to decode");
2246
2247                // Verify
2248                let pqc = decoded.pqc_algorithms.unwrap();
2249                assert_eq!(pqc.ml_kem_768, ml_kem);
2250                assert_eq!(pqc.ml_dsa_65, ml_dsa);
2251            }
2252        }
2253    }
2254
2255    #[test]
2256    fn test_pqc_algorithms_not_sent_when_none() {
2257        // Test that PQC algorithms parameter is not sent when None
2258        let mut params = TransportParameters::default();
2259        params.pqc_algorithms = None;
2260
2261        let mut encoded = Vec::new();
2262        params.write(&mut encoded);
2263
2264        // Check that the parameter ID doesn't appear in the encoding
2265        // (Can't easily check for exact bytes due to VarInt encoding)
2266        let decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
2267            .expect("Failed to decode");
2268        assert!(decoded.pqc_algorithms.is_none());
2269    }
2270
2271    #[test]
2272    fn test_pqc_algorithms_duplicate_parameter() {
2273        // Test that duplicate PQC algorithms parameters are rejected
2274        let mut encoded = Vec::new();
2275
2276        // Write a valid parameter
2277        encoded.write_var(TransportParameterId::PqcAlgorithms as u64);
2278        encoded.write_var(1u64); // Length
2279        encoded.write(0b1111u8); // All algorithms enabled
2280
2281        // Write duplicate
2282        encoded.write_var(TransportParameterId::PqcAlgorithms as u64);
2283        encoded.write_var(1u64);
2284        encoded.write(0b0000u8);
2285
2286        // Should fail to decode
2287        let result = TransportParameters::read(Side::Client, &mut encoded.as_slice());
2288        assert!(result.is_err());
2289        assert!(matches!(result.unwrap_err(), Error::Malformed));
2290    }
2291
2292    // Include comprehensive tests module
2293    mod comprehensive_tests {
2294        include!("transport_parameters/tests.rs");
2295    }
2296}