h3i/
config.rs

1// Copyright (C) 2024, Cloudflare, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//
11//     * Redistributions in binary form must reproduce the above copyright
12//       notice, this list of conditions and the following disclaimer in the
13//       documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27//! Configuration for the h3i client.
28use std::io;
29
30/// Server details and QUIC connection properties.
31#[derive(Clone)]
32pub struct Config {
33    /// A string representing the host and port to connect to using the format
34    /// `<host>:<port>`.
35    pub host_port: String,
36    /// If the SNI should be omitted during the TLS handshake.
37    pub omit_sni: bool,
38    /// Set a specific IP address to connect to, rather than use DNS resolution.
39    pub connect_to: Option<String>,
40    /// The source port to use when connecting to a server.
41    pub source_port: u32,
42    /// Whether to verify the server certificate.
43    pub verify_peer: bool,
44    /// The QUIC idle timeout value in milliseconds.
45    pub idle_timeout: u64,
46    /// Flow control limit for the connection in bytes
47    pub max_data: u64,
48    /// Flow control limit for locally-initiated bidirectional streams in bytes.
49    pub max_stream_data_bidi_local: u64,
50    /// Flow control limit for remotely-initiated bidirectional streams in
51    /// bytes.
52    pub max_stream_data_bidi_remote: u64,
53    /// Flow control limit for unidirectional streams in bytes.
54    pub max_stream_data_uni: u64,
55    /// Maximum count for concurrent remotely-initiated bidirectional streams.
56    pub max_streams_bidi: u64,
57    /// "Maximum count for concurrent remotely-initiated unidirectional
58    /// streams".
59    pub max_streams_uni: u64,
60    /// Receiver window limit for the connection in bytes.
61    pub max_window: u64,
62    /// Receiver window limit for a stream in bytes.
63    pub max_stream_window: u64,
64}
65
66impl Config {
67    /// Construct a new config object with default values.
68    pub fn new() -> Self {
69        Self::default()
70    }
71
72    pub fn with_host_port(mut self, host_port: String) -> Self {
73        self.host_port = host_port;
74        self
75    }
76
77    pub fn omit_sni(mut self) -> Self {
78        self.omit_sni = true;
79        self
80    }
81
82    pub fn with_connect_to(mut self, connect_to: String) -> Self {
83        self.connect_to = Some(connect_to);
84        self
85    }
86
87    pub fn with_source_port(mut self, port: u32) -> Self {
88        self.source_port = port;
89        self
90    }
91
92    pub fn verify_peer(mut self, verify_peer: bool) -> Self {
93        self.verify_peer = verify_peer;
94        self
95    }
96
97    pub fn with_idle_timeout(mut self, idle_timeout: u64) -> Self {
98        self.idle_timeout = idle_timeout;
99        self
100    }
101
102    pub fn with_max_data(mut self, max_data: u64) -> Self {
103        self.max_data = max_data;
104        self
105    }
106
107    pub fn with_max_stream_data_bidi_local(
108        mut self, max_stream_data_bidi_local: u64,
109    ) -> Self {
110        self.max_stream_data_bidi_local = max_stream_data_bidi_local;
111        self
112    }
113
114    pub fn with_max_stream_data_bidi_remote(
115        mut self, max_stream_data_bidi_remote: u64,
116    ) -> Self {
117        self.max_stream_data_bidi_remote = max_stream_data_bidi_remote;
118        self
119    }
120
121    pub fn with_max_stream_data_uni(mut self, max_stream_data_uni: u64) -> Self {
122        self.max_stream_data_uni = max_stream_data_uni;
123        self
124    }
125
126    pub fn with_max_streams_bidi(mut self, max_streams_bidi: u64) -> Self {
127        self.max_streams_bidi = max_streams_bidi;
128        self
129    }
130
131    pub fn with_max_streams_uni(mut self, max_streams_uni: u64) -> Self {
132        self.max_streams_uni = max_streams_uni;
133        self
134    }
135
136    pub fn with_max_window(mut self, max_window: u64) -> Self {
137        self.max_window = max_window;
138        self
139    }
140
141    pub fn with_max_stream_window(mut self, max_stream_window: u64) -> Self {
142        self.max_stream_window = max_stream_window;
143        self
144    }
145
146    pub fn build(self) -> Result<Self, io::Error> {
147        if self.host_port.is_empty() {
148            return Err(io::Error::new(
149                io::ErrorKind::InvalidInput,
150                "Must provide a <host:port> to connect".to_string(),
151            ));
152        }
153
154        Ok(Config {
155            host_port: self.host_port,
156            omit_sni: self.omit_sni,
157            connect_to: self.connect_to,
158            source_port: self.source_port,
159            verify_peer: self.verify_peer,
160            idle_timeout: self.idle_timeout,
161            max_data: self.max_data,
162            max_stream_data_bidi_local: self.max_stream_data_bidi_local,
163            max_stream_data_bidi_remote: self.max_stream_data_bidi_remote,
164            max_stream_data_uni: self.max_stream_data_uni,
165            max_streams_bidi: self.max_streams_bidi,
166            max_streams_uni: self.max_streams_uni,
167            max_window: self.max_window,
168            max_stream_window: self.max_stream_window,
169        })
170    }
171}
172
173impl Default for Config {
174    fn default() -> Self {
175        // Values mirror config_from_clap()
176        Self {
177            host_port: "".to_string(),
178            omit_sni: false,
179            connect_to: None,
180            source_port: 0,
181            verify_peer: true,
182            idle_timeout: 5000,
183            max_data: 10000000,
184            max_stream_data_bidi_local: 10000000,
185            max_stream_data_bidi_remote: 10000000,
186            max_stream_data_uni: 10000000,
187            max_streams_bidi: 100,
188            max_streams_uni: 100,
189            max_window: 25165824,
190            max_stream_window: 16777216,
191        }
192    }
193}