use std::io;
use crate::error::Result;
use crate::io::runtime::AsyncConn;
use crate::proto::tls::TlsEngine;
use crate::tls::ClientEngine;
fn to_io(e: crate::error::Error) -> io::Error {
io::Error::other(e.to_string())
}
pub(crate) struct AsyncTlsStream<C> {
conn: C,
engine: ClientEngine,
inbuf: Vec<u8>,
}
impl<C: AsyncConn> AsyncTlsStream<C> {
pub(crate) async fn connect(
mut conn: C,
sni: &str,
opts: &mut crate::tls::TlsOpts,
) -> Result<AsyncTlsStream<C>> {
let mut engine = crate::tls::build_client_engine(sni, opts)?;
let mut inbuf = vec![0u8; 16 * 1024];
loop {
let mut out = Vec::new();
engine.drain_outgoing(&mut out);
if !out.is_empty() {
conn.write_all(&out).await?;
conn.flush().await?;
}
if !engine.is_handshaking() {
break;
}
let n = conn.read(&mut inbuf).await?;
if n == 0 {
return Err(crate::error::Error::UnexpectedEof);
}
engine.feed_incoming(&inbuf[..n])?;
}
Ok(AsyncTlsStream {
conn,
engine,
inbuf,
})
}
}
impl<C: AsyncConn> AsyncConn for AsyncTlsStream<C> {
async fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
loop {
let n = self.engine.read_plaintext(dst).map_err(to_io)?;
if n > 0 {
return Ok(n);
}
let m = self.conn.read(&mut self.inbuf).await?;
if m == 0 {
return Ok(0); }
let chunk = self.inbuf[..m].to_vec();
self.engine.feed_incoming(&chunk).map_err(to_io)?;
let mut out = Vec::new();
self.engine.drain_outgoing(&mut out);
if !out.is_empty() {
self.conn.write_all(&out).await?;
self.conn.flush().await?;
}
}
}
async fn write_all(&mut self, src: &[u8]) -> io::Result<()> {
self.engine.write_plaintext(src);
let mut out = Vec::new();
self.engine.drain_outgoing(&mut out);
if !out.is_empty() {
self.conn.write_all(&out).await?;
}
Ok(())
}
async fn flush(&mut self) -> io::Result<()> {
let mut out = Vec::new();
self.engine.drain_outgoing(&mut out);
if !out.is_empty() {
self.conn.write_all(&out).await?;
}
self.conn.flush().await
}
}