wtransport/
config.rs

1//!
2//! This module defines configurations for the WebTransport server and client.
3//!
4//! It provides builders for creating server and client configurations with various options.
5//!
6//! The module includes:
7//! - [`ServerConfig`]: Configuration for the WebTransport server.
8//! - [`ClientConfig`]: Configuration for the WebTransport client.
9//!
10//! Example for creating a server configuration:
11//!
12//! ```no_run
13//! # async fn run() -> anyhow::Result<()> {
14//! use wtransport::Identity;
15//! use wtransport::ServerConfig;
16//!
17//! let server_config = ServerConfig::builder()
18//!     .with_bind_default(443)
19//!     .with_identity(Identity::load_pemfiles("cert.pem", "key.pem").await?)
20//!     .build();
21//!
22//! # Ok(())
23//! # }
24//! ```
25//!
26//! Example for creating a client configuration:
27//!
28//! ```no_run
29//! use wtransport::ClientConfig;
30//!
31//! let client_config = ClientConfig::builder()
32//!     .with_bind_default()
33//!     .with_native_certs()
34//!     .build();
35//! ```
36
37use crate::tls::build_native_cert_store;
38use crate::tls::Identity;
39use quinn::EndpointConfig;
40use quinn::TransportConfig;
41use socket2::Domain as SocketDomain;
42use socket2::Protocol as SocketProtocol;
43use socket2::Socket;
44use socket2::Type as SocketType;
45use std::fmt::Debug;
46use std::fmt::Display;
47use std::future::Future;
48use std::net::IpAddr;
49use std::net::Ipv4Addr;
50use std::net::Ipv6Addr;
51use std::net::SocketAddr;
52use std::net::SocketAddrV4;
53use std::net::SocketAddrV6;
54use std::net::UdpSocket;
55use std::pin::Pin;
56use std::sync::Arc;
57use std::time::Duration;
58
59/// Alias of [`crate::tls::rustls::ServerConfig`].
60pub type TlsServerConfig = crate::tls::rustls::ServerConfig;
61
62/// Alias of [`crate::tls::rustls::ClientConfig`].
63pub type TlsClientConfig = crate::tls::rustls::ClientConfig;
64
65/// Alias of [`crate::quinn::TransportConfig`].
66#[cfg(feature = "quinn")]
67#[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
68pub type QuicTransportConfig = crate::quinn::TransportConfig;
69
70/// Alias of [`crate::quinn::ServerConfig`].
71#[cfg(feature = "quinn")]
72#[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
73pub type QuicServerConfig = crate::quinn::ServerConfig;
74
75/// Alias of [`crate::quinn::ClientConfig`].
76#[cfg(feature = "quinn")]
77#[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
78pub type QuicClientConfig = crate::quinn::ClientConfig;
79
80/// Configuration for IP address socket bind.
81#[derive(Debug, Copy, Clone)]
82pub enum IpBindConfig {
83    /// Bind to LOCALHOST IPv4 address (no IPv6).
84    LocalV4,
85
86    /// Bind to LOCALHOST IPv6 address (no IPv4).
87    LocalV6,
88
89    /// Bind to LOCALHOST both IPv4 and IPv6 address (dual stack, if supported).
90    LocalDual,
91
92    /// Bind to `INADDR_ANY` IPv4 address (no IPv6).
93    InAddrAnyV4,
94
95    /// Bind to `INADDR_ANY` IPv6 address (no IPv4).
96    InAddrAnyV6,
97
98    /// Bind to `INADDR_ANY` both IPv4 and IPv6 address (dual stack, if supported).
99    InAddrAnyDual,
100}
101
102impl IpBindConfig {
103    fn into_ip(self) -> IpAddr {
104        match self {
105            IpBindConfig::LocalV4 => Ipv4Addr::LOCALHOST.into(),
106            IpBindConfig::LocalV6 => Ipv6Addr::LOCALHOST.into(),
107            IpBindConfig::LocalDual => Ipv6Addr::LOCALHOST.into(),
108            IpBindConfig::InAddrAnyV4 => Ipv4Addr::UNSPECIFIED.into(),
109            IpBindConfig::InAddrAnyV6 => Ipv6Addr::UNSPECIFIED.into(),
110            IpBindConfig::InAddrAnyDual => Ipv6Addr::UNSPECIFIED.into(),
111        }
112    }
113
114    fn into_dual_stack_config(self) -> Ipv6DualStackConfig {
115        match self {
116            IpBindConfig::LocalV4 | IpBindConfig::InAddrAnyV4 => Ipv6DualStackConfig::OsDefault,
117            IpBindConfig::LocalV6 | IpBindConfig::InAddrAnyV6 => Ipv6DualStackConfig::Deny,
118            IpBindConfig::LocalDual | IpBindConfig::InAddrAnyDual => Ipv6DualStackConfig::Allow,
119        }
120    }
121}
122
123/// Configuration for IPv6 dual stack.
124#[derive(Debug, Copy, Clone)]
125pub enum Ipv6DualStackConfig {
126    /// Do not configure dual stack. Use OS's default.
127    OsDefault,
128
129    /// Deny dual stack. This is equivalent to `IPV6_V6ONLY`.
130    ///
131    /// Socket will only bind for IPv6 (IPv4 port will still be available).
132    Deny,
133
134    /// Allow dual stack.
135    ///
136    /// Please note that not all configurations/platforms support dual stack.
137    Allow,
138}
139
140/// Invalid idle timeout.
141pub struct InvalidIdleTimeout;
142
143/// Server configuration.
144///
145/// You can create an instance of `ServerConfig` using its builder pattern by calling
146/// the [`builder()`](Self::builder) method.
147/// Once you have an instance, you can further customize it by chaining method calls
148/// to set various configuration options.
149///
150/// ## Configuration Builder States
151///
152/// The configuration process follows a *state-based builder pattern*, where the server
153/// configuration progresses through *3* states.
154///
155/// ### 1. `WantsBindAddress`
156///
157/// The caller must supply a binding address for the server. This is where to specify
158/// the listening port of the server.
159/// The following options are mutually exclusive:
160///
161///   - [`with_bind_default`](ServerConfigBuilder::with_bind_default): the simplest
162///     configuration where only the port will be specified.
163///   - [`with_bind_config`](ServerConfigBuilder::with_bind_config): configures
164///     binding to an address determined by a configuration preset.
165///   - [`with_bind_address`](ServerConfigBuilder::with_bind_address): configures
166///     binding to a custom-specified socket address.
167///   - [`with_bind_address_v6`](ServerConfigBuilder::with_bind_address_v6): configures
168///     binding to a custom-specified socket address for *IPv6*, along with the [dual stack
169///     configuration](Ipv6DualStackConfig).
170///   - [`with_bind_socket`](ServerConfigBuilder::with_bind_socket): configures
171///     binding directly to a custom-specified socket.
172///
173/// Only one of these options can be selected during the client configuration process.
174///
175/// #### Examples:
176///
177/// ```
178/// use wtransport::ServerConfig;
179///
180/// // Configuration for accepting incoming connection on port 443
181/// ServerConfig::builder().with_bind_default(443);
182/// ```
183///
184/// ### 2. `WantsIdentity`
185///
186/// The caller must supply a TLS identity for the server.
187///
188/// - [`with_identity`](ServerConfigBuilder::with_identity): configures
189///   a TLS [`Identity`] for the server.
190/// - [`with_custom_tls`](ServerConfigBuilder::with_custom_tls): sets the TLS
191///   server configuration manually.
192/// - [`with_custom_transport`](ServerConfigBuilder::with_custom_transport): sets the QUIC
193///   transport configuration manually (using default TLS).
194/// - [`with_custom_tls_and_transport`](ServerConfigBuilder::with_custom_tls_and_transport): sets both
195///   a custom TLS and QUIC transport configuration.
196/// - [`build_with_quic_config`](ServerConfigBuilder::build_with_quic_config): directly builds
197///   [`ServerConfig`] providing both TLS and QUIC transport configuration given by
198///   [`quic_config`](QuicServerConfig).
199///
200/// #### Examples:
201/// ```
202/// # use anyhow::Result;
203/// use wtransport::Identity;
204/// use wtransport::ServerConfig;
205///
206/// # async fn run() -> Result<()> {
207/// ServerConfig::builder()
208///     .with_bind_default(443)
209///     .with_identity(Identity::load_pemfiles("cert.pem", "key.pem").await?);
210/// # Ok(())
211/// # }
212/// ```
213///
214/// ### 3. `WantsTransportConfigServer`
215///
216/// The caller can supply *additional* transport configurations.
217/// Multiple options can be given at this stage. Once the configuration is completed, it is possible
218/// to finalize with the method [`build()`](ServerConfigBuilder::build).
219///
220/// All these options can be omitted in the configuration; default values will be used.
221///
222/// - [`max_idle_timeout`](ServerConfigBuilder::max_idle_timeout)
223/// - [`keep_alive_interval`](ServerConfigBuilder::keep_alive_interval)
224/// - [`allow_migration`](ServerConfigBuilder::allow_migration)
225///
226/// #### Examples:
227/// ```
228/// # use anyhow::Result;
229/// use wtransport::ServerConfig;
230/// use wtransport::Identity;
231/// use std::time::Duration;
232///
233/// # async fn run() -> Result<()> {
234/// let server_config = ServerConfig::builder()
235///     .with_bind_default(443)
236///     .with_identity(Identity::load_pemfiles("cert.pem", "key.pem").await?)
237///     .keep_alive_interval(Some(Duration::from_secs(3)))
238///     .build();
239/// # Ok(())
240/// # }
241#[derive(Debug)]
242pub struct ServerConfig {
243    pub(crate) bind_address_config: BindAddressConfig,
244    pub(crate) endpoint_config: quinn::EndpointConfig,
245    pub(crate) quic_config: quinn::ServerConfig,
246}
247
248impl ServerConfig {
249    /// Creates a builder to build up the server configuration.
250    ///
251    /// For more information, see the [`ServerConfigBuilder`] documentation.
252    pub fn builder() -> ServerConfigBuilder<states::WantsBindAddress> {
253        ServerConfigBuilder::default()
254    }
255
256    /// Returns a reference to the inner QUIC endpoint configuration.
257    #[cfg(feature = "quinn")]
258    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
259    pub fn quic_endpoint_config(&self) -> &quinn::EndpointConfig {
260        &self.endpoint_config
261    }
262
263    /// Returns a mutable reference to the inner QUIC endpoint configuration.
264    #[cfg(feature = "quinn")]
265    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
266    pub fn quic_endpoint_config_mut(&mut self) -> &mut quinn::EndpointConfig {
267        &mut self.endpoint_config
268    }
269
270    /// Returns a reference to the inner QUIC configuration.
271    #[cfg(feature = "quinn")]
272    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
273    pub fn quic_config(&self) -> &quinn::ServerConfig {
274        &self.quic_config
275    }
276
277    /// Returns a mutable reference to the inner QUIC configuration.
278    #[cfg(feature = "quinn")]
279    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
280    pub fn quic_config_mut(&mut self) -> &mut quinn::ServerConfig {
281        &mut self.quic_config
282    }
283}
284
285/// Server builder configuration.
286///
287/// The builder might have different state at compile time.
288///
289/// # Examples:
290/// ```no_run
291/// # async fn run() -> anyhow::Result<()> {
292/// # use std::net::Ipv4Addr;
293/// # use std::net::SocketAddr;
294/// # use wtransport::Identity;
295/// # use wtransport::ServerConfig;
296/// let config = ServerConfig::builder()
297///     .with_bind_default(4433)
298///     .with_identity(Identity::load_pemfiles("cert.pem", "key.pem").await?);
299/// # Ok(())
300/// # }
301/// ```
302#[must_use]
303pub struct ServerConfigBuilder<State>(State);
304
305impl ServerConfigBuilder<states::WantsBindAddress> {
306    /// Configures for accepting incoming connections binding ANY IP (allowing IP dual-stack).
307    ///
308    /// `listening_port` is the port where the server will accept incoming connections.
309    ///
310    /// This is equivalent to: [`Self::with_bind_config`] with [`IpBindConfig::InAddrAnyDual`].
311    pub fn with_bind_default(
312        self,
313        listening_port: u16,
314    ) -> ServerConfigBuilder<states::WantsIdentity> {
315        self.with_bind_config(IpBindConfig::InAddrAnyDual, listening_port)
316    }
317
318    /// Sets the binding (local) socket address with a specific [`IpBindConfig`].
319    ///
320    /// `listening_port` is the port where the server will accept incoming connections.
321    pub fn with_bind_config(
322        self,
323        ip_bind_config: IpBindConfig,
324        listening_port: u16,
325    ) -> ServerConfigBuilder<states::WantsIdentity> {
326        let ip_address: IpAddr = ip_bind_config.into_ip();
327
328        match ip_address {
329            IpAddr::V4(ip) => self.with_bind_address(SocketAddr::new(ip.into(), listening_port)),
330            IpAddr::V6(ip) => self.with_bind_address_v6(
331                SocketAddrV6::new(ip, listening_port, 0, 0),
332                ip_bind_config.into_dual_stack_config(),
333            ),
334        }
335    }
336
337    /// Sets the binding (local) socket address for the endpoint.
338    pub fn with_bind_address(
339        self,
340        address: SocketAddr,
341    ) -> ServerConfigBuilder<states::WantsIdentity> {
342        ServerConfigBuilder(states::WantsIdentity {
343            bind_address_config: BindAddressConfig::from(address),
344        })
345    }
346
347    /// Sets the binding (local) socket address for the endpoint with Ipv6 address.
348    ///
349    /// `dual_stack_config` allows/denies dual stack port binding.
350    pub fn with_bind_address_v6(
351        self,
352        address: SocketAddrV6,
353        dual_stack_config: Ipv6DualStackConfig,
354    ) -> ServerConfigBuilder<states::WantsIdentity> {
355        ServerConfigBuilder(states::WantsIdentity {
356            bind_address_config: BindAddressConfig::AddressV6(address, dual_stack_config),
357        })
358    }
359
360    /// Configures the server to bind to a pre-existing [`UdpSocket`].
361    ///
362    /// This allows the server to use an already created socket, which may be beneficial
363    /// for scenarios where socket reuse or specific socket configuration is needed.
364    pub fn with_bind_socket(self, socket: UdpSocket) -> ServerConfigBuilder<states::WantsIdentity> {
365        ServerConfigBuilder(states::WantsIdentity {
366            bind_address_config: BindAddressConfig::Socket(socket),
367        })
368    }
369}
370
371impl ServerConfigBuilder<states::WantsIdentity> {
372    /// Configures TLS with safe defaults and a TLS [`Identity`].
373    ///
374    /// # Example
375    /// ```no_run
376    /// use wtransport::Identity;
377    /// use wtransport::ServerConfig;
378    /// # use anyhow::Result;
379    ///
380    /// # async fn run() -> Result<()> {
381    /// let identity = Identity::load_pemfiles("cert.pem", "key.pem").await?;
382    ///
383    /// let server_config = ServerConfig::builder()
384    ///     .with_bind_default(4433)
385    ///     .with_identity(identity)
386    ///     .build();
387    /// # Ok(())
388    /// # }
389    /// ```
390    pub fn with_identity(
391        self,
392        identity: Identity,
393    ) -> ServerConfigBuilder<states::WantsTransportConfigServer> {
394        use crate::tls::server::build_default_tls_config;
395
396        let tls_config = build_default_tls_config(identity);
397        let quic_endpoint_config = EndpointConfig::default();
398        let quic_transport_config = TransportConfig::default();
399
400        self.with(tls_config, quic_endpoint_config, quic_transport_config)
401    }
402
403    /// Allows for manual configuration of a custom TLS setup using a provided
404    /// [`rustls::ServerConfig`], which must support
405    /// [`rustls::CipherSuite::TLS13_AES_128_GCM_SHA256`]. A suitable configuration
406    /// can be obtained using the `ring` crypto provider with a set of versions containing
407    /// [`rustls::version::TLS13`].
408    ///
409    /// This method is provided for advanced users who need fine-grained control over the
410    /// TLS configuration. It allows you to pass a preconfigured [`rustls::ServerConfig`]
411    /// instance to customize the TLS settings according to your specific requirements.
412    ///
413    /// Generally, it is recommended to use the [`with_identity`](Self::with_identity) method
414    /// to configure TLS with safe defaults and an TLS [`Identity`].
415    ///
416    /// # Example
417    ///
418    /// ```no_run
419    /// use wtransport::tls::rustls;
420    /// use wtransport::ServerConfig;
421    ///
422    /// // Create a custom rustls::ServerConfig with specific TLS settings
423    /// let custom_tls_config = rustls::ServerConfig::builder();
424    /// // Customize TLS settings here...
425    /// # let custom_tls_config = custom_tls_config
426    /// #          .with_no_client_auth()
427    /// #          .with_single_cert(todo!(), todo!()).unwrap();
428    ///
429    /// // Create a ServerConfigBuilder with the custom TLS configuration
430    /// let server_config = ServerConfig::builder()
431    ///     .with_bind_default(4433)
432    ///     .with_custom_tls(custom_tls_config)
433    ///     .build();
434    /// ```
435    pub fn with_custom_tls(
436        self,
437        tls_config: TlsServerConfig,
438    ) -> ServerConfigBuilder<states::WantsTransportConfigServer> {
439        let quic_endpoint_config = EndpointConfig::default();
440        let quic_transport_config = TransportConfig::default();
441
442        self.with(tls_config, quic_endpoint_config, quic_transport_config)
443    }
444
445    /// Configures the server with a custom QUIC transport configuration and a default TLS setup
446    /// using the provided [`Identity`].
447    ///
448    /// This method is useful for scenarios where you need to customize the transport settings
449    /// while relying on a default TLS configuration built from an [`Identity`]. It gives you
450    /// control over the transport layer while maintaining safe and standard TLS settings.
451    ///
452    /// **See**: [`with_identity`](Self::with_identity)
453    /// for a simpler configuration option that does not require custom transport settings.
454    ///
455    /// # Parameters
456    ///
457    /// - `identity`: A reference to an [`Identity`] that contains the server's certificate and
458    ///   private key. This will be used to generate the default TLS configuration.
459    /// - `quic_transport_config`: A custom [`QuicTransportConfig`] instance that allows you to specify
460    ///   various QUIC transport-layer settings according to your requirements.
461    ///
462    /// # Example
463    ///
464    /// ```
465    /// use wtransport::config::QuicTransportConfig;
466    /// use wtransport::Identity;
467    /// use wtransport::ServerConfig;
468    ///
469    /// // Generate a server identity (self signed certificate and private key)
470    /// let identity = Identity::self_signed(["localhost", "127.0.0.1", "::1"]).unwrap();
471    ///
472    /// // Create a custom QuicTransportConfig with specific settings
473    /// let mut custom_transport_config = QuicTransportConfig::default();
474    /// custom_transport_config.datagram_send_buffer_size(1024);
475    ///
476    /// // Create a ServerConfigBuilder with the custom transport configuration and default TLS settings
477    /// let server_config = ServerConfig::builder()
478    ///     .with_bind_default(4433)
479    ///     .with_custom_transport(identity, custom_transport_config)
480    ///     .build();
481    /// ```
482    #[cfg(feature = "quinn")]
483    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
484    pub fn with_custom_transport(
485        self,
486        identity: Identity,
487        quic_transport_config: QuicTransportConfig,
488    ) -> ServerConfigBuilder<states::WantsTransportConfigServer> {
489        use crate::tls::server::build_default_tls_config;
490
491        let tls_config = build_default_tls_config(identity);
492        let quic_endpoint_config = EndpointConfig::default();
493
494        self.with(tls_config, quic_endpoint_config, quic_transport_config)
495    }
496
497    /// Configures the server with both a custom TLS configuration and a custom QUIC transport
498    /// configuration.
499    ///
500    /// This method is designed for advanced users who require full control over both the TLS
501    /// and transport settings. It allows you to pass a preconfigured [`TlsServerConfig`] and
502    /// a custom [`QuicTransportConfig`] to fine-tune both layers of the server configuration.
503    ///
504    /// # Parameters
505    ///
506    /// - `tls_config`: A custom [`TlsServerConfig`] instance that allows you to specify
507    ///   detailed TLS settings, such as ciphersuites, certificate verification, and more. It must
508    ///   support TLS 1.3 (see the documentation of [`Self::with_custom_tls`]).
509    /// - `quic_transport_config`: A custom [`QuicTransportConfig`] instance that allows you to specify
510    ///   various QUIC transport-layer settings according to your requirements.
511    #[cfg(feature = "quinn")]
512    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
513    pub fn with_custom_tls_and_transport(
514        self,
515        tls_config: TlsServerConfig,
516        quic_transport_config: QuicTransportConfig,
517    ) -> ServerConfigBuilder<states::WantsTransportConfigServer> {
518        let quic_endpoint_config = EndpointConfig::default();
519        self.with(tls_config, quic_endpoint_config, quic_transport_config)
520    }
521
522    /// Directly builds [`ServerConfig`] skipping TLS and transport configuration.
523    ///
524    /// Both TLS and transport configuration is given by [`quic_config`](QuicServerConfig).
525    #[cfg(feature = "quinn")]
526    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
527    pub fn build_with_quic_config(self, quic_config: QuicServerConfig) -> ServerConfig {
528        ServerConfig {
529            bind_address_config: self.0.bind_address_config,
530            endpoint_config: EndpointConfig::default(),
531            quic_config,
532        }
533    }
534
535    fn with(
536        self,
537        tls_config: TlsServerConfig,
538        endpoint_config: EndpointConfig,
539        transport_config: TransportConfig,
540    ) -> ServerConfigBuilder<states::WantsTransportConfigServer> {
541        ServerConfigBuilder(states::WantsTransportConfigServer {
542            bind_address_config: self.0.bind_address_config,
543            tls_config,
544            endpoint_config,
545            transport_config,
546            migration: true,
547        })
548    }
549}
550
551impl ServerConfigBuilder<states::WantsTransportConfigServer> {
552    /// Completes configuration process.
553    ///
554    /// # Panics
555    ///
556    /// See the documentation of [`Self::with_custom_tls`] for the TLS 1.3 requirement.
557    #[must_use]
558    pub fn build(self) -> ServerConfig {
559        let crypto: Arc<quinn::crypto::rustls::QuicServerConfig> = Arc::new(
560            quinn::crypto::rustls::QuicServerConfig::try_from(self.0.tls_config)
561                .expect("CipherSuite::TLS13_AES_128_GCM_SHA256 missing"),
562        );
563
564        let mut quic_config = quinn::ServerConfig::with_crypto(crypto);
565
566        quic_config.transport_config(Arc::new(self.0.transport_config));
567        quic_config.migration(self.0.migration);
568
569        ServerConfig {
570            bind_address_config: self.0.bind_address_config,
571            endpoint_config: self.0.endpoint_config,
572            quic_config,
573        }
574    }
575
576    /// Maximum duration of inactivity to accept before timing out the connection.
577    ///
578    /// The true idle timeout is the minimum of this and the peer's own max idle timeout. `None`
579    /// represents an infinite timeout.
580    ///
581    /// **WARNING**: If a peer or its network path malfunctions or acts maliciously, an infinite
582    /// idle timeout can result in permanently hung futures!
583    pub fn max_idle_timeout(
584        mut self,
585        idle_timeout: Option<Duration>,
586    ) -> Result<Self, InvalidIdleTimeout> {
587        let idle_timeout = idle_timeout
588            .map(quinn::IdleTimeout::try_from)
589            .transpose()
590            .map_err(|_| InvalidIdleTimeout)?;
591
592        self.0.transport_config.max_idle_timeout(idle_timeout);
593
594        Ok(self)
595    }
596
597    /// Period of inactivity before sending a keep-alive packet
598    ///
599    /// Keep-alive packets prevent an inactive but otherwise healthy connection from timing out.
600    ///
601    /// `None` to disable, which is the default. Only one side of any given connection needs keep-alive
602    /// enabled for the connection to be preserved. Must be set lower than the
603    /// [`max_idle_timeout`](Self::max_idle_timeout) of both peers to be effective.
604    pub fn keep_alive_interval(mut self, interval: Option<Duration>) -> Self {
605        self.0.transport_config.keep_alive_interval(interval);
606        self
607    }
608
609    /// Whether to allow clients to migrate to new addresses.
610    ///
611    /// Improves behavior for clients that move between different internet connections or suffer NAT
612    /// rebinding. Enabled by default.
613    pub fn allow_migration(mut self, value: bool) -> Self {
614        self.0.migration = value;
615        self
616    }
617}
618
619/// Client configuration.
620///
621///
622/// You can create an instance of `ClientConfig` using its builder pattern by calling
623/// the [`builder()`](Self::builder) method.
624/// Once you have an instance, you can further customize it by chaining method calls
625/// to set various configuration options.
626///
627/// ## Configuration Builder States
628///
629/// The configuration process follows a *state-based builder pattern*, where the client
630/// configuration progresses through *3* states.
631///
632/// ### 1. `WantsBindAddress`
633///
634/// The caller must supply a binding address for the client.
635/// The following options are mutually exclusive:
636///
637///   - [`with_bind_default`](ClientConfigBuilder::with_bind_default): configures to use
638///     the default bind address. This is generally the *default* choice for a client.
639///   - [`with_bind_config`](ClientConfigBuilder::with_bind_config): configures
640///     binding to an address determined by a configuration preset.
641///   - [`with_bind_address`](ClientConfigBuilder::with_bind_address): configures
642///     binding to a custom-specified socket address.
643///   - [`with_bind_address_v6`](ClientConfigBuilder::with_bind_address_v6): configures
644///     binding to a custom-specified socket address for *IPv6*, along with the [dual stack
645///     configuration](Ipv6DualStackConfig).
646///   - [`with_bind_socket`](ClientConfigBuilder::with_bind_socket): configures
647///     binding directly to a custom-specified socket.
648///
649/// Only one of these options can be selected during the client configuration process.
650///
651/// #### Examples:
652///
653/// ```
654/// use wtransport::ClientConfig;
655///
656/// ClientConfig::builder().with_bind_default();
657/// ```
658///
659/// ### 2. `WantsRootStore`
660///
661/// The caller must supply a TLS root store configuration for server certificate validation.
662/// The following options are mutually exclusive:
663///
664/// - [`with_native_certs`](ClientConfigBuilder::with_native_certs): configures to use
665///   root certificates found in the platform's native certificate store. This is the *default*
666///   configuration as it uses root store installed on the current machine.
667/// - [`with_server_certificate_hashes`][cert_hashes]: configures the client to accept
668///   *some* certificates mapped to hashes. This can be used to connect to self signed
669///   certificates securely, where the hash of the certificate is shared in advance
670///   through some other mechanism (such as an invite link).
671/// - (**insecure**) [`with_no_cert_validation`](ClientConfigBuilder::with_no_cert_validation):
672///   configure to skip server certificate validation. This might be handy for testing purpose
673///   to accept *self-signed* certificate, but you should almost always prefer
674///   [`with_server_certificate_hashes`][cert_hashes] for that use case.
675/// - [`with_custom_tls`](ClientConfigBuilder::with_custom_tls): sets the TLS client
676///   configuration manually.
677/// - [`with_custom_transport`](ClientConfigBuilder::with_custom_transport): sets the QUIC
678///   transport configuration manually (using default TLS).
679/// - [`with_custom_tls_and_transport`](ClientConfigBuilder::with_custom_tls_and_transport): sets both
680///   a custom TLS and QUIC transport configuration.
681/// - [`build_with_quic_config`](ClientConfigBuilder::build_with_quic_config): directly builds
682///   [`ClientConfig`] providing both TLS and QUIC transport configuration given by
683///   [`quic_config`](QuicClientConfig).
684///
685/// Only one of these options can be selected during the client configuration process.
686///
687/// [cert_hashes]: ClientConfigBuilder::with_server_certificate_hashes
688///
689/// #### Examples:
690/// ```
691/// use wtransport::ClientConfig;
692///
693/// ClientConfig::builder()
694///     .with_bind_default()
695///     .with_native_certs();
696/// ```
697///
698/// ### 3. `WantsTransportConfigClient`
699///
700/// The caller can supply *additional* transport configurations.
701/// Multiple options can be given at this stage. Once the configuration is completed, it is possible
702/// to finalize with the method [`build()`](ClientConfigBuilder::build).
703///
704/// All these options can be omitted in the configuration; default values will be used.
705///
706/// - [`max_idle_timeout`](ClientConfigBuilder::max_idle_timeout)
707/// - [`keep_alive_interval`](ClientConfigBuilder::keep_alive_interval)
708/// - [`dns_resolver`](ClientConfigBuilder::dns_resolver)
709///
710/// #### Examples:
711/// ```
712/// use std::time::Duration;
713/// use wtransport::ClientConfig;
714///
715/// let client_config = ClientConfig::builder()
716///     .with_bind_default()
717///     .with_native_certs()
718///     .max_idle_timeout(Some(Duration::from_secs(30)))
719///     .unwrap()
720///     .keep_alive_interval(Some(Duration::from_secs(3)))
721///     .build();
722/// ```
723#[derive(Debug)]
724pub struct ClientConfig {
725    pub(crate) bind_address_config: BindAddressConfig,
726    pub(crate) endpoint_config: quinn::EndpointConfig,
727    pub(crate) quic_config: quinn::ClientConfig,
728    pub(crate) dns_resolver: Arc<dyn DnsResolver + Send + Sync>,
729}
730
731impl ClientConfig {
732    /// Creates a builder to build up the client configuration.
733    ///
734    /// For more information, see the [`ClientConfigBuilder`] documentation.
735    pub fn builder() -> ClientConfigBuilder<states::WantsBindAddress> {
736        ClientConfigBuilder::default()
737    }
738
739    /// Allows setting a custom [`DnsResolver`] for this configuration.
740    ///
741    /// Default resolver is [`TokioDnsResolver`].
742    pub fn set_dns_resolver<R>(&mut self, dns_resolver: R)
743    where
744        R: DnsResolver + Send + Sync + 'static,
745    {
746        self.dns_resolver = Arc::new(dns_resolver);
747    }
748
749    /// Returns a reference to the inner QUIC endpoint configuration.
750    #[cfg(feature = "quinn")]
751    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
752    pub fn quic_endpoint_config(&self) -> &quinn::EndpointConfig {
753        &self.endpoint_config
754    }
755
756    /// Returns a mutable reference to the inner QUIC endpoint configuration.
757    #[cfg(feature = "quinn")]
758    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
759    pub fn quic_endpoint_config_mut(&mut self) -> &mut quinn::EndpointConfig {
760        &mut self.endpoint_config
761    }
762
763    /// Returns a reference to the inner QUIC configuration.
764    #[cfg(feature = "quinn")]
765    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
766    pub fn quic_config(&self) -> &quinn::ClientConfig {
767        &self.quic_config
768    }
769
770    /// Returns a mutable reference to the inner QUIC configuration.
771    #[cfg(feature = "quinn")]
772    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
773    pub fn quic_config_mut(&mut self) -> &mut quinn::ClientConfig {
774        &mut self.quic_config
775    }
776}
777
778impl Default for ClientConfig {
779    fn default() -> Self {
780        ClientConfig::builder()
781            .with_bind_default()
782            .with_native_certs()
783            .build()
784    }
785}
786
787/// Client builder configuration.
788///
789/// The builder might have different state at compile time.
790///
791/// # Example
792/// ```no_run
793/// # use std::net::Ipv4Addr;
794/// # use std::net::SocketAddr;
795/// # use wtransport::ClientConfig;
796/// let config = ClientConfig::builder().with_bind_default();
797/// ```
798#[must_use]
799pub struct ClientConfigBuilder<State>(State);
800
801impl ClientConfigBuilder<states::WantsBindAddress> {
802    /// Configures for connecting binding ANY IP (allowing IP dual-stack).
803    ///
804    /// Bind port will be randomly picked.
805    ///
806    /// This is equivalent to: [`Self::with_bind_config`] with [`IpBindConfig::InAddrAnyDual`].
807    pub fn with_bind_default(self) -> ClientConfigBuilder<states::WantsRootStore> {
808        self.with_bind_config(IpBindConfig::InAddrAnyDual)
809    }
810
811    /// Sets the binding (local) socket address with a specific [`IpBindConfig`].
812    ///
813    /// Bind port will be randomly picked.
814    pub fn with_bind_config(
815        self,
816        ip_bind_config: IpBindConfig,
817    ) -> ClientConfigBuilder<states::WantsRootStore> {
818        let ip_address: IpAddr = ip_bind_config.into_ip();
819
820        match ip_address {
821            IpAddr::V4(ip) => self.with_bind_address(SocketAddr::new(ip.into(), 0)),
822            IpAddr::V6(ip) => self.with_bind_address_v6(
823                SocketAddrV6::new(ip, 0, 0, 0),
824                ip_bind_config.into_dual_stack_config(),
825            ),
826        }
827    }
828
829    /// Sets the binding (local) socket address for the endpoint.
830    pub fn with_bind_address(
831        self,
832        address: SocketAddr,
833    ) -> ClientConfigBuilder<states::WantsRootStore> {
834        ClientConfigBuilder(states::WantsRootStore {
835            bind_address_config: BindAddressConfig::from(address),
836        })
837    }
838
839    /// Sets the binding (local) socket address for the endpoint.
840    ///
841    /// `dual_stack_config` allows/denies dual stack port binding.
842    pub fn with_bind_address_v6(
843        self,
844        address: SocketAddrV6,
845        dual_stack_config: Ipv6DualStackConfig,
846    ) -> ClientConfigBuilder<states::WantsRootStore> {
847        ClientConfigBuilder(states::WantsRootStore {
848            bind_address_config: BindAddressConfig::AddressV6(address, dual_stack_config),
849        })
850    }
851
852    /// Configures the client to bind to a pre-existing [`UdpSocket`].
853    ///
854    /// This allows the client to use an already created socket, which can be useful in cases
855    /// where socket reuse or specific socket configurations are necessary.
856    pub fn with_bind_socket(
857        self,
858        socket: UdpSocket,
859    ) -> ClientConfigBuilder<states::WantsRootStore> {
860        ClientConfigBuilder(states::WantsRootStore {
861            bind_address_config: BindAddressConfig::Socket(socket),
862        })
863    }
864}
865
866impl ClientConfigBuilder<states::WantsRootStore> {
867    /// Configures the client to use native (local) root certificates for server validation.
868    ///
869    /// This method loads trusted root certificates from the system's certificate store,
870    /// ensuring that your client can trust certificates signed by well-known authorities.
871    ///
872    /// It configures safe default TLS configuration.
873    pub fn with_native_certs(self) -> ClientConfigBuilder<states::WantsTransportConfigClient> {
874        use crate::tls::client::build_default_tls_config;
875
876        let tls_config = build_default_tls_config(Arc::new(build_native_cert_store()), None);
877        let endpoint_config = EndpointConfig::default();
878        let transport_config = TransportConfig::default();
879
880        self.with(tls_config, endpoint_config, transport_config)
881    }
882
883    /// Configures the client to skip server certificate validation, potentially
884    /// compromising security.
885    ///
886    /// This method is intended for advanced users and should be used with caution. It
887    /// configures the client to bypass server certificate validation during the TLS
888    /// handshake, effectively trusting any server certificate presented, even if it is
889    /// not signed by a trusted certificate authority (CA). Using this method can expose
890    /// your application to security risks.
891    ///
892    /// # Safety Note
893    ///
894    /// Using [`with_no_cert_validation`] should only be considered when you have a
895    /// specific need to disable certificate validation. In most cases, it is strongly
896    /// recommended to validate server certificates using trusted root certificates
897    /// (e.g., [`with_native_certs`]) to ensure secure communication.
898    ///
899    /// However, this method can be useful in testing environments or situations where
900    /// you intentionally want to skip certificate validation for specific use cases.
901    ///
902    /// [`with_native_certs`]: #method.with_native_certs
903    /// [`with_no_cert_validation`]: #method.with_no_cert_validation
904    #[cfg(feature = "dangerous-configuration")]
905    #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-configuration")))]
906    pub fn with_no_cert_validation(
907        self,
908    ) -> ClientConfigBuilder<states::WantsTransportConfigClient> {
909        use crate::tls::client::build_default_tls_config;
910        use crate::tls::client::NoServerVerification;
911        use rustls::RootCertStore;
912
913        let tls_config = build_default_tls_config(
914            Arc::new(RootCertStore::empty()),
915            Some(Arc::new(NoServerVerification::new())),
916        );
917
918        let endpoint_config = EndpointConfig::default();
919        let transport_config = TransportConfig::default();
920
921        self.with(tls_config, endpoint_config, transport_config)
922    }
923
924    /// Configures the client to skip *some* server certificates validation.
925    ///
926    /// This method configures the client to accept server certificates
927    /// whose digests match the specified *SHA-256* hashes and fulfill
928    /// some additional constraints (*see notes below*).
929    ///
930    /// This is useful for scenarios where clients need to accept known
931    /// self-signed certificates or certificates from non-standard authorities.
932    ///
933    /// This method configuration is similar to the
934    /// [browser W3C WebTransport API](https://www.w3.org/TR/webtransport/#dom-webtransportoptions-servercertificatehashes).
935    ///
936    /// # Notes
937    ///
938    /// - The current time MUST be within the validity period of the certificate.
939    /// - The total length of the validity period MUST NOT exceed *two* weeks.
940    /// - Only certificates for which the public key algorithm is *ECDSA* with the *secp256r1* are accepted.
941    pub fn with_server_certificate_hashes<I>(
942        self,
943        hashes: I,
944    ) -> ClientConfigBuilder<states::WantsTransportConfigClient>
945    where
946        I: IntoIterator<Item = crate::tls::Sha256Digest>,
947    {
948        use crate::tls::client::build_default_tls_config;
949        use crate::tls::client::ServerHashVerification;
950        use rustls::RootCertStore;
951
952        let tls_config = build_default_tls_config(
953            Arc::new(RootCertStore::empty()),
954            Some(Arc::new(ServerHashVerification::new(hashes))),
955        );
956
957        let endpoint_config = EndpointConfig::default();
958        let transport_config = TransportConfig::default();
959
960        self.with(tls_config, endpoint_config, transport_config)
961    }
962
963    /// Allows for manual configuration of a custom TLS setup using a provided
964    /// [`rustls::ClientConfig`], which must support
965    /// [`rustls::CipherSuite::TLS13_AES_128_GCM_SHA256`]. A suitable configuration
966    /// can be obtained using the `ring` crypto provider with a set of versions containing
967    /// [`rustls::version::TLS13`].
968    ///
969    /// This method is provided for advanced users who need fine-grained control over the
970    /// TLS configuration. It allows you to pass a preconfigured [`rustls::ClientConfig`]
971    /// instance to customize the TLS settings according to your specific requirements.
972    ///
973    /// For most use cases, it is recommended to use the [`with_native_certs`](Self::with_native_certs)
974    /// method to configure TLS with safe defaults.
975    pub fn with_custom_tls(
976        self,
977        tls_config: TlsClientConfig,
978    ) -> ClientConfigBuilder<states::WantsTransportConfigClient> {
979        let endpoint_config = EndpointConfig::default();
980        let transport_config = TransportConfig::default();
981
982        self.with(tls_config, endpoint_config, transport_config)
983    }
984
985    /// Similar to [`with_native_certs`](Self::with_native_certs), but it allows specifying a custom
986    /// QUIC transport configuration.
987    ///
988    /// # Parameters
989    ///
990    /// - `quic_transport_config`: A custom [`QuicTransportConfig`] instance that allows you to specify
991    ///   various QUIC transport-layer settings according to your requirements.
992    ///
993    /// # Example
994    ///
995    /// ```
996    /// use wtransport::config::QuicTransportConfig;
997    /// use wtransport::ClientConfig;
998    ///
999    /// // Create a custom QuicTransportConfig with specific settings
1000    /// let mut custom_transport_config = QuicTransportConfig::default();
1001    /// custom_transport_config.datagram_send_buffer_size(1024);
1002    ///
1003    /// // Create a ClientConfigBuilder with the custom transport configuration and default TLS settings
1004    /// let client_config = ClientConfig::builder()
1005    ///     .with_bind_default()
1006    ///     .with_custom_transport(custom_transport_config)
1007    ///     .build();
1008    /// ```
1009    #[cfg(feature = "quinn")]
1010    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
1011    pub fn with_custom_transport(
1012        self,
1013        quic_transport_config: QuicTransportConfig,
1014    ) -> ClientConfigBuilder<states::WantsTransportConfigClient> {
1015        use crate::tls::client::build_default_tls_config;
1016
1017        let tls_config = build_default_tls_config(Arc::new(build_native_cert_store()), None);
1018        let quic_endpoint_config = EndpointConfig::default();
1019
1020        self.with(tls_config, quic_endpoint_config, quic_transport_config)
1021    }
1022
1023    /// Configures the client with both a custom TLS configuration and a custom QUIC transport
1024    /// configuration.
1025    ///
1026    /// This method is designed for advanced users who require full control over both the TLS
1027    /// and transport settings. It allows you to pass a preconfigured [`TlsClientConfig`] and
1028    /// a custom [`QuicTransportConfig`] to fine-tune both layers of the server configuration.
1029    ///
1030    /// # Parameters
1031    ///
1032    /// - `tls_config`: A custom [`TlsClientConfig`] instance that allows you to specify
1033    ///   detailed TLS settings, such as ciphersuites, certificate verification, and more. It must
1034    ///   support TLS 1.3 (see the documentation of [`Self::with_custom_tls`]).
1035    /// - `quic_transport_config`: A custom [`QuicTransportConfig`] instance that allows you to specify
1036    ///   various QUIC transport-layer settings according to your requirements.
1037    #[cfg(feature = "quinn")]
1038    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
1039    pub fn with_custom_tls_and_transport(
1040        self,
1041        tls_config: TlsClientConfig,
1042        quic_transport_config: QuicTransportConfig,
1043    ) -> ClientConfigBuilder<states::WantsTransportConfigClient> {
1044        let quic_endpoint_config = EndpointConfig::default();
1045        self.with(tls_config, quic_endpoint_config, quic_transport_config)
1046    }
1047
1048    /// Directly builds [`ClientConfig`] skipping TLS and transport configuration.
1049    ///
1050    /// Both TLS and transport configuration is given by [`quic_config`](QuicClientConfig).
1051    #[cfg(feature = "quinn")]
1052    #[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
1053    pub fn build_with_quic_config(self, quic_config: QuicClientConfig) -> ClientConfig {
1054        ClientConfig {
1055            bind_address_config: self.0.bind_address_config,
1056            endpoint_config: EndpointConfig::default(),
1057            quic_config,
1058            dns_resolver: Arc::<TokioDnsResolver>::default(),
1059        }
1060    }
1061
1062    fn with(
1063        self,
1064        tls_config: TlsClientConfig,
1065        endpoint_config: EndpointConfig,
1066        transport_config: TransportConfig,
1067    ) -> ClientConfigBuilder<states::WantsTransportConfigClient> {
1068        ClientConfigBuilder(states::WantsTransportConfigClient {
1069            bind_address_config: self.0.bind_address_config,
1070            tls_config,
1071            endpoint_config,
1072            transport_config,
1073            dns_resolver: Arc::<TokioDnsResolver>::default(),
1074        })
1075    }
1076}
1077
1078impl ClientConfigBuilder<states::WantsTransportConfigClient> {
1079    /// Completes configuration process.
1080    ///
1081    /// # Panics
1082    ///
1083    /// See the documentation of [`Self::with_custom_tls`] for the TLS 1.3 requirement.
1084    #[must_use]
1085    pub fn build(self) -> ClientConfig {
1086        let crypto = quinn::crypto::rustls::QuicClientConfig::try_from(self.0.tls_config)
1087            .expect("CipherSuite::TLS13_AES_128_GCM_SHA256 missing");
1088
1089        let mut quic_config = quinn::ClientConfig::new(Arc::new(crypto));
1090        quic_config.transport_config(Arc::new(self.0.transport_config));
1091
1092        ClientConfig {
1093            bind_address_config: self.0.bind_address_config,
1094            endpoint_config: self.0.endpoint_config,
1095            quic_config,
1096            dns_resolver: self.0.dns_resolver,
1097        }
1098    }
1099
1100    /// Maximum duration of inactivity to accept before timing out the connection.
1101    ///
1102    /// The true idle timeout is the minimum of this and the peer's own max idle timeout. `None`
1103    /// represents an infinite timeout.
1104    ///
1105    /// **WARNING**: If a peer or its network path malfunctions or acts maliciously, an infinite
1106    /// idle timeout can result in permanently hung futures!
1107    pub fn max_idle_timeout(
1108        mut self,
1109        idle_timeout: Option<Duration>,
1110    ) -> Result<Self, InvalidIdleTimeout> {
1111        let idle_timeout = idle_timeout
1112            .map(quinn::IdleTimeout::try_from)
1113            .transpose()
1114            .map_err(|_| InvalidIdleTimeout)?;
1115
1116        self.0.transport_config.max_idle_timeout(idle_timeout);
1117
1118        Ok(self)
1119    }
1120
1121    /// Period of inactivity before sending a keep-alive packet
1122    ///
1123    /// Keep-alive packets prevent an inactive but otherwise healthy connection from timing out.
1124    ///
1125    /// `None` to disable, which is the default. Only one side of any given connection needs keep-alive
1126    /// enabled for the connection to be preserved. Must be set lower than the
1127    /// [`max_idle_timeout`](Self::max_idle_timeout) of both peers to be effective.
1128    pub fn keep_alive_interval(mut self, interval: Option<Duration>) -> Self {
1129        self.0.transport_config.keep_alive_interval(interval);
1130        self
1131    }
1132
1133    /// Sets the *DNS* resolver used during [`Endpoint::connect`](crate::Endpoint::connect).
1134    ///
1135    /// Default configuration uses [`TokioDnsResolver`].
1136    pub fn dns_resolver<R>(mut self, dns_resolver: R) -> Self
1137    where
1138        R: DnsResolver + Send + Sync + 'static,
1139    {
1140        self.0.dns_resolver = Arc::new(dns_resolver);
1141        self
1142    }
1143}
1144
1145impl Default for ServerConfigBuilder<states::WantsBindAddress> {
1146    fn default() -> Self {
1147        Self(states::WantsBindAddress {})
1148    }
1149}
1150
1151impl Default for ClientConfigBuilder<states::WantsBindAddress> {
1152    fn default() -> Self {
1153        Self(states::WantsBindAddress {})
1154    }
1155}
1156
1157#[derive(Debug)]
1158pub(crate) enum BindAddressConfig {
1159    AddressV4(SocketAddrV4),
1160    AddressV6(SocketAddrV6, Ipv6DualStackConfig),
1161    Socket(UdpSocket),
1162}
1163
1164impl BindAddressConfig {
1165    pub(crate) fn bind_socket(self) -> std::io::Result<UdpSocket> {
1166        let (bind_address, dual_stack_config) = match self {
1167            BindAddressConfig::AddressV4(address) => {
1168                (SocketAddr::from(address), Ipv6DualStackConfig::OsDefault)
1169            }
1170            BindAddressConfig::AddressV6(address, ipv6_dual_stack_config) => {
1171                (SocketAddr::from(address), ipv6_dual_stack_config)
1172            }
1173            BindAddressConfig::Socket(socket) => {
1174                return Ok(socket);
1175            }
1176        };
1177
1178        let domain = match bind_address {
1179            SocketAddr::V4(_) => SocketDomain::IPV4,
1180            SocketAddr::V6(_) => SocketDomain::IPV6,
1181        };
1182
1183        let socket = Socket::new(domain, SocketType::DGRAM, Some(SocketProtocol::UDP))?;
1184
1185        match dual_stack_config {
1186            Ipv6DualStackConfig::OsDefault => {}
1187            Ipv6DualStackConfig::Deny => socket.set_only_v6(true)?,
1188            Ipv6DualStackConfig::Allow => socket.set_only_v6(false)?,
1189        }
1190
1191        socket.bind(&bind_address.into())?;
1192
1193        Ok(UdpSocket::from(socket))
1194    }
1195}
1196
1197impl From<SocketAddr> for BindAddressConfig {
1198    fn from(value: SocketAddr) -> Self {
1199        match value {
1200            SocketAddr::V4(address) => BindAddressConfig::AddressV4(address),
1201            SocketAddr::V6(address) => {
1202                BindAddressConfig::AddressV6(address, Ipv6DualStackConfig::OsDefault)
1203            }
1204        }
1205    }
1206}
1207
1208/// State-types for client/server builder.
1209pub mod states {
1210    use super::*;
1211
1212    /// Config builder state where the caller must supply binding address.
1213    pub struct WantsBindAddress {}
1214
1215    /// Config builder state where the caller must supply TLS certificate.
1216    pub struct WantsIdentity {
1217        pub(super) bind_address_config: BindAddressConfig,
1218    }
1219
1220    /// Config builder state where the caller must supply TLS root store.
1221    pub struct WantsRootStore {
1222        pub(super) bind_address_config: BindAddressConfig,
1223    }
1224
1225    /// Config builder state where transport properties can be set.
1226    pub struct WantsTransportConfigServer {
1227        pub(super) bind_address_config: BindAddressConfig,
1228        pub(super) tls_config: TlsServerConfig,
1229        pub(super) endpoint_config: quinn::EndpointConfig,
1230        pub(super) transport_config: quinn::TransportConfig,
1231        pub(super) migration: bool,
1232    }
1233
1234    /// Config builder state where transport properties can be set.
1235    pub struct WantsTransportConfigClient {
1236        pub(super) bind_address_config: BindAddressConfig,
1237        pub(super) tls_config: TlsClientConfig,
1238        pub(super) endpoint_config: quinn::EndpointConfig,
1239        pub(super) transport_config: quinn::TransportConfig,
1240        pub(super) dns_resolver: Arc<dyn DnsResolver + Send + Sync>,
1241    }
1242}
1243
1244/// Future resolving domain name.
1245///
1246/// See [`DnsResolver::resolve`].
1247pub trait DnsLookupFuture: Future<Output = std::io::Result<Option<SocketAddr>>> + Send {}
1248
1249impl<F> DnsLookupFuture for F where F: Future<Output = std::io::Result<Option<SocketAddr>>> + Send {}
1250
1251/// A trait for asynchronously resolving domain names to IP addresses using DNS.
1252pub trait DnsResolver: Debug {
1253    /// Resolves a domain name to one IP address.
1254    fn resolve(&self, host: &str) -> Pin<Box<dyn DnsLookupFuture>>;
1255}
1256
1257/// A DNS resolver implementation using the *Tokio* asynchronous runtime.
1258///
1259/// Internally, it uses [`tokio::net::lookup_host`].
1260#[derive(Default)]
1261pub struct TokioDnsResolver;
1262
1263impl DnsResolver for TokioDnsResolver {
1264    fn resolve(&self, host: &str) -> Pin<Box<dyn DnsLookupFuture>> {
1265        let host = host.to_string();
1266
1267        Box::pin(async move { Ok(tokio::net::lookup_host(host).await?.next()) })
1268    }
1269}
1270
1271impl Debug for TokioDnsResolver {
1272    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1273        f.debug_struct("TokioDnsResolver").finish()
1274    }
1275}
1276
1277impl std::error::Error for InvalidIdleTimeout {}
1278
1279impl Debug for InvalidIdleTimeout {
1280    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1281        f.write_str("idle timeout value configuration is invalid")
1282    }
1283}
1284
1285impl Display for InvalidIdleTimeout {
1286    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1287        Debug::fmt(self, f)
1288    }
1289}