use std::ffi::c_int;
use bytes::Bytes;
use thiserror::Error;
use wolfssl_sys::wolfCrypt_ErrorCodes_ASN_NO_SIGNER_E as WOLFSSL_ERROR_ASN_NO_SIGNER;
use wolfssl_sys::wolfSSL_ErrorCodes_DOMAIN_NAME_MISMATCH as WOLFSSL_ERROR_DOMAIN_NAME_MISMATCH;
use wolfssl_sys::wolfSSL_ErrorCodes_DUPLICATE_MSG_E as WOLFSSL_ERROR_DUPLICATE_MSG_E;
use wolfssl_sys::wolfSSL_ErrorCodes_ZERO_RETURN as WOLFSSL_ERROR_ZERO_RETURN_ALT;
use wolfssl_sys::WOLFSSL_ERROR_ZERO_RETURN_c_int as WOLFSSL_ERROR_ZERO_RETURN;
#[derive(Debug)]
pub enum Poll<T> {
PendingWrite,
PendingRead,
Ready(T),
AppData(Bytes),
}
#[derive(Clone, Error, Debug)]
pub enum Error {
#[error("App Data: {0}")]
AppData(ErrorKind),
#[error("Fatal: {0}")]
Fatal(ErrorKind),
}
impl Error {
pub(crate) fn fatal(code: c_int) -> Self {
Self::Fatal(ErrorKind::from(code))
}
pub fn kind(&self) -> ErrorKind {
match self {
Error::AppData(e) => e,
Error::Fatal(e) => e,
}
.clone()
}
}
#[derive(Clone, Debug, Error)]
pub enum ErrorKind {
#[error("CA cert not available to verify certificate")]
CaCertNotAvailable,
#[error("Domain name mismatch")]
DomainNameMismatch,
#[error("Duplicate message error")]
DuplicateMessage,
#[error("Peer sent close notify alert")]
PeerClosed,
#[error("code: {code}, what: {what}")]
Other {
what: String,
code: c_int,
},
}
impl std::convert::From<c_int> for ErrorKind {
fn from(code: c_int) -> Self {
let this = match code {
WOLFSSL_ERROR_ASN_NO_SIGNER => Self::CaCertNotAvailable,
WOLFSSL_ERROR_DOMAIN_NAME_MISMATCH => Self::DomainNameMismatch,
WOLFSSL_ERROR_DUPLICATE_MSG_E => Self::DuplicateMessage,
WOLFSSL_ERROR_ZERO_RETURN => Self::PeerClosed,
WOLFSSL_ERROR_ZERO_RETURN_ALT => Self::PeerClosed,
_other => Self::Other {
what: wolf_error_string(code as std::ffi::c_ulong),
code,
},
};
debug_assert!(
!matches!(
this,
Self::Other {
code: wolfssl_sys::WOLFSSL_ERROR_WANT_READ_c_int
| wolfssl_sys::WOLFSSL_ERROR_WANT_WRITE_c_int
| wolfssl_sys::WOLFSSL_SUCCESS_c_int,
..
}
),
"Attempting to construct a `ErrorKind` from a non-error code {code}",
);
this
}
}
pub type PollResult<T> = std::result::Result<Poll<T>, Error>;
pub type Result<T> = std::result::Result<T, Error>;
fn wolf_error_string(raw_err: std::ffi::c_ulong) -> String {
let mut buffer = vec![0u8; wolfssl_sys::WOLFSSL_MAX_ERROR_SZ as usize];
unsafe {
wolfssl_sys::wolfSSL_ERR_error_string(
raw_err,
buffer.as_mut_slice().as_mut_ptr() as *mut std::os::raw::c_char,
);
}
String::from_utf8_lossy(&buffer)
.trim_end_matches(char::from(0))
.to_string()
}
#[cfg(test)]
mod wolf_error {
use super::*;
#[test]
fn wolf_error_string_check_string() {
let s = wolf_error_string(wolfssl_sys::WOLFSSL_ERROR_WANT_READ as std::ffi::c_ulong);
assert_eq!(s, "non-blocking socket wants data to be read");
}
}