use std::io;
mod key_log_file;
pub use key_log_file::KeyLogFile;
use rustls::{Connection, VecInput};
mod stream;
pub use crate::stream::{Stream, StreamOwned};
pub fn complete_io(
io: &mut (impl io::Read + io::Write),
input: &mut VecInput,
conn: &mut dyn Connection,
) -> Result<(usize, usize), io::Error> {
let mut eof = false;
let mut wrlen = 0;
let mut rdlen = 0;
loop {
let (mut blocked_write, mut blocked_read) = (None, None);
let until_handshaked = conn.is_handshaking();
if !conn.wants_write() && !conn.wants_read() {
return Ok((rdlen, wrlen));
}
while conn.wants_write() {
match conn.write_tls(io) {
Ok(0) => {
io.flush()?;
return Ok((rdlen, wrlen)); }
Ok(n) => wrlen += n,
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
blocked_write = Some(err);
break;
}
Err(err) => return Err(err),
}
}
if wrlen > 0 {
io.flush()?;
}
if !until_handshaked && wrlen > 0 {
return Ok((rdlen, wrlen));
}
if let (Some(_), false) = (&blocked_write, conn.wants_read()) {
return match wrlen {
0 => Err(blocked_write.unwrap()),
_ => Ok((rdlen, wrlen)),
};
}
while !eof && conn.wants_read() {
let read_size = match input.read(io) {
Ok(0) => {
eof = true;
Some(0)
}
Ok(n) => {
rdlen += n;
Some(n)
}
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
blocked_read = Some(err);
break;
}
Err(err) if err.kind() == io::ErrorKind::Interrupted => None, Err(err) => return Err(err),
};
if read_size.is_some() {
break;
}
}
if let Err(e) = conn.process_new_packets(input) {
let _ignored = conn.write_tls(io);
let _ignored = io.flush();
return Err(io::Error::new(io::ErrorKind::InvalidData, e));
};
if let (Some(_), false) = (&blocked_read, conn.wants_write()) {
return match rdlen {
0 => Err(blocked_read.unwrap()),
_ => Ok((rdlen, wrlen)),
};
}
if until_handshaked && !conn.is_handshaking() && conn.wants_write() {
continue;
}
let blocked = blocked_write.zip(blocked_read);
match (eof, until_handshaked, conn.is_handshaking(), blocked) {
(_, true, false, _) => return Ok((rdlen, wrlen)),
(_, _, _, Some((e, _))) if rdlen == 0 && wrlen == 0 => return Err(e),
(_, false, _, _) => return Ok((rdlen, wrlen)),
(true, true, true, _) => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)),
_ => {}
}
}
}