From ba795e02abc95ec250cf89937f398207d1d78ae2 Mon Sep 17 00:00:00 2001 From: youyuanwu <48816116+youyuanwu@users.noreply.github.com> Date: Mon, 13 Jan 2025 17:12:36 -0800 Subject: [PATCH] Implement Error and ErrorCode for Rust (#4743) --- src/error.rs | 210 +++++++++++++++++++++++++++++++++++ src/lib.rs | 307 +++++++++------------------------------------------ 2 files changed, 264 insertions(+), 253 deletions(-) create mode 100644 src/error.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000000..651b16702a --- /dev/null +++ b/src/error.rs @@ -0,0 +1,210 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use crate::ffi::QUIC_ERROR; + +/// Defines quic error code enum and its conversion +/// to raw type using macro. +macro_rules! define_quic_error_code{ + ($( $code1:ident ),*) =>{ + /// Enum of quic status codes. + #[allow(non_camel_case_types)] + #[derive(Debug, Clone, PartialEq)] + #[repr(u32)] + pub enum ErrorCode { + $( + $code1 = crate::ffi::$code1 as u32, + )* + } + + /// Convert from ffi type to enum. + /// Conversion failes when the status value is not a quic status. + impl std::convert::TryFrom for ErrorCode { + type Error = &'static str; + fn try_from(value: crate::ffi::QUIC_ERROR) -> Result { + match value { + $( + crate::ffi::$code1 => Ok(Self::$code1), + )* + _ => Err("Unknown QUIC_ERROR") + } + } + } + } +} + +// defines all quic error codes. +define_quic_error_code!( + QUIC_ERROR_SUCCESS, + QUIC_ERROR_PENDING, + QUIC_ERROR_CONTINUE, + QUIC_ERROR_OUT_OF_MEMORY, + QUIC_ERROR_INVALID_PARAMETER, + QUIC_ERROR_INVALID_STATE, + QUIC_ERROR_NOT_SUPPORTED, + QUIC_ERROR_NOT_FOUND, + QUIC_ERROR_BUFFER_TOO_SMALL, + QUIC_ERROR_HANDSHAKE_FAILURE, + QUIC_ERROR_ABORTED, + QUIC_ERROR_ADDRESS_IN_USE, + QUIC_ERROR_INVALID_ADDRESS, + QUIC_ERROR_CONNECTION_TIMEOUT, + QUIC_ERROR_CONNECTION_IDLE, + QUIC_ERROR_UNREACHABLE, + QUIC_ERROR_INTERNAL_ERROR, + QUIC_ERROR_CONNECTION_REFUSED, + QUIC_ERROR_PROTOCOL_ERROR, + QUIC_ERROR_VER_NEG_ERROR, + QUIC_ERROR_TLS_ERROR, + QUIC_ERROR_USER_CANCELED, + QUIC_ERROR_ALPN_NEG_FAILURE, + QUIC_ERROR_STREAM_LIMIT_REACHED, + QUIC_ERROR_ALPN_IN_USE, + QUIC_ERROR_CLOSE_NOTIFY, + QUIC_ERROR_BAD_CERTIFICATE, + QUIC_ERROR_UNSUPPORTED_CERTIFICATE, + QUIC_ERROR_REVOKED_CERTIFICATE, + QUIC_ERROR_EXPIRED_CERTIFICATE, + QUIC_ERROR_UNKNOWN_CERTIFICATE, + QUIC_ERROR_REQUIRED_CERTIFICATE, + QUIC_ERROR_CERT_EXPIRED, + QUIC_ERROR_CERT_UNTRUSTED_ROOT, + QUIC_ERROR_CERT_NO_CERT +); + +impl From for QUIC_ERROR { + fn from(value: ErrorCode) -> Self { + value as QUIC_ERROR + } +} + +/// The display string is the same as the debug string, i.e. the enum string. +impl core::fmt::Display for ErrorCode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + core::write!(f, "{:?}", self) + } +} + +/// Quic error used in non-ffi code. +/// Internal representation matches the os platfrom type. +#[derive(Clone)] +pub struct Error(pub QUIC_ERROR); + +impl Error { + /// Create an error from enum. + pub fn new(ec: ErrorCode) -> Self { + Self(ec as QUIC_ERROR) + } + /// Convert to error code if possible. + pub fn try_as_error_code(&self) -> Result { + use std::convert::TryFrom; + ErrorCode::try_from(self.0 as QUIC_ERROR) + } + + /// Convert from raw ffi error type. + pub fn from_raw(ec: QUIC_ERROR) -> Self { + Self(ec) + } + + /// Temp api to use in manually written ffi code which is going to be + /// removed and replaced by auto generated ffi code. + /// This api will be replaced by from_raw. + pub fn from_u32(ec: u32) -> Self { + Self(ec as QUIC_ERROR) + } + + /// Return Err if the error is considered a failure. + /// Ok includes both "no error" and "pending" status codes. + pub fn ok(self) -> Result<(), Self> { + // on windows it is signed. + #[cfg(target_os = "windows")] + if self.0 < 0 { + Err(self) + } else { + Ok(()) + } + + #[cfg(not(target_os = "windows"))] + if (self.0 as i32) > 0 { + Err(self) + } else { + Ok(()) + } + } +} + +impl std::error::Error for Error {} + +impl From for Error { + fn from(value: QUIC_ERROR) -> Self { + Self(value) + } +} + +impl From for Error { + fn from(value: ErrorCode) -> Self { + Self::new(value) + } +} + +/// The debug message is in the same format as error in windows crate. +impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut debug = fmt.debug_struct("Error"); + let str_code = match self.try_as_error_code() { + Ok(c) => Some(c), + Err(_) => None, + }; + debug.field("code", &format_args!("0x{:x}", self.0)); + match str_code { + Some(c) => debug.field("message", &c), + None => debug.field("message", &"unknown quic error"), + }; + debug.finish() + } +} + +/// The display message is in the same format as error in windows crate. +impl core::fmt::Display for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let str_code = match self.try_as_error_code() { + Ok(c) => Some(c), + Err(_) => None, + }; + match str_code { + Some(c) => core::write!(fmt, "{} (0x{:x})", c, self.0), + None => core::write!(fmt, "0x{:x}", self.0), + } + } +} + +#[cfg(test)] +mod tests { + use crate::ffi::QUIC_ERROR; + + use super::{Error, ErrorCode}; + + #[test] + fn error_fmt_test() { + let err = Error::new(ErrorCode::QUIC_ERROR_ABORTED); + // message is platform dependent. + #[cfg(target_os = "windows")] + assert_eq!(format!("{err}"), "QUIC_ERROR_ABORTED (0x80004004)"); + #[cfg(target_os = "windows")] + assert_eq!( + format!("{err:?}"), + "Error { code: 0x80004004, message: QUIC_ERROR_ABORTED }" + ); + let ec = err.try_as_error_code().unwrap(); + assert_eq!(format!("{ec}"), "QUIC_ERROR_ABORTED"); + } + + #[test] + fn error_ok_test() { + assert!(Error::new(ErrorCode::QUIC_ERROR_ABORTED).ok().is_err()); + assert!(Error::new(ErrorCode::QUIC_ERROR_SUCCESS).ok().is_ok()); + assert!(Error::from_raw(ErrorCode::QUIC_ERROR_PENDING as QUIC_ERROR) + .ok() + .is_ok()); + } +} diff --git a/src/lib.rs b/src/lib.rs index 2d1eb2e281..0839b6319b 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,9 @@ use std::result::Result; use std::sync::Once; #[macro_use] extern crate bitfield; +mod error; pub mod ffi; +pub use error::{Error, ErrorCode}; // // The following starts the C interop layer of MsQuic API. @@ -117,153 +119,6 @@ impl From for Addr { } } -#[cfg(target_os = "windows")] -mod status { - pub const QUIC_STATUS_SUCCESS: u32 = 0x0; - pub const QUIC_STATUS_PENDING: u32 = 0x703e5; - pub const QUIC_STATUS_CONTINUE: u32 = 0x704de; - pub const QUIC_STATUS_OUT_OF_MEMORY: u32 = 0x8007000e; - pub const QUIC_STATUS_INVALID_PARAMETER: u32 = 0x80070057; - pub const QUIC_STATUS_INVALID_STATE: u32 = 0x8007139f; - pub const QUIC_STATUS_NOT_SUPPORTED: u32 = 0x80004002; - pub const QUIC_STATUS_NOT_FOUND: u32 = 0x80070490; - pub const QUIC_STATUS_BUFFER_TOO_SMALL: u32 = 0x8007007a; - pub const QUIC_STATUS_HANDSHAKE_FAILURE: u32 = 0x80410000; - pub const QUIC_STATUS_ABORTED: u32 = 0x80004004; - pub const QUIC_STATUS_ADDRESS_IN_USE: u32 = 0x80072740; - pub const QUIC_STATUS_INVALID_ADDRESS: u32 = 0x80072741; - pub const QUIC_STATUS_CONNECTION_TIMEOUT: u32 = 0x80410006; - pub const QUIC_STATUS_CONNECTION_IDLE: u32 = 0x80410005; - pub const QUIC_STATUS_UNREACHABLE: u32 = 0x800704d0; - pub const QUIC_STATUS_INTERNAL_ERROR: u32 = 0x80410003; - pub const QUIC_STATUS_CONNECTION_REFUSED: u32 = 0x800704c9; - pub const QUIC_STATUS_PROTOCOL_ERROR: u32 = 0x80410004; - pub const QUIC_STATUS_VER_NEG_ERROR: u32 = 0x80410001; - pub const QUIC_STATUS_TLS_ERROR: u32 = 0x80072b18; - pub const QUIC_STATUS_USER_CANCELED: u32 = 0x80410002; - pub const QUIC_STATUS_ALPN_NEG_FAILURE: u32 = 0x80410007; - pub const QUIC_STATUS_STREAM_LIMIT_REACHED: u32 = 0x80410008; - pub const QUIC_STATUS_ALPN_IN_USE: u32 = 0x80410009; - pub const QUIC_STATUS_CLOSE_NOTIFY: u32 = 0x80410100; - pub const QUIC_STATUS_BAD_CERTIFICATE: u32 = 0x80410100 | 42; - pub const QUIC_STATUS_UNSUPPORTED_CERTIFICATE: u32 = 0x80410100 | 43; - pub const QUIC_STATUS_REVOKED_CERTIFICATE: u32 = 0x80410100 | 44; - pub const QUIC_STATUS_EXPIRED_CERTIFICATE: u32 = 0x80410100 | 45; - pub const QUIC_STATUS_UNKNOWN_CERTIFICATE: u32 = 0x80410100 | 46; - pub const QUIC_STATUS_REQUIRED_CERTIFICATE: u32 = 0x80410100 | 116; - pub const QUIC_STATUS_CERT_EXPIRED: u32 = 0x800B0101; - pub const QUIC_STATUS_CERT_UNTRUSTED_ROOT: u32 = 0x800B0109; - pub const QUIC_STATUS_CERT_NO_CERT: u32 = 0x8009030E; -} - -#[cfg(target_os = "linux")] -mod status { - pub const QUIC_STATUS_SUCCESS: u32 = 0; - pub const QUIC_STATUS_PENDING: u32 = 0xFFFFFFFE; // -2 - pub const QUIC_STATUS_CONTINUE: u32 = 0xFFFFFFFF; // -1 - pub const QUIC_STATUS_OUT_OF_MEMORY: u32 = 12; - pub const QUIC_STATUS_INVALID_PARAMETER: u32 = 22; - pub const QUIC_STATUS_INVALID_STATE: u32 = 1; - pub const QUIC_STATUS_NOT_SUPPORTED: u32 = 95; - pub const QUIC_STATUS_NOT_FOUND: u32 = 2; - pub const QUIC_STATUS_BUFFER_TOO_SMALL: u32 = 75; - pub const QUIC_STATUS_HANDSHAKE_FAILURE: u32 = 103; - pub const QUIC_STATUS_ABORTED: u32 = 125; - pub const QUIC_STATUS_ADDRESS_IN_USE: u32 = 98; - pub const QUIC_STATUS_INVALID_ADDRESS: u32 = 97; - pub const QUIC_STATUS_CONNECTION_TIMEOUT: u32 = 110; - pub const QUIC_STATUS_CONNECTION_IDLE: u32 = 62; - pub const QUIC_STATUS_INTERNAL_ERROR: u32 = 5; - pub const QUIC_STATUS_CONNECTION_REFUSED: u32 = 111; - pub const QUIC_STATUS_PROTOCOL_ERROR: u32 = 71; - pub const QUIC_STATUS_VER_NEG_ERROR: u32 = 93; - pub const QUIC_STATUS_UNREACHABLE: u32 = 113; - pub const QUIC_STATUS_TLS_ERROR: u32 = 126; - pub const QUIC_STATUS_USER_CANCELED: u32 = 130; - pub const QUIC_STATUS_ALPN_NEG_FAILURE: u32 = 92; - pub const QUIC_STATUS_STREAM_LIMIT_REACHED: u32 = 86; - pub const QUIC_STATUS_ALPN_IN_USE: u32 = 91; - pub const QUIC_STATUS_ADDRESS_NOT_AVAILABLE: u32 = 99; - pub const QUIC_STATUS_CLOSE_NOTIFY: u32 = 0xBEBC300; - pub const QUIC_STATUS_BAD_CERTIFICATE: u32 = 0xBEBC32A; - pub const QUIC_STATUS_UNSUPPORTED_CERTIFICATE: u32 = 0xBEBC32B; - pub const QUIC_STATUS_REVOKED_CERTIFICATE: u32 = 0xBEBC32C; - pub const QUIC_STATUS_EXPIRED_CERTIFICATE: u32 = 0xBEBC32D; - pub const QUIC_STATUS_UNKNOWN_CERTIFICATE: u32 = 0xBEBC32E; - pub const QUIC_STATUS_REQUIRED_CERTIFICATE: u32 = 0xBEBC374; - pub const QUIC_STATUS_CERT_EXPIRED: u32 = 0xBEBC401; - pub const QUIC_STATUS_CERT_UNTRUSTED_ROOT: u32 = 0xBEBC402; - pub const QUIC_STATUS_CERT_NO_CERT: u32 = 0xBEBC403; -} - -#[cfg(target_os = "macos")] -mod status { - pub const QUIC_STATUS_SUCCESS: u32 = 0; - pub const QUIC_STATUS_PENDING: u32 = 0xFFFFFFFE; // -2 - pub const QUIC_STATUS_CONTINUE: u32 = 0xFFFFFFFF; // -1 - pub const QUIC_STATUS_OUT_OF_MEMORY: u32 = 12; - pub const QUIC_STATUS_INVALID_PARAMETER: u32 = 22; - pub const QUIC_STATUS_INVALID_STATE: u32 = 1; - pub const QUIC_STATUS_NOT_SUPPORTED: u32 = 102; - pub const QUIC_STATUS_NOT_FOUND: u32 = 2; - pub const QUIC_STATUS_BUFFER_TOO_SMALL: u32 = 84; - pub const QUIC_STATUS_HANDSHAKE_FAILURE: u32 = 53; - pub const QUIC_STATUS_ABORTED: u32 = 89; - pub const QUIC_STATUS_ADDRESS_IN_USE: u32 = 48; - pub const QUIC_STATUS_INVALID_ADDRESS: u32 = 47; - pub const QUIC_STATUS_CONNECTION_TIMEOUT: u32 = 60; - pub const QUIC_STATUS_CONNECTION_IDLE: u32 = 101; - pub const QUIC_STATUS_INTERNAL_ERROR: u32 = 5; - pub const QUIC_STATUS_CONNECTION_REFUSED: u32 = 61; - pub const QUIC_STATUS_PROTOCOL_ERROR: u32 = 100; - pub const QUIC_STATUS_VER_NEG_ERROR: u32 = 43; - pub const QUIC_STATUS_UNREACHABLE: u32 = 65; - pub const QUIC_STATUS_TLS_ERROR: u32 = 126; - pub const QUIC_STATUS_USER_CANCELED: u32 = 105; - pub const QUIC_STATUS_ALPN_NEG_FAILURE: u32 = 42; - pub const QUIC_STATUS_STREAM_LIMIT_REACHED: u32 = 86; - pub const QUIC_STATUS_ALPN_IN_USE: u32 = 41; - pub const QUIC_STATUS_ADDRESS_NOT_AVAILABLE: u32 = 47; - pub const QUIC_STATUS_CLOSE_NOTIFY: u32 = 0xBEBC300; - pub const QUIC_STATUS_BAD_CERTIFICATE: u32 = 0xBEBC32A; - pub const QUIC_STATUS_UNSUPPORTED_CERTIFICATE: u32 = 0xBEBC32B; - pub const QUIC_STATUS_REVOKED_CERTIFICATE: u32 = 0xBEBC32C; - pub const QUIC_STATUS_EXPIRED_CERTIFICATE: u32 = 0xBEBC32D; - pub const QUIC_STATUS_UNKNOWN_CERTIFICATE: u32 = 0xBEBC32E; - pub const QUIC_STATUS_REQUIRED_CERTIFICATE: u32 = 0xBEBC374; - pub const QUIC_STATUS_CERT_EXPIRED: u32 = 0xBEBC401; - pub const QUIC_STATUS_CERT_UNTRUSTED_ROOT: u32 = 0xBEBC402; - pub const QUIC_STATUS_CERT_NO_CERT: u32 = 0xBEBC403; -} - -pub use status::*; - -/// Helper for processing MsQuic return statuses. -pub struct Status {} - -impl Status { - /// Determines if a MsQuic status is considered a success, which includes - /// both "no error" and "pending" status codes. - #[cfg(target_os = "windows")] - pub fn succeeded(status: u32) -> bool { - (status as i32) >= 0 - } - #[cfg(not(target_os = "windows"))] - pub fn succeeded(status: u32) -> bool { - (status as i32) <= 0 - } - - /// Determines if a MsQuic status is considered a failure. - #[cfg(target_os = "windows")] - pub fn failed(status: u32) -> bool { - (status as i32) < 0 - } - #[cfg(not(target_os = "windows"))] - pub fn failed(status: u32) -> bool { - (status as i32) > 0 - } -} - /// The different possible TLS providers used by MsQuic. pub type TlsProvider = u32; pub const TLS_PROVIDER_SCHANNEL: TlsProvider = 0; @@ -1503,8 +1358,8 @@ impl Api { START_MSQUIC.call_once(|| { let table: *const ApiTable = ptr::null(); let status = MsQuicOpenVersion(2, &table); - if Status::failed(status) { - panic!("Failed to open MsQuic: {}", status); + if let Err(err) = Error::from_u32(status).ok() { + panic!("Failed to open MsQuic: {}", err); } APITABLE = table; }); @@ -1567,23 +1422,21 @@ fn close_msquic() { } impl Registration { - pub fn new(config: *const RegistrationConfig) -> Result { + pub fn new(config: *const RegistrationConfig) -> Result { // We initialize APITABLE at only once. unsafe { START_MSQUIC.call_once(|| { let table: *const ApiTable = ptr::null(); let status = MsQuicOpenVersion(2, &table); - if Status::failed(status) { - panic!("Failed to open MsQuic: {}", status); + if let Err(err) = Error::from_u32(status).ok() { + panic!("Failed to open MsQuic: {}", err); } APITABLE = table; }); } let new_registration: Handle = ptr::null(); let status = unsafe { ((*APITABLE).registration_open)(config, &new_registration) }; - if Status::failed(status) { - return Err(status); - } + Error::from_u32(status).ok()?; Ok(Registration { handle: new_registration, }) @@ -1605,7 +1458,7 @@ impl Configuration { registration: &Registration, alpn: &[Buffer], settings: *const Settings, - ) -> Result { + ) -> Result { let context: *const c_void = ptr::null(); let new_configuration: Handle = ptr::null(); let mut settings_size: u32 = 0; @@ -1623,21 +1476,16 @@ impl Configuration { &new_configuration, ) }; - if Status::failed(status) { - return Err(status); - } + Error::from_u32(status).ok()?; Ok(Configuration { handle: new_configuration, }) } - pub fn load_credential(&self, cred_config: &CredentialConfig) -> Result<(), u32> { + pub fn load_credential(&self, cred_config: &CredentialConfig) -> Result<(), Error> { let status = unsafe { ((*APITABLE).configuration_load_credential)(self.handle, cred_config) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } } @@ -1669,14 +1517,11 @@ impl Connection { registration: &Registration, handler: ConnectionEventHandler, context: *const c_void, - ) -> Result<(), u32> { + ) -> Result<(), Error> { let status = unsafe { ((*APITABLE).connection_open)(registration.handle, handler, context, &self.handle) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } pub fn start( @@ -1684,7 +1529,7 @@ impl Connection { configuration: &Configuration, server_name: &str, server_port: u16, - ) -> Result<(), u32> { + ) -> Result<(), Error> { let server_name_safe = std::ffi::CString::new(server_name).unwrap(); let status = unsafe { ((*APITABLE).connection_start)( @@ -1695,10 +1540,7 @@ impl Connection { server_port, ) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } pub fn close(&self) { @@ -1713,8 +1555,9 @@ impl Connection { } } - pub fn set_param(&self, param: u32, buffer_length: u32, buffer: *const c_void) -> u32 { - unsafe { ((*APITABLE).set_param)(self.handle, param, buffer_length, buffer) } + pub fn set_param(&self, param: u32, buffer_length: u32, buffer: *const c_void) -> Error { + let status = unsafe { ((*APITABLE).set_param)(self.handle, param, buffer_length, buffer) }; + Error::from_u32(status) } pub fn stream_close(&self, stream: Handle) { @@ -1755,14 +1598,11 @@ impl Connection { unsafe { *(stat_buffer.as_ptr() as *const c_void as *const QuicStatisticsV2) } } - pub fn set_configuration(&self, configuration: &Configuration) -> Result<(), u32> { + pub fn set_configuration(&self, configuration: &Configuration) -> Result<(), Error> { let status = unsafe { ((*APITABLE).connection_set_configuration)(self.handle, configuration.handle) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } pub fn set_callback_handler(&self, handler: ConnectionEventHandler, context: *const c_void) { @@ -1788,7 +1628,7 @@ impl Connection { buffer_count: u32, flags: SendFlags, client_send_context: *const c_void, - ) -> Result<(), u32> { + ) -> Result<(), Error> { let status = unsafe { ((*APITABLE).datagram_send)( self.handle, @@ -1798,36 +1638,27 @@ impl Connection { client_send_context, ) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } - pub fn resumption_ticket_validation_complete(&self, result: BOOLEAN) -> Result<(), u32> { + pub fn resumption_ticket_validation_complete(&self, result: BOOLEAN) -> Result<(), Error> { let status = unsafe { ((*APITABLE).resumption_ticket_validation_complete)(self.handle, result) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } pub fn certificate_validation_complete( &self, result: BOOLEAN, tls_alert: TlsAlertCode, - ) -> Result<(), u32> { + ) -> Result<(), Error> { let status = unsafe { ((*APITABLE).certificate_validation_complete)(self.handle, result, tls_alert) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } - pub fn get_local_addr(&self) -> Result { + pub fn get_local_addr(&self) -> Result { let mut addr_buffer: [u8; mem::size_of::()] = [0; mem::size_of::()]; let addr_size_mut = mem::size_of::(); let status = unsafe { @@ -1838,13 +1669,11 @@ impl Connection { addr_buffer.as_mut_ptr() as *const c_void, ) }; - if Status::failed(status) { - return Err(status); - } + Error::from_u32(status).ok()?; Ok(unsafe { *(addr_buffer.as_ptr() as *const c_void as *const Addr) }) } - pub fn get_remote_addr(&self) -> Result { + pub fn get_remote_addr(&self) -> Result { let mut addr_buffer: [u8; mem::size_of::()] = [0; mem::size_of::()]; let addr_size_mut = mem::size_of::(); let status = unsafe { @@ -1855,9 +1684,7 @@ impl Connection { addr_buffer.as_mut_ptr() as *const c_void, ) }; - if Status::failed(status) { - return Err(status); - } + Error::from_u32(status).ok()?; Ok(unsafe { *(addr_buffer.as_ptr() as *const c_void as *const Addr) }) } } @@ -1886,17 +1713,14 @@ impl Listener { registration: &Registration, handler: ListenerEventHandler, context: *const c_void, - ) -> Result<(), u32> { + ) -> Result<(), Error> { let status = unsafe { ((*APITABLE).listener_open)(registration.handle, handler, context, &self.handle) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } - pub fn start(&self, alpn: &[Buffer], local_address: Option<&Addr>) -> Result<(), u32> { + pub fn start(&self, alpn: &[Buffer], local_address: Option<&Addr>) -> Result<(), Error> { let status = unsafe { ((*APITABLE).listener_start)( self.handle, @@ -1907,10 +1731,7 @@ impl Listener { .unwrap_or(ptr::null()), ) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } pub fn stop(&self) { @@ -1919,7 +1740,7 @@ impl Listener { } } - pub fn get_local_addr(&self) -> Result { + pub fn get_local_addr(&self) -> Result { let mut addr_buffer: [u8; mem::size_of::()] = [0; mem::size_of::()]; let addr_size_mut = mem::size_of::(); let status = unsafe { @@ -1930,9 +1751,7 @@ impl Listener { addr_buffer.as_mut_ptr() as *const c_void, ) }; - if Status::failed(status) { - return Err(status); - } + Error::from_u32(status).ok()?; Ok(unsafe { *(addr_buffer.as_ptr() as *const c_void as *const Addr) }) } @@ -1972,30 +1791,21 @@ impl Stream { flags: StreamOpenFlags, handler: StreamEventHandler, context: *const c_void, - ) -> Result<(), u32> { + ) -> Result<(), Error> { let status = unsafe { ((*APITABLE).stream_open)(connection.handle, flags, handler, context, &self.handle) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } - pub fn start(&self, flags: StreamStartFlags) -> Result<(), u32> { + pub fn start(&self, flags: StreamStartFlags) -> Result<(), Error> { let status = unsafe { ((*APITABLE).stream_start)(self.handle, flags) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } - pub fn shutdown(&self, flags: StreamShutdownFlags, error_code: u62) -> Result<(), u32> { + pub fn shutdown(&self, flags: StreamShutdownFlags, error_code: u62) -> Result<(), Error> { let status = unsafe { ((*APITABLE).stream_shutdown)(self.handle, flags, error_code) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } pub fn close(&self) { @@ -2010,7 +1820,7 @@ impl Stream { buffer_count: u32, flags: SendFlags, client_send_context: *const c_void, - ) -> Result<(), u32> { + ) -> Result<(), Error> { let status = unsafe { ((*APITABLE).stream_send)( self.handle, @@ -2020,10 +1830,7 @@ impl Stream { client_send_context, //(self as *const Stream) as *const c_void, ) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } pub fn set_callback_handler(&self, handler: StreamEventHandler, context: *const c_void) { @@ -2037,20 +1844,14 @@ impl Stream { param: u32, buffer_length: *mut u32, buffer: *const c_void, - ) -> Result<(), u32> { + ) -> Result<(), Error> { let status = unsafe { ((*APITABLE).get_param)(self.handle, param, buffer_length, buffer) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } - pub fn receive_complete(&self, buffer_length: u64) -> Result<(), u32> { + pub fn receive_complete(&self, buffer_length: u64) -> Result<(), Error> { let status = unsafe { ((*APITABLE).stream_receive_complete)(self.handle, buffer_length) }; - if Status::failed(status) { - return Err(status); - } - Ok(()) + Error::from_u32(status).ok() } } @@ -2134,7 +1935,7 @@ fn test_module() { let res = Registration::new(ptr::null()); assert!( res.is_ok(), - "Failed to open registration: 0x{:x}", + "Failed to open registration: {}", res.err().unwrap() ); let registration = res.unwrap(); @@ -2155,7 +1956,7 @@ fn test_module() { ); assert!( res.is_ok(), - "Failed to open configuration: 0x{:x}", + "Failed to open configuration: {}", res.err().unwrap() ); let configuration = res.unwrap(); @@ -2164,7 +1965,7 @@ fn test_module() { let res = configuration.load_credential(&cred_config); assert!( res.is_ok(), - "Failed to load credential: 0x{:x}", + "Failed to load credential: {}", res.err().unwrap() ); @@ -2176,14 +1977,14 @@ fn test_module() { ); assert!( res.is_ok(), - "Failed to open connection: 0x{:x}", + "Failed to open connection: {}", res.err().unwrap() ); let res = connection.start(&configuration, "www.cloudflare.com", 443); assert!( res.is_ok(), - "Failed to start connection: 0x{:x}", + "Failed to start connection: {}", res.err().unwrap() );