You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.0 KiB
149 lines
4.0 KiB
#[cfg(unix)]
|
|
use std::os::unix::io::{AsRawFd, RawFd};
|
|
#[cfg(windows)]
|
|
use std::os::windows::io::{AsRawSocket, RawSocket};
|
|
|
|
use super::*;
|
|
use crate::common::IoSession;
|
|
|
|
/// A wrapper around an underlying raw stream which implements the TLS or SSL
|
|
/// protocol.
|
|
#[derive(Debug)]
|
|
pub struct TlsStream<IO> {
|
|
pub(crate) io: IO,
|
|
pub(crate) session: ServerConnection,
|
|
pub(crate) state: TlsState,
|
|
}
|
|
|
|
impl<IO> TlsStream<IO> {
|
|
#[inline]
|
|
pub fn get_ref(&self) -> (&IO, &ServerConnection) {
|
|
(&self.io, &self.session)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn get_mut(&mut self) -> (&mut IO, &mut ServerConnection) {
|
|
(&mut self.io, &mut self.session)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn into_inner(self) -> (IO, ServerConnection) {
|
|
(self.io, self.session)
|
|
}
|
|
}
|
|
|
|
impl<IO> IoSession for TlsStream<IO> {
|
|
type Io = IO;
|
|
type Session = ServerConnection;
|
|
|
|
#[inline]
|
|
fn skip_handshake(&self) -> bool {
|
|
false
|
|
}
|
|
|
|
#[inline]
|
|
fn get_mut(&mut self) -> (&mut TlsState, &mut Self::Io, &mut Self::Session) {
|
|
(&mut self.state, &mut self.io, &mut self.session)
|
|
}
|
|
|
|
#[inline]
|
|
fn into_io(self) -> Self::Io {
|
|
self.io
|
|
}
|
|
}
|
|
|
|
impl<IO> AsyncRead for TlsStream<IO>
|
|
where
|
|
IO: AsyncRead + AsyncWrite + Unpin,
|
|
{
|
|
fn poll_read(
|
|
self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>,
|
|
buf: &mut ReadBuf<'_>,
|
|
) -> Poll<io::Result<()>> {
|
|
let this = self.get_mut();
|
|
let mut stream =
|
|
Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable());
|
|
|
|
match &this.state {
|
|
TlsState::Stream | TlsState::WriteShutdown => {
|
|
let prev = buf.remaining();
|
|
|
|
match stream.as_mut_pin().poll_read(cx, buf) {
|
|
Poll::Ready(Ok(())) => {
|
|
if prev == buf.remaining() || stream.eof {
|
|
this.state.shutdown_read();
|
|
}
|
|
|
|
Poll::Ready(Ok(()))
|
|
}
|
|
Poll::Ready(Err(err)) if err.kind() == io::ErrorKind::UnexpectedEof => {
|
|
this.state.shutdown_read();
|
|
Poll::Ready(Err(err))
|
|
}
|
|
output => output,
|
|
}
|
|
}
|
|
TlsState::ReadShutdown | TlsState::FullyShutdown => Poll::Ready(Ok(())),
|
|
#[cfg(feature = "early-data")]
|
|
s => unreachable!("server TLS can not hit this state: {:?}", s),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<IO> AsyncWrite for TlsStream<IO>
|
|
where
|
|
IO: AsyncRead + AsyncWrite + Unpin,
|
|
{
|
|
/// Note: that it does not guarantee the final data to be sent.
|
|
/// To be cautious, you must manually call `flush`.
|
|
fn poll_write(
|
|
self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>,
|
|
buf: &[u8],
|
|
) -> Poll<io::Result<usize>> {
|
|
let this = self.get_mut();
|
|
let mut stream =
|
|
Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable());
|
|
stream.as_mut_pin().poll_write(cx, buf)
|
|
}
|
|
|
|
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
|
let this = self.get_mut();
|
|
let mut stream =
|
|
Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable());
|
|
stream.as_mut_pin().poll_flush(cx)
|
|
}
|
|
|
|
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
|
if self.state.writeable() {
|
|
self.session.send_close_notify();
|
|
self.state.shutdown_write();
|
|
}
|
|
|
|
let this = self.get_mut();
|
|
let mut stream =
|
|
Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable());
|
|
stream.as_mut_pin().poll_shutdown(cx)
|
|
}
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
impl<IO> AsRawFd for TlsStream<IO>
|
|
where
|
|
IO: AsRawFd,
|
|
{
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
self.get_ref().0.as_raw_fd()
|
|
}
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
impl<IO> AsRawSocket for TlsStream<IO>
|
|
where
|
|
IO: AsRawSocket,
|
|
{
|
|
fn as_raw_socket(&self) -> RawSocket {
|
|
self.get_ref().0.as_raw_socket()
|
|
}
|
|
}
|
|
|