s2n_quic/client.rs
1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5 connection::{self, Connection},
6 provider::*,
7};
8use core::{
9 fmt,
10 future::Future,
11 pin::Pin,
12 task::{Context, Poll},
13};
14use s2n_quic_transport::endpoint::{connect, handle::Connector};
15
16mod builder;
17mod providers;
18
19pub use builder::*;
20pub use connect::Connect;
21pub use providers::*;
22
23/// A QUIC client endpoint, capable of opening connections
24#[derive(Clone)]
25pub struct Client {
26 connector: Connector,
27 local_addr: s2n_quic_core::inet::SocketAddress,
28}
29
30impl fmt::Debug for Client {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 f.debug_struct("Client")
33 .field("local_addr", &self.local_addr().ok())
34 .finish()
35 }
36}
37
38impl Client {
39 /// Starts listening on the provided socket
40 ///
41 /// # Examples
42 ///
43 /// ```rust,no_run
44 /// # use std::error::Error;
45 /// # use s2n_quic::Client;
46 /// #
47 /// # fn main() -> Result<(), Box<dyn Error>> {
48 /// let Client = Client::bind("0.0.0.0:0")?;
49 /// #
50 /// # Ok(())
51 /// # }
52 /// ```
53 pub fn bind<T>(socket: T) -> Result<Self, StartError>
54 where
55 T: io::TryInto,
56 {
57 let client = Self::builder()
58 .with_io(socket)
59 .map_err(StartError::new)?
60 .start()?;
61 Ok(client)
62 }
63
64 /// Returns a [`Builder`] which is able to configure the [`Client`] components.
65 ///
66 /// # Examples
67 ///
68 /// ```rust,no_run
69 /// # use std::error::Error;
70 /// use std::path::Path;
71 /// use s2n_quic::Client;
72 ///
73 /// #
74 /// # fn main() -> Result<(), Box<dyn Error>> {
75 /// let client = Client::builder()
76 /// .with_tls(Path::new("./certs/cert.pem"))?
77 /// .with_io("0.0.0.0:0")?
78 /// .start()?;
79 /// #
80 /// # Ok(())
81 /// # }
82 /// ```
83 pub fn builder() -> Builder<impl ClientProviders> {
84 Builder::default()
85 }
86
87 /// Establishes a connection to the specified endpoint
88 ///
89 /// # Examples
90 ///
91 /// ```rust,no_run
92 /// # use std::error::Error;
93 /// use s2n_quic::Client;
94 /// use std::{net::SocketAddr, path::Path};
95 ///
96 /// # async fn connect() -> Result<(), Box<dyn Error>> {
97 /// let client = Client::builder()
98 /// .with_tls(Path::new("./certs/cert.pem"))?
99 /// .with_io("0.0.0.0:0")?
100 /// .start()?;
101 ///
102 /// let addr: SocketAddr = "127.0.0.1:443".parse()?;
103 /// let connection = client.connect(addr.into()).await?;
104 /// #
105 /// # Ok(())
106 /// # }
107 /// ```
108 pub fn connect(&self, connect: Connect) -> ConnectionAttempt {
109 let attempt = self.connector.connect(connect);
110 ConnectionAttempt(attempt)
111 }
112
113 /// Wait for the client endpoint to finish handling all outstanding connections
114 ///
115 /// Notifies the endpoint of application interest in closing the endpoint. The
116 /// call waits for **all** outstanding connections to finish before returning.
117 ///
118 /// Note: The endpoint will continue to accept new connection attempts. If there
119 /// are other client handles with active connections, then this call will never
120 /// return.
121 ///
122 /// # Examples
123 ///
124 /// ```rust,no_run
125 /// # use std::error::Error;
126 /// use s2n_quic::Client;
127 /// use std::{net::SocketAddr, path::Path};
128 ///
129 /// # async fn connect() -> Result<(), Box<dyn Error>> {
130 /// let mut client = Client::builder()
131 /// .with_tls(Path::new("./certs/cert.pem"))?
132 /// .with_io("0.0.0.0:0")?
133 /// .start()?;
134 ///
135 /// let addr: SocketAddr = "127.0.0.1:443".parse()?;
136 /// let connection = client.connect(addr.into()).await?;
137 ///
138 /// client.wait_idle().await?;
139 /// #
140 /// # Ok(())
141 /// # }
142 /// ```
143 pub async fn wait_idle(&mut self) -> Result<(), connection::Error> {
144 futures::future::poll_fn(|cx| self.connector.poll_close(cx)).await
145 }
146
147 /// Returns the local address that this listener is bound to.
148 ///
149 /// This can be useful, for example, when binding to port `0` to figure out which
150 /// port was actually bound.
151 ///
152 /// # Examples
153 ///
154 /// ```rust,no_run
155 /// # use std::error::Error;
156 /// # use s2n_quic::Client;
157 /// #
158 /// # fn main() -> Result<(), Box<dyn Error>> {
159 /// let client = Client::bind("0.0.0.0:0")?;
160 ///
161 /// let local_addr = client.local_addr()?;
162 /// assert_ne!(local_addr.port(), 0);
163 /// # Ok(())
164 /// # }
165 /// ```
166 pub fn local_addr(&self) -> Result<std::net::SocketAddr, std::io::Error> {
167 Ok(self.local_addr.into())
168 }
169}
170
171#[must_use = "futures do nothing unless you `.await` or poll them"]
172pub struct ConnectionAttempt(connect::Attempt);
173
174impl Future for ConnectionAttempt {
175 type Output = Result<Connection, connection::Error>;
176
177 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
178 match Pin::new(&mut self.0).poll(cx) {
179 Poll::Ready(Ok(conn)) => Poll::Ready(Ok(Connection::new(conn))),
180 Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
181 Poll::Pending => Poll::Pending,
182 }
183 }
184}