1#![deny(missing_docs, missing_debug_implementations, unsafe_code)]
7#![warn(unreachable_pub, unused_qualifications, unused_lifetimes)]
8#![warn(
9 clippy::must_use_candidate,
10 clippy::unwrap_in_result,
11 clippy::panic_in_result_fn
12)]
13
14use futures_io::{AsyncRead, AsyncWrite};
15use openssl::{
16 error::ErrorStack,
17 ssl::{self, ErrorCode, ShutdownResult, Ssl, SslRef},
18};
19use std::{
20 fmt, future,
21 io::{self, Read, Write},
22 pin::Pin,
23 task::{Context, Poll, Waker},
24};
25
26#[cfg(test)]
27mod test;
28
29struct StreamWrapper<S: Unpin> {
30 stream: S,
31 waker: Option<Waker>,
32}
33
34impl<S> fmt::Debug for StreamWrapper<S>
35where
36 S: fmt::Debug + Unpin,
37{
38 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
39 self.stream.fmt(fmt)
40 }
41}
42
43impl<S: Unpin> StreamWrapper<S> {
44 fn parts(&mut self) -> (Pin<&mut S>, Context<'_>) {
45 let stream = Pin::new(&mut self.stream);
46 let context = Context::from_waker(self.waker.as_ref().unwrap_or(Waker::noop()));
49 (stream, context)
50 }
51}
52
53impl<S> Read for StreamWrapper<S>
54where
55 S: AsyncRead + Unpin,
56{
57 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
58 let (stream, mut cx) = self.parts();
59 match stream.poll_read(&mut cx, buf)? {
60 Poll::Ready(nread) => Ok(nread),
61 Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)),
62 }
63 }
64}
65
66impl<S> Write for StreamWrapper<S>
67where
68 S: AsyncWrite + Unpin,
69{
70 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
71 let (stream, mut cx) = self.parts();
72 match stream.poll_write(&mut cx, buf) {
73 Poll::Ready(r) => r,
74 Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)),
75 }
76 }
77
78 fn flush(&mut self) -> io::Result<()> {
79 let (stream, mut cx) = self.parts();
80 match stream.poll_flush(&mut cx) {
81 Poll::Ready(r) => r,
82 Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)),
83 }
84 }
85}
86
87fn cvt<T>(r: io::Result<T>) -> Poll<io::Result<T>> {
88 match r {
89 Ok(v) => Poll::Ready(Ok(v)),
90 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
91 Err(e) => Poll::Ready(Err(e)),
92 }
93}
94
95fn cvt_ossl<T>(r: Result<T, ssl::Error>) -> Poll<Result<T, ssl::Error>> {
96 match r {
97 Ok(v) => Poll::Ready(Ok(v)),
98 Err(e) => match e.code() {
99 ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Poll::Pending,
100 _ => Poll::Ready(Err(e)),
101 },
102 }
103}
104
105pub struct SslStream<S: Unpin> {
107 inner: ssl::SslStream<StreamWrapper<S>>,
108 close_notify_sent: bool,
112}
113
114impl<S> fmt::Debug for SslStream<S>
115where
116 S: fmt::Debug + Unpin,
117{
118 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
119 fmt.debug_tuple("SslStream").field(&self.inner).finish()
120 }
121}
122
123impl<S> SslStream<S>
124where
125 S: AsyncRead + AsyncWrite + Unpin,
126{
127 pub fn new(ssl: Ssl, stream: S) -> Result<Self, ErrorStack> {
129 ssl::SslStream::new(
130 ssl,
131 StreamWrapper {
132 stream,
133 waker: None,
134 },
135 )
136 .map(|inner| SslStream {
137 inner,
138 close_notify_sent: false,
139 })
140 }
141
142 pub fn poll_connect(
144 self: Pin<&mut Self>,
145 cx: &mut Context<'_>,
146 ) -> Poll<Result<(), ssl::Error>> {
147 self.with_context(cx, |s| cvt_ossl(s.connect()))
148 }
149
150 pub async fn connect(mut self: Pin<&mut Self>) -> Result<(), ssl::Error> {
152 future::poll_fn(|cx| self.as_mut().poll_connect(cx)).await
153 }
154
155 pub fn poll_accept(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), ssl::Error>> {
157 self.with_context(cx, |s| cvt_ossl(s.accept()))
158 }
159
160 pub async fn accept(mut self: Pin<&mut Self>) -> Result<(), ssl::Error> {
162 future::poll_fn(|cx| self.as_mut().poll_accept(cx)).await
163 }
164
165 pub fn poll_do_handshake(
167 self: Pin<&mut Self>,
168 cx: &mut Context<'_>,
169 ) -> Poll<Result<(), ssl::Error>> {
170 self.with_context(cx, |s| cvt_ossl(s.do_handshake()))
171 }
172
173 pub async fn do_handshake(mut self: Pin<&mut Self>) -> Result<(), ssl::Error> {
175 future::poll_fn(|cx| self.as_mut().poll_do_handshake(cx)).await
176 }
177
178 pub fn poll_peek(
180 self: Pin<&mut Self>,
181 cx: &mut Context<'_>,
182 buf: &mut [u8],
183 ) -> Poll<Result<usize, ssl::Error>> {
184 if buf.is_empty() {
188 return Poll::Ready(Ok(0));
189 }
190 self.with_context(cx, |s| cvt_ossl(s.ssl_peek(buf)))
191 }
192
193 pub async fn peek(mut self: Pin<&mut Self>, buf: &mut [u8]) -> Result<usize, ssl::Error> {
195 future::poll_fn(|cx| self.as_mut().poll_peek(cx, buf)).await
196 }
197
198 #[cfg(ossl111)]
200 pub fn poll_read_early_data(
201 self: Pin<&mut Self>,
202 cx: &mut Context<'_>,
203 buf: &mut [u8],
204 ) -> Poll<Result<usize, ssl::Error>> {
205 self.with_context(cx, |s| cvt_ossl(s.read_early_data(buf)))
206 }
207
208 #[cfg(ossl111)]
210 pub async fn read_early_data(
211 mut self: Pin<&mut Self>,
212 buf: &mut [u8],
213 ) -> Result<usize, ssl::Error> {
214 future::poll_fn(|cx| self.as_mut().poll_read_early_data(cx, buf)).await
215 }
216
217 #[cfg(ossl111)]
219 pub fn poll_write_early_data(
220 self: Pin<&mut Self>,
221 cx: &mut Context<'_>,
222 buf: &[u8],
223 ) -> Poll<Result<usize, ssl::Error>> {
224 self.with_context(cx, |s| cvt_ossl(s.write_early_data(buf)))
225 }
226
227 #[cfg(ossl111)]
229 pub async fn write_early_data(
230 mut self: Pin<&mut Self>,
231 buf: &[u8],
232 ) -> Result<usize, ssl::Error> {
233 future::poll_fn(|cx| self.as_mut().poll_write_early_data(cx, buf)).await
234 }
235}
236
237impl<S: Unpin> SslStream<S> {
238 #[must_use]
240 pub fn ssl(&self) -> &SslRef {
241 self.inner.ssl()
242 }
243
244 #[must_use]
246 pub fn get_ref(&self) -> &S {
247 &self.inner.get_ref().stream
248 }
249
250 pub fn get_mut(&mut self) -> &mut S {
256 &mut self.inner.get_mut().stream
257 }
258
259 #[must_use]
265 pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut S> {
266 Pin::new(&mut self.get_mut().inner.get_mut().stream)
267 }
268
269 fn with_context<F, R>(self: Pin<&mut Self>, ctx: &mut Context<'_>, f: F) -> R
270 where
271 F: FnOnce(&mut ssl::SslStream<StreamWrapper<S>>) -> R,
272 {
273 let this = self.get_mut();
274 match &mut this.inner.get_mut().waker {
275 Some(waker) => waker.clone_from(ctx.waker()),
278 waker @ None => *waker = Some(ctx.waker().clone()),
279 }
280 f(&mut this.inner)
281 }
282}
283
284impl<S> AsyncRead for SslStream<S>
285where
286 S: AsyncRead + AsyncWrite + Unpin,
287{
288 fn poll_read(
289 self: Pin<&mut Self>,
290 ctx: &mut Context<'_>,
291 buf: &mut [u8],
292 ) -> Poll<io::Result<usize>> {
293 self.with_context(ctx, |s| cvt(s.read(buf)))
294 }
295}
296
297impl<S> AsyncWrite for SslStream<S>
298where
299 S: AsyncRead + AsyncWrite + Unpin,
300{
301 fn poll_write(self: Pin<&mut Self>, ctx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
302 self.with_context(ctx, |s| cvt(s.write(buf)))
303 }
304
305 fn poll_flush(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<io::Result<()>> {
306 self.with_context(ctx, |s| cvt(s.flush()))
307 }
308
309 fn poll_close(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<io::Result<()>> {
310 if !self.close_notify_sent {
320 match self.as_mut().with_context(ctx, |s| s.shutdown()) {
321 Ok(ShutdownResult::Sent | ShutdownResult::Received) => {}
322 Err(ref e) if e.code() == ErrorCode::ZERO_RETURN => {}
323 Err(ref e)
324 if e.code() == ErrorCode::WANT_READ || e.code() == ErrorCode::WANT_WRITE =>
325 {
326 return Poll::Pending;
327 }
328 Err(e) => {
329 return Poll::Ready(Err(e.into_io_error().unwrap_or_else(io::Error::other)));
330 }
331 }
332 self.as_mut().get_mut().close_notify_sent = true;
333 }
334
335 self.get_pin_mut().poll_close(ctx)
336 }
337}