1use super::*;
5use core::marker::PhantomData;
6use s2n_quic_core::{connection::id::Generator, crypto, path};
7use s2n_quic_transport::{connection, endpoint, stream};
8
9impl_providers_state! {
10 #[derive(Debug, Default)]
11 struct Providers {
12 congestion_controller: CongestionController,
13 connection_close_formatter: ConnectionCloseFormatter,
14 connection_id: ConnectionID,
15 packet_interceptor: PacketInterceptor,
16 stateless_reset_token: StatelessResetToken,
17 random: Random,
18 event: Event,
19 limits: Limits,
20 mtu: Mtu,
21 io: IO,
22 sync: Sync,
23 tls: Tls,
24 datagram: Datagram,
25 dc: Dc,
26 }
27
28 trait ClientProviders {}
30}
31
32impl<
33 CongestionController: congestion_controller::Provider,
34 ConnectionCloseFormatter: connection_close_formatter::Provider,
35 ConnectionID: connection_id::Provider,
36 PacketInterceptor: packet_interceptor::Provider,
37 StatelessResetToken: stateless_reset_token::Provider,
38 Random: random::Provider,
39 Event: event::Provider,
40 Limits: limits::Provider,
41 Mtu: mtu::Provider,
42 IO: io::Provider,
43 Sync: sync::Provider,
44 Tls: tls::Provider,
45 Datagram: datagram::Provider,
46 Dc: dc::Provider,
47 >
48 Providers<
49 CongestionController,
50 ConnectionCloseFormatter,
51 ConnectionID,
52 PacketInterceptor,
53 StatelessResetToken,
54 Random,
55 Event,
56 Limits,
57 Mtu,
58 IO,
59 Sync,
60 Tls,
61 Datagram,
62 Dc,
63 >
64{
65 pub fn start(self) -> Result<Client, StartError> {
66 let Self {
67 congestion_controller,
68 connection_close_formatter,
69 connection_id,
70 packet_interceptor,
71 stateless_reset_token,
72 random,
73 event,
74 limits,
75 mtu,
76 io,
77 sync,
78 tls,
79 datagram,
80 dc,
81 } = self;
82
83 let congestion_controller = congestion_controller.start().map_err(StartError::new)?;
84 let connection_close_formatter = connection_close_formatter
85 .start()
86 .map_err(StartError::new)?;
87 let connection_id = connection_id.start().map_err(StartError::new)?;
88 let packet_interceptor = packet_interceptor.start().map_err(StartError::new)?;
89 let stateless_reset_token = stateless_reset_token.start().map_err(StartError::new)?;
90 let random = random.start().map_err(StartError::new)?;
91 let endpoint_limits = EndpointLimits;
92 let limits = limits.start().map_err(StartError::new)?;
93 let mtu = mtu.start().map_err(StartError::new)?;
94 let event = event.start().map_err(StartError::new)?;
95 let token = Token;
96 let sync = sync.start().map_err(StartError::new)?;
97 let path_migration = PathMigration;
98 let tls = tls.start_client().map_err(StartError::new)?;
99 let datagram = datagram.start().map_err(StartError::new)?;
100 let dc = dc.start().map_err(StartError::new)?;
101
102 let valid_lifetime = |lifetime| {
105 (connection::id::MIN_LIFETIME..=connection::id::MAX_LIFETIME).contains(&lifetime)
106 };
107 if connection_id
108 .lifetime()
109 .is_some_and(|lifetime| !valid_lifetime(lifetime))
110 {
111 return Err(StartError::new(connection::id::Error::InvalidLifetime));
112 };
113 let mtu = path::mtu::Manager::new(mtu);
114
115 let endpoint_config = EndpointConfig {
116 congestion_controller,
117 connection_close_formatter,
118 connection_id,
119 packet_interceptor,
120 stateless_reset_token,
121 random,
122 endpoint_limits,
123 event,
124 limits,
125 mtu,
126 sync,
127 tls,
128 token,
129 path_handle: PhantomData,
130 path_migration,
131 datagram,
132 dc,
133 };
134
135 let (endpoint, connector) = endpoint::Endpoint::new_client(endpoint_config);
136
137 let local_addr = io.start(endpoint).map_err(StartError::new)?;
139
140 Ok(Client {
141 connector,
142 local_addr,
143 })
144 }
145}
146
147#[derive(Debug)]
148struct EndpointLimits;
149
150impl endpoint::limits::Limiter for EndpointLimits {
151 fn on_connection_attempt(
152 &mut self,
153 _info: &endpoint::limits::ConnectionAttempt,
154 ) -> endpoint::limits::Outcome {
155 unreachable!("endpoint limits should not be used with clients")
156 }
157}
158
159#[derive(Debug)]
160struct Token;
161
162impl crate::provider::address_token::Format for Token {
163 const TOKEN_LEN: usize = 0;
164
165 fn generate_new_token(
166 &mut self,
167 _context: &mut s2n_quic_core::token::Context<'_>,
168 _source_connection_id: &s2n_quic_core::connection::LocalId,
169 _output_buffer: &mut [u8],
170 ) -> Option<()> {
171 unreachable!("tokens should not be generated with clients")
172 }
173
174 fn generate_retry_token(
175 &mut self,
176 _context: &mut s2n_quic_core::token::Context<'_>,
177 _original_destination_connection_id: &s2n_quic_core::connection::InitialId,
178 _output_buffer: &mut [u8],
179 ) -> Option<()> {
180 unreachable!("tokens should not be generated with clients")
181 }
182
183 fn validate_token(
184 &mut self,
185 _context: &mut s2n_quic_core::token::Context<'_>,
186 _token: &[u8],
187 ) -> Option<s2n_quic_core::connection::InitialId> {
188 unreachable!("tokens should not be generated with clients")
189 }
190}
191
192#[derive(Debug)]
193struct PathMigration;
194
195impl crate::provider::path_migration::Validator for PathMigration {
196 fn on_migration_attempt(
197 &mut self,
198 _attempt: &path::migration::Attempt,
199 ) -> path::migration::Outcome {
200 unreachable!("path migration should not be validated with clients")
201 }
202}
203
204#[allow(dead_code)] struct EndpointConfig<
206 CongestionController,
207 ConnectionCloseFormatter,
208 ConnectionID,
209 PacketInterceptor,
210 PathHandle,
211 StatelessResetToken,
212 Random,
213 Event,
214 Limits,
215 Mtu: path::Endpoint,
216 Sync,
217 Tls,
218 Datagram,
219 Dc,
220> {
221 congestion_controller: CongestionController,
222 connection_close_formatter: ConnectionCloseFormatter,
223 connection_id: ConnectionID,
224 packet_interceptor: PacketInterceptor,
225 stateless_reset_token: StatelessResetToken,
226 random: Random,
227 endpoint_limits: EndpointLimits,
228 event: Event,
229 limits: Limits,
230 mtu: path::mtu::Manager<Mtu>,
231 sync: Sync,
232 tls: Tls,
233 token: Token,
234 path_handle: PhantomData<PathHandle>,
235 path_migration: PathMigration,
236 datagram: Datagram,
237 dc: Dc,
238}
239
240impl<
241 CongestionController: congestion_controller::Endpoint,
242 ConnectionCloseFormatter: connection_close_formatter::Formatter,
243 ConnectionID: connection::id::Format,
244 PacketInterceptor: packet_interceptor::PacketInterceptor,
245 PathHandle: path::Handle,
246 StatelessResetToken: stateless_reset_token::Generator,
247 Random: s2n_quic_core::random::Generator,
248 Event: s2n_quic_core::event::Subscriber,
249 Limits: s2n_quic_core::connection::limits::Limiter,
250 Mtu: s2n_quic_core::path::mtu::Endpoint,
251 Sync,
252 Tls: crypto::tls::Endpoint,
253 Datagram: s2n_quic_core::datagram::Endpoint,
254 Dc: s2n_quic_core::dc::Endpoint,
255 > core::fmt::Debug
256 for EndpointConfig<
257 CongestionController,
258 ConnectionCloseFormatter,
259 ConnectionID,
260 PacketInterceptor,
261 PathHandle,
262 StatelessResetToken,
263 Random,
264 Event,
265 Limits,
266 Mtu,
267 Sync,
268 Tls,
269 Datagram,
270 Dc,
271 >
272{
273 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274 f.debug_struct("ClientConfig").finish()
275 }
276}
277
278impl<
279 CongestionController: congestion_controller::Endpoint,
280 ConnectionCloseFormatter: connection_close_formatter::Formatter,
281 ConnectionID: connection::id::Format,
282 PacketInterceptor: packet_interceptor::PacketInterceptor,
283 PathHandle: path::Handle,
284 StatelessResetToken: stateless_reset_token::Generator,
285 Random: s2n_quic_core::random::Generator,
286 Event: s2n_quic_core::event::Subscriber,
287 Limits: s2n_quic_core::connection::limits::Limiter,
288 Mtu: s2n_quic_core::path::mtu::Endpoint,
289 Sync: 'static + Send,
290 Tls: crypto::tls::Endpoint,
291 Datagram: s2n_quic_core::datagram::Endpoint,
292 Dc: s2n_quic_core::dc::Endpoint,
293 > endpoint::Config
294 for EndpointConfig<
295 CongestionController,
296 ConnectionCloseFormatter,
297 ConnectionID,
298 PacketInterceptor,
299 PathHandle,
300 StatelessResetToken,
301 Random,
302 Event,
303 Limits,
304 Mtu,
305 Sync,
306 Tls,
307 Datagram,
308 Dc,
309 >
310{
311 type ConnectionIdFormat = ConnectionID;
312 type ConnectionCloseFormatter = ConnectionCloseFormatter;
313 type PathHandle = PathHandle;
314 type StatelessResetTokenGenerator = StatelessResetToken;
315 type RandomGenerator = Random;
316 type Connection = connection::Implementation<Self>;
317 type ConnectionLock = std::sync::Mutex<Self::Connection>;
319 type CongestionControllerEndpoint = CongestionController;
320 type EndpointLimits = EndpointLimits;
321 type EventSubscriber = Event;
322 type TLSEndpoint = Tls;
323 type TokenFormat = Token;
324 type ConnectionLimits = Limits;
325 type Mtu = Mtu;
326 type StreamManager = stream::DefaultStreamManager;
327 type PathMigrationValidator = PathMigration;
328 type PacketInterceptor = PacketInterceptor;
329 type DatagramEndpoint = Datagram;
330 type DcEndpoint = Dc;
331
332 const ENDPOINT_TYPE: endpoint::Type = endpoint::Type::Client;
333
334 fn context(&mut self) -> endpoint::Context<'_, Self> {
335 endpoint::Context {
336 congestion_controller: &mut self.congestion_controller,
337 connection_close_formatter: &mut self.connection_close_formatter,
338 connection_id_format: &mut self.connection_id,
339 packet_interceptor: &mut self.packet_interceptor,
340 stateless_reset_token_generator: &mut self.stateless_reset_token,
341 random_generator: &mut self.random,
342 tls: &mut self.tls,
343 endpoint_limits: &mut self.endpoint_limits,
344 token: &mut self.token,
345 connection_limits: &mut self.limits,
346 mtu: &mut self.mtu,
347 event_subscriber: &mut self.event,
348 path_migration: &mut self.path_migration,
349 datagram: &mut self.datagram,
350 dc: &mut self.dc,
351 }
352 }
353}