Coverage Report

Created: 2025-10-31 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-rustls-0.26.2/src/lib.rs
Line
Count
Source
1
//! Asynchronous TLS/SSL streams for Tokio using [Rustls](https://github.com/rustls/rustls).
2
//!
3
//! # Why do I need to call `poll_flush`?
4
//!
5
//! Most TLS implementations will have an internal buffer to improve throughput,
6
//! and rustls is no exception.
7
//!
8
//! When we write data to `TlsStream`, we always write rustls buffer first,
9
//! then take out rustls encrypted data packet, and write it to data channel (like TcpStream).
10
//! When data channel is pending, some data may remain in rustls buffer.
11
//!
12
//! `tokio-rustls` To keep it simple and correct, [TlsStream] will behave like `BufWriter`.
13
//! For `TlsStream<TcpStream>`, this means that data written by `poll_write` is not guaranteed to be written to `TcpStream`.
14
//! You must call `poll_flush` to ensure that it is written to `TcpStream`.
15
//!
16
//! You should call `poll_flush` at the appropriate time,
17
//! such as when a period of `poll_write` write is complete and there is no more data to write.
18
//!
19
//! ## Why don't we write during `poll_read`?
20
//!
21
//! We did this in the early days of `tokio-rustls`, but it caused some bugs.
22
//! We can solve these bugs through some solutions, but this will cause performance degradation (reverse false wakeup).
23
//!
24
//! And reverse write will also prevent us implement full duplex in the future.
25
//!
26
//! see <https://github.com/tokio-rs/tls/issues/40>
27
//!
28
//! ## Why can't we handle it like `native-tls`?
29
//!
30
//! When data channel returns to pending, `native-tls` will falsely report the number of bytes it consumes.
31
//! This means that if data written by `poll_write` is not actually written to data channel, it will not return `Ready`.
32
//! Thus avoiding the call of `poll_flush`.
33
//!
34
//! but which does not conform to convention of `AsyncWrite` trait.
35
//! This means that if you give inconsistent data in two `poll_write`, it may cause unexpected behavior.
36
//!
37
//! see <https://github.com/tokio-rs/tls/issues/41>
38
39
use std::future::Future;
40
use std::io;
41
#[cfg(unix)]
42
use std::os::unix::io::{AsRawFd, RawFd};
43
#[cfg(windows)]
44
use std::os::windows::io::{AsRawSocket, RawSocket};
45
use std::pin::Pin;
46
use std::sync::Arc;
47
use std::task::{Context, Poll};
48
49
pub use rustls;
50
51
use rustls::pki_types::ServerName;
52
use rustls::server::AcceptedAlert;
53
use rustls::{ClientConfig, ClientConnection, CommonState, ServerConfig, ServerConnection};
54
use tokio::io::{AsyncBufRead, AsyncRead, AsyncWrite, ReadBuf};
55
56
macro_rules! ready {
57
    ( $e:expr ) => {
58
        match $e {
59
            std::task::Poll::Ready(t) => t,
60
            std::task::Poll::Pending => return std::task::Poll::Pending,
61
        }
62
    };
63
}
64
65
pub mod client;
66
mod common;
67
use common::{MidHandshake, TlsState};
68
pub mod server;
69
70
/// A wrapper around a `rustls::ClientConfig`, providing an async `connect` method.
71
#[derive(Clone)]
72
pub struct TlsConnector {
73
    inner: Arc<ClientConfig>,
74
    #[cfg(feature = "early-data")]
75
    early_data: bool,
76
}
77
78
/// A wrapper around a `rustls::ServerConfig`, providing an async `accept` method.
79
#[derive(Clone)]
80
pub struct TlsAcceptor {
81
    inner: Arc<ServerConfig>,
82
}
83
84
impl From<Arc<ClientConfig>> for TlsConnector {
85
0
    fn from(inner: Arc<ClientConfig>) -> TlsConnector {
86
0
        TlsConnector {
87
0
            inner,
88
0
            #[cfg(feature = "early-data")]
89
0
            early_data: false,
90
0
        }
91
0
    }
92
}
93
94
impl From<Arc<ServerConfig>> for TlsAcceptor {
95
0
    fn from(inner: Arc<ServerConfig>) -> TlsAcceptor {
96
0
        TlsAcceptor { inner }
97
0
    }
98
}
99
100
impl TlsConnector {
101
    /// Enable 0-RTT.
102
    ///
103
    /// If you want to use 0-RTT,
104
    /// You must also set `ClientConfig.enable_early_data` to `true`.
105
    #[cfg(feature = "early-data")]
106
    pub fn early_data(mut self, flag: bool) -> TlsConnector {
107
        self.early_data = flag;
108
        self
109
    }
110
111
    #[inline]
112
0
    pub fn connect<IO>(&self, domain: ServerName<'static>, stream: IO) -> Connect<IO>
113
0
    where
114
0
        IO: AsyncRead + AsyncWrite + Unpin,
115
    {
116
0
        self.connect_with(domain, stream, |_| ())
117
0
    }
Unexecuted instantiation: <tokio_rustls::TlsConnector>::connect::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>
Unexecuted instantiation: <tokio_rustls::TlsConnector>::connect::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>>
Unexecuted instantiation: <tokio_rustls::TlsConnector>::connect::<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>>
Unexecuted instantiation: <tokio_rustls::TlsConnector>::connect::<_>
118
119
0
    pub fn connect_with<IO, F>(&self, domain: ServerName<'static>, stream: IO, f: F) -> Connect<IO>
120
0
    where
121
0
        IO: AsyncRead + AsyncWrite + Unpin,
122
0
        F: FnOnce(&mut ClientConnection),
123
    {
124
0
        let mut session = match ClientConnection::new(self.inner.clone(), domain) {
125
0
            Ok(session) => session,
126
0
            Err(error) => {
127
0
                return Connect(MidHandshake::Error {
128
0
                    io: stream,
129
0
                    // TODO(eliza): should this really return an `io::Error`?
130
0
                    // Probably not...
131
0
                    error: io::Error::new(io::ErrorKind::Other, error),
132
0
                });
133
            }
134
        };
135
0
        f(&mut session);
136
137
0
        Connect(MidHandshake::Handshaking(client::TlsStream {
138
0
            io: stream,
139
0
140
0
            #[cfg(not(feature = "early-data"))]
141
0
            state: TlsState::Stream,
142
0
143
0
            #[cfg(feature = "early-data")]
144
0
            state: if self.early_data && session.early_data().is_some() {
145
0
                TlsState::EarlyData(0, Vec::new())
146
0
            } else {
147
0
                TlsState::Stream
148
0
            },
149
0
150
0
            #[cfg(feature = "early-data")]
151
0
            early_waker: None,
152
0
153
0
            session,
154
0
        }))
155
0
    }
Unexecuted instantiation: <tokio_rustls::TlsConnector>::connect_with::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>, <tokio_rustls::TlsConnector>::connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>::{closure#0}>
Unexecuted instantiation: <tokio_rustls::TlsConnector>::connect_with::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>, <tokio_rustls::TlsConnector>::connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>>::{closure#0}>
Unexecuted instantiation: <tokio_rustls::TlsConnector>::connect_with::<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>, <tokio_rustls::TlsConnector>::connect<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>>::{closure#0}>
Unexecuted instantiation: <tokio_rustls::TlsConnector>::connect_with::<_, _>
156
157
    /// Get a read-only reference to underlying config
158
0
    pub fn config(&self) -> &Arc<ClientConfig> {
159
0
        &self.inner
160
0
    }
161
}
162
163
impl TlsAcceptor {
164
    #[inline]
165
0
    pub fn accept<IO>(&self, stream: IO) -> Accept<IO>
166
0
    where
167
0
        IO: AsyncRead + AsyncWrite + Unpin,
168
    {
169
0
        self.accept_with(stream, |_| ())
170
0
    }
171
172
0
    pub fn accept_with<IO, F>(&self, stream: IO, f: F) -> Accept<IO>
173
0
    where
174
0
        IO: AsyncRead + AsyncWrite + Unpin,
175
0
        F: FnOnce(&mut ServerConnection),
176
    {
177
0
        let mut session = match ServerConnection::new(self.inner.clone()) {
178
0
            Ok(session) => session,
179
0
            Err(error) => {
180
0
                return Accept(MidHandshake::Error {
181
0
                    io: stream,
182
0
                    // TODO(eliza): should this really return an `io::Error`?
183
0
                    // Probably not...
184
0
                    error: io::Error::new(io::ErrorKind::Other, error),
185
0
                });
186
            }
187
        };
188
0
        f(&mut session);
189
190
0
        Accept(MidHandshake::Handshaking(server::TlsStream {
191
0
            session,
192
0
            io: stream,
193
0
            state: TlsState::Stream,
194
0
        }))
195
0
    }
196
197
    /// Get a read-only reference to underlying config
198
0
    pub fn config(&self) -> &Arc<ServerConfig> {
199
0
        &self.inner
200
0
    }
201
}
202
203
pub struct LazyConfigAcceptor<IO> {
204
    acceptor: rustls::server::Acceptor,
205
    io: Option<IO>,
206
    alert: Option<(rustls::Error, AcceptedAlert)>,
207
}
208
209
impl<IO> LazyConfigAcceptor<IO>
210
where
211
    IO: AsyncRead + AsyncWrite + Unpin,
212
{
213
    #[inline]
214
0
    pub fn new(acceptor: rustls::server::Acceptor, io: IO) -> Self {
215
0
        Self {
216
0
            acceptor,
217
0
            io: Some(io),
218
0
            alert: None,
219
0
        }
220
0
    }
221
222
    /// Takes back the client connection. Will return `None` if called more than once or if the
223
    /// connection has been accepted.
224
    ///
225
    /// # Example
226
    ///
227
    /// ```no_run
228
    /// # fn choose_server_config(
229
    /// #     _: rustls::server::ClientHello,
230
    /// # ) -> std::sync::Arc<rustls::ServerConfig> {
231
    /// #     unimplemented!();
232
    /// # }
233
    /// # #[allow(unused_variables)]
234
    /// # async fn listen() {
235
    /// use tokio::io::AsyncWriteExt;
236
    /// let listener = tokio::net::TcpListener::bind("127.0.0.1:4443").await.unwrap();
237
    /// let (stream, _) = listener.accept().await.unwrap();
238
    ///
239
    /// let acceptor = tokio_rustls::LazyConfigAcceptor::new(rustls::server::Acceptor::default(), stream);
240
    /// tokio::pin!(acceptor);
241
    ///
242
    /// match acceptor.as_mut().await {
243
    ///     Ok(start) => {
244
    ///         let clientHello = start.client_hello();
245
    ///         let config = choose_server_config(clientHello);
246
    ///         let stream = start.into_stream(config).await.unwrap();
247
    ///         // Proceed with handling the ServerConnection...
248
    ///     }
249
    ///     Err(err) => {
250
    ///         if let Some(mut stream) = acceptor.take_io() {
251
    ///             stream
252
    ///                 .write_all(
253
    ///                     format!("HTTP/1.1 400 Invalid Input\r\n\r\n\r\n{:?}\n", err)
254
    ///                         .as_bytes()
255
    ///                 )
256
    ///                 .await
257
    ///                 .unwrap();
258
    ///         }
259
    ///     }
260
    /// }
261
    /// # }
262
    /// ```
263
0
    pub fn take_io(&mut self) -> Option<IO> {
264
0
        self.io.take()
265
0
    }
266
}
267
268
impl<IO> Future for LazyConfigAcceptor<IO>
269
where
270
    IO: AsyncRead + AsyncWrite + Unpin,
271
{
272
    type Output = Result<StartHandshake<IO>, io::Error>;
273
274
0
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
275
0
        let this = self.get_mut();
276
        loop {
277
0
            let io = match this.io.as_mut() {
278
0
                Some(io) => io,
279
                None => {
280
0
                    return Poll::Ready(Err(io::Error::new(
281
0
                        io::ErrorKind::Other,
282
0
                        "acceptor cannot be polled after acceptance",
283
0
                    )))
284
                }
285
            };
286
287
0
            if let Some((err, mut alert)) = this.alert.take() {
288
0
                match alert.write(&mut common::SyncWriteAdapter { io, cx }) {
289
0
                    Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
290
0
                        this.alert = Some((err, alert));
291
0
                        return Poll::Pending;
292
                    }
293
                    Ok(0) | Err(_) => {
294
0
                        return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidData, err)))
295
                    }
296
                    Ok(_) => {
297
0
                        this.alert = Some((err, alert));
298
0
                        continue;
299
                    }
300
                };
301
0
            }
302
303
0
            let mut reader = common::SyncReadAdapter { io, cx };
304
0
            match this.acceptor.read_tls(&mut reader) {
305
0
                Ok(0) => return Err(io::ErrorKind::UnexpectedEof.into()).into(),
306
0
                Ok(_) => {}
307
0
                Err(e) if e.kind() == io::ErrorKind::WouldBlock => return Poll::Pending,
308
0
                Err(e) => return Err(e).into(),
309
            }
310
311
0
            match this.acceptor.accept() {
312
0
                Ok(Some(accepted)) => {
313
0
                    let io = this.io.take().unwrap();
314
0
                    return Poll::Ready(Ok(StartHandshake { accepted, io }));
315
                }
316
0
                Ok(None) => {}
317
0
                Err((err, alert)) => {
318
0
                    this.alert = Some((err, alert));
319
0
                }
320
            }
321
        }
322
0
    }
323
}
324
325
pub struct StartHandshake<IO> {
326
    accepted: rustls::server::Accepted,
327
    io: IO,
328
}
329
330
impl<IO> StartHandshake<IO>
331
where
332
    IO: AsyncRead + AsyncWrite + Unpin,
333
{
334
0
    pub fn client_hello(&self) -> rustls::server::ClientHello<'_> {
335
0
        self.accepted.client_hello()
336
0
    }
337
338
0
    pub fn into_stream(self, config: Arc<ServerConfig>) -> Accept<IO> {
339
0
        self.into_stream_with(config, |_| ())
340
0
    }
341
342
0
    pub fn into_stream_with<F>(self, config: Arc<ServerConfig>, f: F) -> Accept<IO>
343
0
    where
344
0
        F: FnOnce(&mut ServerConnection),
345
    {
346
0
        let mut conn = match self.accepted.into_connection(config) {
347
0
            Ok(conn) => conn,
348
0
            Err((error, alert)) => {
349
0
                return Accept(MidHandshake::SendAlert {
350
0
                    io: self.io,
351
0
                    alert,
352
0
                    // TODO(eliza): should this really return an `io::Error`?
353
0
                    // Probably not...
354
0
                    error: io::Error::new(io::ErrorKind::InvalidData, error),
355
0
                });
356
            }
357
        };
358
0
        f(&mut conn);
359
360
0
        Accept(MidHandshake::Handshaking(server::TlsStream {
361
0
            session: conn,
362
0
            io: self.io,
363
0
            state: TlsState::Stream,
364
0
        }))
365
0
    }
366
}
367
368
/// Future returned from `TlsConnector::connect` which will resolve
369
/// once the connection handshake has finished.
370
pub struct Connect<IO>(MidHandshake<client::TlsStream<IO>>);
371
372
/// Future returned from `TlsAcceptor::accept` which will resolve
373
/// once the accept handshake has finished.
374
pub struct Accept<IO>(MidHandshake<server::TlsStream<IO>>);
375
376
/// Like [Connect], but returns `IO` on failure.
377
pub struct FallibleConnect<IO>(MidHandshake<client::TlsStream<IO>>);
378
379
/// Like [Accept], but returns `IO` on failure.
380
pub struct FallibleAccept<IO>(MidHandshake<server::TlsStream<IO>>);
381
382
impl<IO> Connect<IO> {
383
    #[inline]
384
0
    pub fn into_fallible(self) -> FallibleConnect<IO> {
385
0
        FallibleConnect(self.0)
386
0
    }
387
388
0
    pub fn get_ref(&self) -> Option<&IO> {
389
0
        match &self.0 {
390
0
            MidHandshake::Handshaking(sess) => Some(sess.get_ref().0),
391
0
            MidHandshake::SendAlert { io, .. } => Some(io),
392
0
            MidHandshake::Error { io, .. } => Some(io),
393
0
            MidHandshake::End => None,
394
        }
395
0
    }
396
397
0
    pub fn get_mut(&mut self) -> Option<&mut IO> {
398
0
        match &mut self.0 {
399
0
            MidHandshake::Handshaking(sess) => Some(sess.get_mut().0),
400
0
            MidHandshake::SendAlert { io, .. } => Some(io),
401
0
            MidHandshake::Error { io, .. } => Some(io),
402
0
            MidHandshake::End => None,
403
        }
404
0
    }
405
}
406
407
impl<IO> Accept<IO> {
408
    #[inline]
409
0
    pub fn into_fallible(self) -> FallibleAccept<IO> {
410
0
        FallibleAccept(self.0)
411
0
    }
412
413
0
    pub fn get_ref(&self) -> Option<&IO> {
414
0
        match &self.0 {
415
0
            MidHandshake::Handshaking(sess) => Some(sess.get_ref().0),
416
0
            MidHandshake::SendAlert { io, .. } => Some(io),
417
0
            MidHandshake::Error { io, .. } => Some(io),
418
0
            MidHandshake::End => None,
419
        }
420
0
    }
421
422
0
    pub fn get_mut(&mut self) -> Option<&mut IO> {
423
0
        match &mut self.0 {
424
0
            MidHandshake::Handshaking(sess) => Some(sess.get_mut().0),
425
0
            MidHandshake::SendAlert { io, .. } => Some(io),
426
0
            MidHandshake::Error { io, .. } => Some(io),
427
0
            MidHandshake::End => None,
428
        }
429
0
    }
430
}
431
432
impl<IO: AsyncRead + AsyncWrite + Unpin> Future for Connect<IO> {
433
    type Output = io::Result<client::TlsStream<IO>>;
434
435
    #[inline]
436
0
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
437
0
        Pin::new(&mut self.0).poll(cx).map_err(|(err, _)| err)
438
0
    }
Unexecuted instantiation: <tokio_rustls::Connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as core::future::future::Future>::poll
Unexecuted instantiation: <tokio_rustls::Connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as core::future::future::Future>::poll
Unexecuted instantiation: <tokio_rustls::Connect<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as core::future::future::Future>::poll
Unexecuted instantiation: <tokio_rustls::Connect<_> as core::future::future::Future>::poll
439
}
440
441
impl<IO: AsyncRead + AsyncWrite + Unpin> Future for Accept<IO> {
442
    type Output = io::Result<server::TlsStream<IO>>;
443
444
    #[inline]
445
0
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
446
0
        Pin::new(&mut self.0).poll(cx).map_err(|(err, _)| err)
447
0
    }
448
}
449
450
impl<IO: AsyncRead + AsyncWrite + Unpin> Future for FallibleConnect<IO> {
451
    type Output = Result<client::TlsStream<IO>, (io::Error, IO)>;
452
453
    #[inline]
454
0
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
455
0
        Pin::new(&mut self.0).poll(cx)
456
0
    }
457
}
458
459
impl<IO: AsyncRead + AsyncWrite + Unpin> Future for FallibleAccept<IO> {
460
    type Output = Result<server::TlsStream<IO>, (io::Error, IO)>;
461
462
    #[inline]
463
0
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
464
0
        Pin::new(&mut self.0).poll(cx)
465
0
    }
466
}
467
468
/// Unified TLS stream type
469
///
470
/// This abstracts over the inner `client::TlsStream` and `server::TlsStream`, so you can use
471
/// a single type to keep both client- and server-initiated TLS-encrypted connections.
472
#[allow(clippy::large_enum_variant)] // https://github.com/rust-lang/rust-clippy/issues/9798
473
#[derive(Debug)]
474
pub enum TlsStream<T> {
475
    Client(client::TlsStream<T>),
476
    Server(server::TlsStream<T>),
477
}
478
479
impl<T> TlsStream<T> {
480
0
    pub fn get_ref(&self) -> (&T, &CommonState) {
481
        use TlsStream::*;
482
0
        match self {
483
0
            Client(io) => {
484
0
                let (io, session) = io.get_ref();
485
0
                (io, session)
486
            }
487
0
            Server(io) => {
488
0
                let (io, session) = io.get_ref();
489
0
                (io, session)
490
            }
491
        }
492
0
    }
493
494
0
    pub fn get_mut(&mut self) -> (&mut T, &mut CommonState) {
495
        use TlsStream::*;
496
0
        match self {
497
0
            Client(io) => {
498
0
                let (io, session) = io.get_mut();
499
0
                (io, &mut *session)
500
            }
501
0
            Server(io) => {
502
0
                let (io, session) = io.get_mut();
503
0
                (io, &mut *session)
504
            }
505
        }
506
0
    }
507
}
508
509
impl<T> From<client::TlsStream<T>> for TlsStream<T> {
510
0
    fn from(s: client::TlsStream<T>) -> Self {
511
0
        Self::Client(s)
512
0
    }
513
}
514
515
impl<T> From<server::TlsStream<T>> for TlsStream<T> {
516
0
    fn from(s: server::TlsStream<T>) -> Self {
517
0
        Self::Server(s)
518
0
    }
519
}
520
521
#[cfg(unix)]
522
impl<S> AsRawFd for TlsStream<S>
523
where
524
    S: AsRawFd,
525
{
526
0
    fn as_raw_fd(&self) -> RawFd {
527
0
        self.get_ref().0.as_raw_fd()
528
0
    }
529
}
530
531
#[cfg(windows)]
532
impl<S> AsRawSocket for TlsStream<S>
533
where
534
    S: AsRawSocket,
535
{
536
    fn as_raw_socket(&self) -> RawSocket {
537
        self.get_ref().0.as_raw_socket()
538
    }
539
}
540
541
impl<T> AsyncRead for TlsStream<T>
542
where
543
    T: AsyncRead + AsyncWrite + Unpin,
544
{
545
    #[inline]
546
0
    fn poll_read(
547
0
        self: Pin<&mut Self>,
548
0
        cx: &mut Context<'_>,
549
0
        buf: &mut ReadBuf<'_>,
550
0
    ) -> Poll<io::Result<()>> {
551
0
        match self.get_mut() {
552
0
            TlsStream::Client(x) => Pin::new(x).poll_read(cx, buf),
553
0
            TlsStream::Server(x) => Pin::new(x).poll_read(cx, buf),
554
        }
555
0
    }
556
}
557
558
impl<T> AsyncBufRead for TlsStream<T>
559
where
560
    T: AsyncRead + AsyncWrite + Unpin,
561
{
562
    #[inline]
563
0
    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
564
0
        match self.get_mut() {
565
0
            TlsStream::Client(x) => Pin::new(x).poll_fill_buf(cx),
566
0
            TlsStream::Server(x) => Pin::new(x).poll_fill_buf(cx),
567
        }
568
0
    }
569
570
    #[inline]
571
0
    fn consume(self: Pin<&mut Self>, amt: usize) {
572
0
        match self.get_mut() {
573
0
            TlsStream::Client(x) => Pin::new(x).consume(amt),
574
0
            TlsStream::Server(x) => Pin::new(x).consume(amt),
575
        }
576
0
    }
577
}
578
579
impl<T> AsyncWrite for TlsStream<T>
580
where
581
    T: AsyncRead + AsyncWrite + Unpin,
582
{
583
    #[inline]
584
0
    fn poll_write(
585
0
        self: Pin<&mut Self>,
586
0
        cx: &mut Context<'_>,
587
0
        buf: &[u8],
588
0
    ) -> Poll<io::Result<usize>> {
589
0
        match self.get_mut() {
590
0
            TlsStream::Client(x) => Pin::new(x).poll_write(cx, buf),
591
0
            TlsStream::Server(x) => Pin::new(x).poll_write(cx, buf),
592
        }
593
0
    }
594
595
    #[inline]
596
0
    fn poll_write_vectored(
597
0
        self: Pin<&mut Self>,
598
0
        cx: &mut Context<'_>,
599
0
        bufs: &[io::IoSlice<'_>],
600
0
    ) -> Poll<io::Result<usize>> {
601
0
        match self.get_mut() {
602
0
            TlsStream::Client(x) => Pin::new(x).poll_write_vectored(cx, bufs),
603
0
            TlsStream::Server(x) => Pin::new(x).poll_write_vectored(cx, bufs),
604
        }
605
0
    }
606
607
    #[inline]
608
0
    fn is_write_vectored(&self) -> bool {
609
0
        match self {
610
0
            TlsStream::Client(x) => x.is_write_vectored(),
611
0
            TlsStream::Server(x) => x.is_write_vectored(),
612
        }
613
0
    }
614
615
    #[inline]
616
0
    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
617
0
        match self.get_mut() {
618
0
            TlsStream::Client(x) => Pin::new(x).poll_flush(cx),
619
0
            TlsStream::Server(x) => Pin::new(x).poll_flush(cx),
620
        }
621
0
    }
622
623
    #[inline]
624
0
    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
625
0
        match self.get_mut() {
626
0
            TlsStream::Client(x) => Pin::new(x).poll_shutdown(cx),
627
0
            TlsStream::Server(x) => Pin::new(x).poll_shutdown(cx),
628
        }
629
0
    }
630
}