use std::io;
#[non_exhaustive]
#[derive(Debug)]
pub enum IOCallbackResult<T> {
Ok(T),
WouldBlock,
Err(io::Error),
}
impl From<io::Result<usize>> for IOCallbackResult<usize> {
fn from(result: io::Result<usize>) -> Self {
match result {
Ok(n) => IOCallbackResult::Ok(n),
Err(e) if e.kind() == io::ErrorKind::WouldBlock => IOCallbackResult::WouldBlock,
Err(e) => IOCallbackResult::Err(e),
}
}
}
pub trait IOCallbacks {
fn recv(&mut self, buf: &mut [u8]) -> IOCallbackResult<usize>;
fn send(&mut self, buf: &[u8]) -> IOCallbackResult<usize>;
}
impl<T: io::Read + io::Write> IOCallbacks for T {
fn recv(&mut self, buf: &mut [u8]) -> IOCallbackResult<usize> {
self.read(buf).into()
}
fn send(&mut self, buf: &[u8]) -> IOCallbackResult<usize> {
self.write(buf).into()
}
}
pub(crate) unsafe extern "C" fn io_recv_shim<IOCB: IOCallbacks>(
_ssl: *mut wolfcrypt_sys::WOLFSSL,
buf: *mut core::ffi::c_char,
sz: core::ffi::c_int,
ctx: *mut core::ffi::c_void,
) -> core::ffi::c_int {
use wolfcrypt_sys::IOerrors_WOLFSSL_CBIO_ERR_WANT_READ;
debug_assert!(!ctx.is_null());
debug_assert!(sz > 0, "wolfSSL passed non-positive sz to recv shim: {sz}");
let io = unsafe { &mut *(ctx as *mut IOCB) };
let buf = unsafe { std::slice::from_raw_parts_mut(buf as *mut u8, sz as usize) };
match io.recv(buf) {
IOCallbackResult::Ok(n) => n as core::ffi::c_int,
IOCallbackResult::WouldBlock => IOerrors_WOLFSSL_CBIO_ERR_WANT_READ,
IOCallbackResult::Err(e) => errorkind_to_cbio(e.kind(), IOerrors_WOLFSSL_CBIO_ERR_WANT_READ),
}
}
pub(crate) unsafe extern "C" fn io_send_shim<IOCB: IOCallbacks>(
_ssl: *mut wolfcrypt_sys::WOLFSSL,
buf: *mut core::ffi::c_char,
sz: core::ffi::c_int,
ctx: *mut core::ffi::c_void,
) -> core::ffi::c_int {
use wolfcrypt_sys::{IOerrors_WOLFSSL_CBIO_ERR_WANT_WRITE};
debug_assert!(!ctx.is_null());
debug_assert!(sz > 0, "wolfSSL passed non-positive sz to send shim: {sz}");
let io = unsafe { &mut *(ctx as *mut IOCB) };
let buf = unsafe { std::slice::from_raw_parts(buf as *const u8, sz as usize) };
match io.send(buf) {
IOCallbackResult::Ok(n) => n as core::ffi::c_int,
IOCallbackResult::WouldBlock => IOerrors_WOLFSSL_CBIO_ERR_WANT_WRITE,
IOCallbackResult::Err(e) => errorkind_to_cbio(e.kind(), IOerrors_WOLFSSL_CBIO_ERR_WANT_WRITE),
}
}
pub(crate) fn errorkind_to_cbio(
kind: io::ErrorKind,
would_block_code: core::ffi::c_int,
) -> core::ffi::c_int {
use io::ErrorKind::*;
use wolfcrypt_sys::{
IOerrors_WOLFSSL_CBIO_ERR_CONN_CLOSE, IOerrors_WOLFSSL_CBIO_ERR_CONN_RST,
IOerrors_WOLFSSL_CBIO_ERR_GENERAL, IOerrors_WOLFSSL_CBIO_ERR_ISR,
IOerrors_WOLFSSL_CBIO_ERR_TIMEOUT,
};
match kind {
WouldBlock => would_block_code,
TimedOut => IOerrors_WOLFSSL_CBIO_ERR_TIMEOUT,
ConnectionReset => IOerrors_WOLFSSL_CBIO_ERR_CONN_RST,
Interrupted => IOerrors_WOLFSSL_CBIO_ERR_ISR,
ConnectionAborted => IOerrors_WOLFSSL_CBIO_ERR_CONN_CLOSE,
_ => IOerrors_WOLFSSL_CBIO_ERR_GENERAL,
}
}