use crate::{
RuntimeError,
futures::tls::{config::tls_error, fd_io::FdIo},
};
use std::io;
pub(crate) fn handshake(
tls: &mut rustls::Connection,
fd: libc::c_int,
) -> Result<Option<i16>, RuntimeError> {
loop {
if let Some(filter) = send_pending(tls, fd)? {
return Ok(Some(filter));
}
if !tls.is_handshaking() {
return Ok(None);
}
match tls.read_tls(&mut FdIo(fd)) {
Ok(0) => return Err(RuntimeError::Closed),
Ok(_) => process(tls, fd)?,
Err(error) if error.kind() == io::ErrorKind::WouldBlock => {
return Ok(Some(libc::EVFILT_READ));
}
Err(error) if error.kind() == io::ErrorKind::Interrupted => {}
Err(error) => return Err(io_error(error)),
}
}
}
pub(crate) fn send_pending(
tls: &mut rustls::Connection,
fd: libc::c_int,
) -> Result<Option<i16>, RuntimeError> {
while tls.wants_write() {
match tls.write_tls(&mut FdIo(fd)) {
Ok(_) => {}
Err(error) if error.kind() == io::ErrorKind::WouldBlock => {
return Ok(Some(libc::EVFILT_WRITE));
}
Err(error) if error.kind() == io::ErrorKind::Interrupted => {}
Err(error) => return Err(io_error(error)),
}
}
Ok(None)
}
pub(crate) fn process(tls: &mut rustls::Connection, fd: libc::c_int) -> Result<(), RuntimeError> {
if let Err(error) = tls.process_new_packets() {
let _ = send_pending(tls, fd);
return Err(tls_error(error));
}
Ok(())
}
#[inline(always)]
pub(crate) fn io_error(error: io::Error) -> RuntimeError {
RuntimeError::CheckError(error.raw_os_error())
}