#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/tokio-tls/0.2.1")]
extern crate futures;
extern crate native_tls;
#[macro_use]
extern crate tokio_io;
use std::io::{self, Read, Write};
use futures::{Poll, Future, Async};
use native_tls::{HandshakeError, Error};
use tokio_io::{AsyncRead, AsyncWrite};
#[derive(Debug)]
pub struct TlsStream<S> {
inner: native_tls::TlsStream<S>,
}
#[derive(Clone)]
pub struct TlsConnector {
inner: native_tls::TlsConnector,
}
#[derive(Clone)]
pub struct TlsAcceptor {
inner: native_tls::TlsAcceptor,
}
pub struct Connect<S> {
inner: MidHandshake<S>,
}
pub struct Accept<S> {
inner: MidHandshake<S>,
}
struct MidHandshake<S> {
inner: Option<Result<native_tls::TlsStream<S>, HandshakeError<S>>>,
}
impl<S> TlsStream<S> {
pub fn get_ref(&self) -> &native_tls::TlsStream<S> {
&self.inner
}
pub fn get_mut(&mut self) -> &mut native_tls::TlsStream<S> {
&mut self.inner
}
}
impl<S: Read + Write> Read for TlsStream<S> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}
impl<S: Read + Write> Write for TlsStream<S> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl<S: AsyncRead + AsyncWrite> AsyncRead for TlsStream<S> {
}
impl<S: AsyncRead + AsyncWrite> AsyncWrite for TlsStream<S> {
fn shutdown(&mut self) -> Poll<(), io::Error> {
try_nb!(self.inner.shutdown());
self.inner.get_mut().shutdown()
}
}
impl TlsConnector {
pub fn connect<S>(&self, domain: &str, stream: S) -> Connect<S>
where S: AsyncRead + AsyncWrite,
{
Connect {
inner: MidHandshake {
inner: Some(self.inner.connect(domain, stream)),
},
}
}
}
impl From<native_tls::TlsConnector> for TlsConnector {
fn from(inner: native_tls::TlsConnector) -> TlsConnector {
TlsConnector {
inner,
}
}
}
impl TlsAcceptor {
pub fn accept<S>(&self, stream: S) -> Accept<S>
where S: AsyncRead + AsyncWrite,
{
Accept {
inner: MidHandshake {
inner: Some(self.inner.accept(stream)),
},
}
}
}
impl From<native_tls::TlsAcceptor> for TlsAcceptor {
fn from(inner: native_tls::TlsAcceptor) -> TlsAcceptor {
TlsAcceptor {
inner,
}
}
}
impl<S: AsyncRead + AsyncWrite> Future for Connect<S> {
type Item = TlsStream<S>;
type Error = Error;
fn poll(&mut self) -> Poll<TlsStream<S>, Error> {
self.inner.poll()
}
}
impl<S: AsyncRead + AsyncWrite> Future for Accept<S> {
type Item = TlsStream<S>;
type Error = Error;
fn poll(&mut self) -> Poll<TlsStream<S>, Error> {
self.inner.poll()
}
}
impl<S: AsyncRead + AsyncWrite> Future for MidHandshake<S> {
type Item = TlsStream<S>;
type Error = Error;
fn poll(&mut self) -> Poll<TlsStream<S>, Error> {
match self.inner.take().expect("cannot poll MidHandshake twice") {
Ok(stream) => Ok(TlsStream { inner: stream }.into()),
Err(HandshakeError::Failure(e)) => Err(e),
Err(HandshakeError::WouldBlock(s)) => {
match s.handshake() {
Ok(stream) => Ok(TlsStream { inner: stream }.into()),
Err(HandshakeError::Failure(e)) => Err(e),
Err(HandshakeError::WouldBlock(s)) => {
self.inner = Some(Err(HandshakeError::WouldBlock(s)));
Ok(Async::NotReady)
}
}
}
}
}
}