1use std::future::Future;
2use std::io::{self, BufRead as _};
3#[cfg(unix)]
4use std::os::unix::io::{AsRawFd, RawFd};
5#[cfg(windows)]
6use std::os::windows::io::{AsRawSocket, RawSocket};
7use std::pin::Pin;
8use std::sync::Arc;
9#[cfg(feature = "early-data")]
10use std::task::Waker;
11use std::task::{Context, Poll};
12
13use rustls::pki_types::ServerName;
14use rustls::{ClientConfig, ClientConnection};
15use tokio::io::{AsyncBufRead, AsyncRead, AsyncWrite, ReadBuf};
16
17use crate::common::{IoSession, MidHandshake, Stream, TlsState};
18
19#[derive(Clone)]
21pub struct TlsConnector {
22 inner: Arc<ClientConfig>,
23 #[cfg(feature = "early-data")]
24 early_data: bool,
25}
26
27impl TlsConnector {
28 #[cfg(feature = "early-data")]
33 pub fn early_data(mut self, flag: bool) -> Self {
34 self.early_data = flag;
35 self
36 }
37
38 #[inline]
45 pub fn connect<IO>(&self, domain: ServerName<'static>, stream: IO) -> Connect<IO>
46 where
47 IO: AsyncRead + AsyncWrite + Unpin,
48 {
49 self.connect_impl(domain, stream, None, |_| ())
50 }
51
52 #[inline]
62 pub fn connect_with<IO, F>(&self, domain: ServerName<'static>, stream: IO, f: F) -> Connect<IO>
63 where
64 IO: AsyncRead + AsyncWrite + Unpin,
65 F: FnOnce(&mut ClientConnection),
66 {
67 self.connect_impl(domain, stream, None, f)
68 }
69
70 fn connect_impl<IO, F>(
71 &self,
72 domain: ServerName<'static>,
73 stream: IO,
74 alpn_protocols: Option<Vec<Vec<u8>>>,
75 f: F,
76 ) -> Connect<IO>
77 where
78 IO: AsyncRead + AsyncWrite + Unpin,
79 F: FnOnce(&mut ClientConnection),
80 {
81 let alpn = alpn_protocols.unwrap_or_else(|| self.inner.alpn_protocols.clone());
82 let mut session = match ClientConnection::new_with_alpn(self.inner.clone(), domain, alpn) {
83 Ok(session) => session,
84 Err(error) => {
85 return Connect(MidHandshake::Error {
86 io: stream,
87 error: io::Error::new(io::ErrorKind::Other, error),
90 });
91 }
92 };
93 f(&mut session);
94
95 Connect(MidHandshake::Handshaking(TlsStream {
96 io: stream,
97
98 #[cfg(not(feature = "early-data"))]
99 state: TlsState::Stream,
100
101 #[cfg(feature = "early-data")]
102 state: if self.early_data && session.early_data().is_some() {
103 TlsState::EarlyData(0, Vec::new())
104 } else {
105 TlsState::Stream
106 },
107
108 need_flush: false,
109
110 #[cfg(feature = "early-data")]
111 early_waker: None,
112
113 session,
114 }))
115 }
116
117 pub fn with_alpn(&self, alpn_protocols: Vec<Vec<u8>>) -> TlsConnectorWithAlpn<'_> {
118 TlsConnectorWithAlpn {
119 inner: self,
120 alpn_protocols,
121 }
122 }
123
124 pub fn config(&self) -> &Arc<ClientConfig> {
126 &self.inner
127 }
128}
129
130impl From<Arc<ClientConfig>> for TlsConnector {
131 fn from(inner: Arc<ClientConfig>) -> Self {
132 Self {
133 inner,
134 #[cfg(feature = "early-data")]
135 early_data: false,
136 }
137 }
138}
139
140pub struct TlsConnectorWithAlpn<'c> {
141 inner: &'c TlsConnector,
142 alpn_protocols: Vec<Vec<u8>>,
143}
144
145impl TlsConnectorWithAlpn<'_> {
146 #[inline]
153 pub fn connect<IO>(self, domain: ServerName<'static>, stream: IO) -> Connect<IO>
154 where
155 IO: AsyncRead + AsyncWrite + Unpin,
156 {
157 self.inner
158 .connect_impl(domain, stream, Some(self.alpn_protocols), |_| ())
159 }
160
161 #[inline]
171 pub fn connect_with<IO, F>(self, domain: ServerName<'static>, stream: IO, f: F) -> Connect<IO>
172 where
173 IO: AsyncRead + AsyncWrite + Unpin,
174 F: FnOnce(&mut ClientConnection),
175 {
176 self.inner
177 .connect_impl(domain, stream, Some(self.alpn_protocols), f)
178 }
179}
180
181pub struct Connect<IO>(MidHandshake<TlsStream<IO>>);
184
185impl<IO> Connect<IO> {
186 #[inline]
187 pub fn into_fallible(self) -> FallibleConnect<IO> {
188 FallibleConnect(self.0)
189 }
190
191 pub fn get_ref(&self) -> Option<&IO> {
192 match &self.0 {
193 MidHandshake::Handshaking(sess) => Some(sess.get_ref().0),
194 MidHandshake::SendAlert { io, .. } => Some(io),
195 MidHandshake::Error { io, .. } => Some(io),
196 MidHandshake::End => None,
197 }
198 }
199
200 pub fn get_mut(&mut self) -> Option<&mut IO> {
201 match &mut self.0 {
202 MidHandshake::Handshaking(sess) => Some(sess.get_mut().0),
203 MidHandshake::SendAlert { io, .. } => Some(io),
204 MidHandshake::Error { io, .. } => Some(io),
205 MidHandshake::End => None,
206 }
207 }
208}
209
210impl<IO: AsyncRead + AsyncWrite + Unpin> Future for Connect<IO> {
211 type Output = io::Result<TlsStream<IO>>;
212
213 #[inline]
214 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
215 Pin::new(&mut self.0).poll(cx).map_err(|(err, _)| err)
216 }
217}
218
219impl<IO: AsyncRead + AsyncWrite + Unpin> Future for FallibleConnect<IO> {
220 type Output = Result<TlsStream<IO>, (io::Error, IO)>;
221
222 #[inline]
223 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
224 Pin::new(&mut self.0).poll(cx)
225 }
226}
227
228pub struct FallibleConnect<IO>(MidHandshake<TlsStream<IO>>);
230
231#[derive(Debug)]
234pub struct TlsStream<IO> {
235 pub(crate) io: IO,
236 pub(crate) session: ClientConnection,
237 pub(crate) state: TlsState,
238 pub(crate) need_flush: bool,
239
240 #[cfg(feature = "early-data")]
241 pub(crate) early_waker: Option<Waker>,
242}
243
244impl<IO> TlsStream<IO> {
245 #[inline]
246 pub fn get_ref(&self) -> (&IO, &ClientConnection) {
247 (&self.io, &self.session)
248 }
249
250 #[inline]
251 pub fn get_mut(&mut self) -> (&mut IO, &mut ClientConnection) {
252 (&mut self.io, &mut self.session)
253 }
254
255 #[inline]
256 pub fn into_inner(self) -> (IO, ClientConnection) {
257 (self.io, self.session)
258 }
259}
260
261#[cfg(unix)]
262impl<S> AsRawFd for TlsStream<S>
263where
264 S: AsRawFd,
265{
266 fn as_raw_fd(&self) -> RawFd {
267 self.get_ref().0.as_raw_fd()
268 }
269}
270
271#[cfg(windows)]
272impl<S> AsRawSocket for TlsStream<S>
273where
274 S: AsRawSocket,
275{
276 fn as_raw_socket(&self) -> RawSocket {
277 self.get_ref().0.as_raw_socket()
278 }
279}
280
281impl<IO> IoSession for TlsStream<IO> {
282 type Io = IO;
283 type Session = ClientConnection;
284
285 #[inline]
286 fn skip_handshake(&self) -> bool {
287 self.state.is_early_data()
288 }
289
290 #[inline]
291 fn get_mut(&mut self) -> (&mut TlsState, &mut Self::Io, &mut Self::Session, &mut bool) {
292 (
293 &mut self.state,
294 &mut self.io,
295 &mut self.session,
296 &mut self.need_flush,
297 )
298 }
299
300 #[inline]
301 fn into_io(self) -> Self::Io {
302 self.io
303 }
304}
305
306#[cfg(feature = "early-data")]
307impl<IO> TlsStream<IO>
308where
309 IO: AsyncRead + AsyncWrite + Unpin,
310{
311 fn poll_early_data(&mut self, cx: &mut Context<'_>) {
312 if self
319 .early_waker
320 .as_ref()
321 .filter(|waker| cx.waker().will_wake(waker))
322 .is_none()
323 {
324 self.early_waker = Some(cx.waker().clone());
325 }
326 }
327}
328
329impl<IO> AsyncRead for TlsStream<IO>
330where
331 IO: AsyncRead + AsyncWrite + Unpin,
332{
333 fn poll_read(
334 mut self: Pin<&mut Self>,
335 cx: &mut Context<'_>,
336 buf: &mut ReadBuf<'_>,
337 ) -> Poll<io::Result<()>> {
338 let data = ready!(self.as_mut().poll_fill_buf(cx))?;
339 let len = data.len().min(buf.remaining());
340 if len == 0 {
341 return Poll::Ready(Ok(()));
342 }
343 buf.put_slice(&data[..len]);
344 self.as_mut().consume(len);
345
346 while buf.remaining() > 0 {
347 let data = match self.as_mut().poll_fill_buf(cx) {
348 Poll::Ready(Ok([])) => break,
349 Poll::Ready(Ok(data)) => data,
350 Poll::Ready(Err(_)) => break, Poll::Pending => break,
352 };
353 let len = Ord::min(data.len(), buf.remaining());
354 buf.put_slice(&data[..len]);
355 self.as_mut().consume(len);
356 }
357 Poll::Ready(Ok(()))
358 }
359}
360
361impl<IO> AsyncBufRead for TlsStream<IO>
362where
363 IO: AsyncRead + AsyncWrite + Unpin,
364{
365 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
366 match self.state {
367 #[cfg(feature = "early-data")]
368 TlsState::EarlyData(..) => {
369 self.get_mut().poll_early_data(cx);
370 Poll::Pending
371 }
372 TlsState::Stream | TlsState::WriteShutdown => {
373 let this = self.get_mut();
374 let stream =
375 Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable());
376
377 match stream.poll_fill_buf(cx) {
378 Poll::Ready(Ok(buf)) => {
379 if buf.is_empty() {
380 this.state.shutdown_read();
381 }
382
383 Poll::Ready(Ok(buf))
384 }
385 Poll::Ready(Err(err)) if err.kind() == io::ErrorKind::ConnectionAborted => {
386 this.state.shutdown_read();
387 Poll::Ready(Err(err))
388 }
389 output => output,
390 }
391 }
392 TlsState::ReadShutdown | TlsState::FullyShutdown => Poll::Ready(Ok(&[])),
393 }
394 }
395
396 fn consume(mut self: Pin<&mut Self>, amt: usize) {
397 self.session.reader().consume(amt);
398 }
399}
400
401impl<IO> AsyncWrite for TlsStream<IO>
402where
403 IO: AsyncRead + AsyncWrite + Unpin,
404{
405 fn poll_write(
408 self: Pin<&mut Self>,
409 cx: &mut Context<'_>,
410 buf: &[u8],
411 ) -> Poll<io::Result<usize>> {
412 let this = self.get_mut();
413 let mut stream = Stream::new(&mut this.io, &mut this.session)
414 .set_eof(!this.state.readable())
415 .set_need_flush(this.need_flush);
416
417 #[cfg(feature = "early-data")]
418 {
419 let bufs = [io::IoSlice::new(buf)];
420 let written = poll_handle_early_data(
421 &mut this.state,
422 &mut stream,
423 &mut this.early_waker,
424 cx,
425 &bufs,
426 )?;
427 match written {
428 Poll::Ready(0) => {}
429 Poll::Ready(written) => return Poll::Ready(Ok(written)),
430 Poll::Pending => {
431 this.need_flush = stream.need_flush;
432 return Poll::Pending;
433 }
434 }
435 }
436
437 stream.as_mut_pin().poll_write(cx, buf)
438 }
439
440 fn poll_write_vectored(
443 self: Pin<&mut Self>,
444 cx: &mut Context<'_>,
445 bufs: &[io::IoSlice<'_>],
446 ) -> Poll<io::Result<usize>> {
447 let this = self.get_mut();
448 let mut stream = Stream::new(&mut this.io, &mut this.session)
449 .set_eof(!this.state.readable())
450 .set_need_flush(this.need_flush);
451
452 #[cfg(feature = "early-data")]
453 {
454 let written = poll_handle_early_data(
455 &mut this.state,
456 &mut stream,
457 &mut this.early_waker,
458 cx,
459 bufs,
460 )?;
461 match written {
462 Poll::Ready(0) => {}
463 Poll::Ready(written) => return Poll::Ready(Ok(written)),
464 Poll::Pending => {
465 this.need_flush = stream.need_flush;
466 return Poll::Pending;
467 }
468 }
469 }
470
471 stream.as_mut_pin().poll_write_vectored(cx, bufs)
472 }
473
474 #[inline]
475 fn is_write_vectored(&self) -> bool {
476 true
477 }
478
479 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
480 let this = self.get_mut();
481 let mut stream = Stream::new(&mut this.io, &mut this.session)
482 .set_eof(!this.state.readable())
483 .set_need_flush(this.need_flush);
484
485 #[cfg(feature = "early-data")]
486 {
487 let written = poll_handle_early_data(
488 &mut this.state,
489 &mut stream,
490 &mut this.early_waker,
491 cx,
492 &[],
493 )?;
494 if written.is_pending() {
495 this.need_flush = stream.need_flush;
496 return Poll::Pending;
497 }
498 }
499
500 stream.as_mut_pin().poll_flush(cx)
501 }
502
503 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
504 #[cfg(feature = "early-data")]
505 {
506 if matches!(self.state, TlsState::EarlyData(..)) {
508 ready!(self.as_mut().poll_flush(cx))?;
509 }
510 }
511
512 if self.state.writeable() {
513 self.session.send_close_notify();
514 self.state.shutdown_write();
515 }
516
517 let this = self.get_mut();
518 let mut stream =
519 Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable());
520 stream.as_mut_pin().poll_shutdown(cx)
521 }
522}
523
524#[cfg(feature = "early-data")]
525fn poll_handle_early_data<IO>(
526 state: &mut TlsState,
527 stream: &mut Stream<IO, ClientConnection>,
528 early_waker: &mut Option<Waker>,
529 cx: &mut Context<'_>,
530 bufs: &[io::IoSlice<'_>],
531) -> Poll<io::Result<usize>>
532where
533 IO: AsyncRead + AsyncWrite + Unpin,
534{
535 if let TlsState::EarlyData(pos, data) = state {
536 use std::io::Write;
537
538 if let Some(mut early_data) = stream.session.early_data() {
540 let mut written = 0;
541
542 for buf in bufs {
543 if buf.is_empty() {
544 continue;
545 }
546
547 let len = match early_data.write(buf) {
548 Ok(0) => break,
549 Ok(n) => n,
550 Err(err) => return Poll::Ready(Err(err)),
551 };
552
553 written += len;
554 data.extend_from_slice(&buf[..len]);
555
556 if len < buf.len() {
557 break;
558 }
559 }
560
561 if written != 0 {
562 return Poll::Ready(Ok(written));
563 }
564 }
565
566 while stream.session.is_handshaking() {
568 ready!(stream.handshake(cx))?;
569 }
570
571 if !stream.session.is_early_data_accepted() {
573 while *pos < data.len() {
574 let len = ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?;
575 *pos += len;
576 }
577 }
578
579 *state = TlsState::Stream;
581
582 if let Some(waker) = early_waker.take() {
583 waker.wake();
584 }
585 }
586
587 Poll::Ready(Ok(0))
588}