diff --git a/Cargo.toml b/Cargo.toml index 2b813cc1..c67beac3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ log = { version = "0.4", optional = true } cfg-if = "0.1" [target.'cfg(any(unix, target_os = "redox", target_os = "wasi"))'.dependencies] -libc = "0.2.54" +libc = "0.2.60" [target.wasm32-unknown-unknown.dependencies] wasm-bindgen = { version = "0.2.29", optional = true } diff --git a/src/cloudabi.rs b/src/cloudabi.rs index e87359ee..d3d09289 100644 --- a/src/cloudabi.rs +++ b/src/cloudabi.rs @@ -17,14 +17,9 @@ extern "C" { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let errno = unsafe { cloudabi_sys_random_get(dest.as_mut_ptr(), dest.len()) }; if let Some(code) = NonZeroU32::new(errno as u32) { - error!("cloudabi_sys_random_get failed with code {}", code); + error!("cloudabi_sys_random_get: failed with {}", errno); Err(Error::from(code)) } else { Ok(()) // Zero means success for CloudABI } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/dummy.rs b/src/dummy.rs index b53f66c1..0c24ba0f 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -6,17 +6,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A dummy implementation for unsupported targets which always returns -//! `Err(Error::UNAVAILABLE)` -use crate::Error; -use core::num::NonZeroU32; +//! A dummy implementation for unsupported targets which always fails +use crate::{error::UNSUPPORTED, Error}; pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> { - error!("no support for this platform"); - Err(Error::UNAVAILABLE) -} - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None + Err(UNSUPPORTED) } diff --git a/src/error.rs b/src/error.rs index a83ea111..a61f2e4d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,78 +5,151 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::convert::From; use core::fmt; use core::num::NonZeroU32; -// A randomly-chosen 24-bit prefix for our codes -pub(crate) const CODE_PREFIX: u32 = 0x57f4c500; -const CODE_UNKNOWN: u32 = CODE_PREFIX | 0x00; -const CODE_UNAVAILABLE: u32 = CODE_PREFIX | 0x01; - -/// The error type. +/// A small and `no_std` compatible error type. +/// +/// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and +/// if so, which error code the OS gave the application. If such an error is +/// encountered, please consult with your system documentation. /// -/// This type is small and no-std compatible. +/// Internally this type is a NonZeroU32, with certain values reserved for +/// certain purposes, see [`Error::INTERNAL_START`] and [`Error::CUSTOM_START`]. #[derive(Copy, Clone, Eq, PartialEq)] -pub struct Error(pub(crate) NonZeroU32); +pub struct Error(NonZeroU32); impl Error { - /// An unknown error. - pub const UNKNOWN: Error = Error(unsafe { NonZeroU32::new_unchecked(CODE_UNKNOWN) }); + #[deprecated(since = "0.1.7")] + pub const UNKNOWN: Error = UNSUPPORTED; + #[deprecated(since = "0.1.7")] + pub const UNAVAILABLE: Error = UNSUPPORTED; + + /// Codes below this point represent OS Errors (i.e. positive i32 values). + /// Codes at or above this point, but below [`Error::CUSTOM_START`] are + /// reserved for use by the `rand` and `getrandom` crates. + pub const INTERNAL_START: u32 = 1 << 31; - /// No generator is available. - pub const UNAVAILABLE: Error = Error(unsafe { NonZeroU32::new_unchecked(CODE_UNAVAILABLE) }); + /// Codes at or above this point can be used by users to define their own + /// custom errors. + pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30); - /// Extract the error code. + /// Extract the raw OS error code (if this error came from the OS) /// - /// This may equal one of the codes defined in this library or may be a - /// system error code. + /// This method is identical to `std::io::Error::raw_os_error()`, except + /// that it works in `no_std` contexts. If this method returns `None`, the + /// error value can still be formatted via the `Diplay` implementation. + #[inline] + pub fn raw_os_error(&self) -> Option { + if self.0.get() < Self::INTERNAL_START { + Some(self.0.get() as i32) + } else { + None + } + } + + /// Extract the bare error code. /// - /// One may attempt to format this error via the `Display` implementation. + /// This code can either come from the underlying OS, or be a custom error. + /// Use [`Error::raw_os_error()`] to disambiguate. + #[inline] pub fn code(&self) -> NonZeroU32 { self.0 } +} - pub(crate) fn msg(&self) -> Option<&'static str> { - if let Some(msg) = crate::imp::error_msg_inner(self.0) { - Some(msg) - } else { - match *self { - Error::UNKNOWN => Some("getrandom: unknown error"), - Error::UNAVAILABLE => Some("getrandom: unavailable"), - _ => None, - } - } +#[cfg(any(unix, target_os = "redox"))] +fn os_err_desc(errno: i32, buf: &mut [u8]) -> Option<&str> { + let buf_ptr = buf.as_mut_ptr() as *mut libc::c_char; + if unsafe { libc::strerror_r(errno, buf_ptr, buf.len()) } != 0 { + return None; } + + // Take up to trailing null byte + let idx = buf.iter().position(|&b| b == 0).unwrap_or(buf.len()); + core::str::from_utf8(&buf[..idx]).ok() +} + +#[cfg(not(any(unix, target_os = "redox")))] +fn os_err_desc(_errno: i32, _buf: &mut [u8]) -> Option<&str> { + None } impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self.msg() { - Some(msg) => write!(f, "Error(\"{}\")", msg), - None => write!(f, "Error(0x{:08X})", self.0), + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut dbg = f.debug_struct("Error"); + if let Some(errno) = self.raw_os_error() { + dbg.field("os_error", &errno); + let mut buf = [0u8; 128]; + if let Some(desc) = os_err_desc(errno, &mut buf) { + dbg.field("description", &desc); + } + } else if let Some(desc) = internal_desc(*self) { + dbg.field("internal_code", &self.0.get()); + dbg.field("description", &desc); + } else { + dbg.field("unknown_code", &self.0.get()); } + dbg.finish() } } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self.msg() { - Some(msg) => write!(f, "{}", msg), - None => write!(f, "getrandom: unknown code 0x{:08X}", self.0), + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(errno) = self.raw_os_error() { + let mut buf = [0u8; 128]; + match os_err_desc(errno, &mut buf) { + Some(desc) => f.write_str(desc), + None => write!(f, "OS Error: {}", errno), + } + } else if let Some(desc) = internal_desc(*self) { + f.write_str(desc) + } else { + write!(f, "Unknown Error: {}", self.0.get()) } } } impl From for Error { fn from(code: NonZeroU32) -> Self { - Error(code) + Self(code) } } -impl From<&Error> for Error { - fn from(error: &Error) -> Self { - *error +// TODO: Convert to a function when min_version >= 1.33 +macro_rules! internal_error { + ($n:expr) => { + Error(unsafe { NonZeroU32::new_unchecked(Error::INTERNAL_START + $n as u16 as u32) }) + }; +} + +/// Internal Error constants +pub(crate) const UNSUPPORTED: Error = internal_error!(0); +pub(crate) const ERRNO_NOT_POSITIVE: Error = internal_error!(1); +pub(crate) const UNKNOWN_IO_ERROR: Error = internal_error!(2); +pub(crate) const SEC_RANDOM_FAILED: Error = internal_error!(3); +pub(crate) const RTL_GEN_RANDOM_FAILED: Error = internal_error!(4); +pub(crate) const FAILED_RDRAND: Error = internal_error!(5); +pub(crate) const NO_RDRAND: Error = internal_error!(6); +pub(crate) const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7); +pub(crate) const BINDGEN_GRV_UNDEF: Error = internal_error!(8); +pub(crate) const STDWEB_NO_RNG: Error = internal_error!(9); +pub(crate) const STDWEB_RNG_FAILED: Error = internal_error!(10); + +fn internal_desc(error: Error) -> Option<&'static str> { + match error { + UNSUPPORTED => Some("getrandom: this target is not supported"), + ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"), + UNKNOWN_IO_ERROR => Some("Unknown std::io::Error"), + SEC_RANDOM_FAILED => Some("SecRandomCopyBytes: call failed"), + RTL_GEN_RANDOM_FAILED => Some("RtlGenRandom: call failed"), + FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"), + NO_RDRAND => Some("RDRAND: instruction not supported"), + BINDGEN_CRYPTO_UNDEF => Some("wasm-bindgen: self.crypto is undefined"), + BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"), + STDWEB_NO_RNG => Some("stdweb: no randomness source available"), + STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"), + _ => None, } } diff --git a/src/error_impls.rs b/src/error_impls.rs index 6bd2c69a..007472e4 100644 --- a/src/error_impls.rs +++ b/src/error_impls.rs @@ -7,28 +7,29 @@ // except according to those terms. extern crate std; -use crate::error::Error; +use crate::{error::UNKNOWN_IO_ERROR, Error}; use core::convert::From; use core::num::NonZeroU32; -use std::{error, io}; +use std::io; impl From for Error { fn from(err: io::Error) -> Self { - err.raw_os_error() - .and_then(|code| NonZeroU32::new(code as u32)) - .map(|code| Error(code)) - // in practice this should never happen - .unwrap_or(Error::UNKNOWN) + if let Some(errno) = err.raw_os_error() { + if let Some(code) = NonZeroU32::new(errno as u32) { + return Error::from(code); + } + } + UNKNOWN_IO_ERROR } } impl From for io::Error { fn from(err: Error) -> Self { - match err.msg() { - Some(msg) => io::Error::new(io::ErrorKind::Other, msg), - None => io::Error::from_raw_os_error(err.0.get() as i32), + match err.raw_os_error() { + Some(errno) => io::Error::from_raw_os_error(errno), + None => io::Error::new(io::ErrorKind::Other, err), } } } -impl error::Error for Error {} +impl std::error::Error for Error {} diff --git a/src/freebsd.rs b/src/freebsd.rs index aa77b221..61feaf73 100644 --- a/src/freebsd.rs +++ b/src/freebsd.rs @@ -9,7 +9,6 @@ //! Implementation for FreeBSD use crate::util_libc::{sys_fill_exact, Weak}; use crate::Error; -use core::num::NonZeroU32; use core::{mem, ptr}; type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; @@ -44,8 +43,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { sys_fill_exact(dest, kern_arnd) } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/fuchsia.rs b/src/fuchsia.rs index a9f53888..572ff534 100644 --- a/src/fuchsia.rs +++ b/src/fuchsia.rs @@ -8,7 +8,6 @@ //! Implementation for Fuchsia Zircon use crate::Error; -use core::num::NonZeroU32; #[link(name = "zircon")] extern "C" { @@ -19,8 +18,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { unsafe { zx_cprng_draw(dest.as_mut_ptr(), dest.len()) } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/ios.rs b/src/ios.rs index 97d68979..30c008c2 100644 --- a/src/ios.rs +++ b/src/ios.rs @@ -7,10 +7,7 @@ // except according to those terms. //! Implementation for iOS -extern crate std; - -use crate::Error; -use core::num::NonZeroU32; +use crate::{error::SEC_RANDOM_FAILED, Error}; // TODO: Make extern once extern_types feature is stabilized. See: // https://github.com/rust-lang/rust/issues/43467 @@ -27,14 +24,8 @@ extern "C" { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) }; if ret == -1 { - error!("SecRandomCopyBytes call failed"); - Err(Error::UNKNOWN) + Err(SEC_RANDOM_FAILED) } else { Ok(()) } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/lib.rs b/src/lib.rs index d98d8584..03e1cc48 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,25 +79,8 @@ //! `getrandom`, hence after the first successful call one can be reasonably //! confident that no errors will occur. //! -//! On unsupported platforms, `getrandom` always fails with [`Error::UNAVAILABLE`]. -//! -//! ## Error codes -//! The crate uses the following custom error codes: -//! - `0x57f4c500` (dec: 1475659008) - an unknown error. Constant: -//! [`Error::UNKNOWN`] -//! - `0x57f4c501` (dec: 1475659009) - no generator is available. Constant: -//! [`Error::UNAVAILABLE`] -//! - `0x57f4c580` (dec: 1475659136) - `self.crypto` is undefined, -//! `wasm-bindgen` specific error. -//! - `0x57f4c581` (dec: 1475659137) - `crypto.getRandomValues` is undefined, -//! `wasm-bindgen` specific error. -//! -//! These codes are provided for reference only and should not be matched upon -//! (but you can match on `Error` constants). The codes may change in future and -//! such change will not be considered a breaking one. -//! -//! Other error codes will originate from an underlying system. In case if such -//! error is encountered, please consult with your system documentation. +//! On unsupported platforms, `getrandom` always fails. See the [`Error`] type +//! for more information on what data is returned on failure. //! //! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html //! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html @@ -146,14 +129,12 @@ cfg_if! { } } -#[cfg(feature = "std")] -extern crate std; - mod error; pub use crate::error::Error; #[allow(dead_code)] mod util; +// Unlike the other Unix, Fuchsia and iOS don't use the libc to make any calls. #[cfg(any( target_os = "android", target_os = "dragonfly", @@ -197,7 +178,6 @@ mod error_impls; target_os = "solaris", target_os = "illumos", ))] -#[allow(dead_code)] mod use_file; // System-specific implementations. diff --git a/src/linux_android.rs b/src/linux_android.rs index 8aa1d58d..0f10e08f 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -7,13 +7,9 @@ // except according to those terms. //! Implementation for Linux / Android -extern crate std; - use crate::util::LazyBool; -use crate::util_libc::sys_fill_exact; +use crate::util_libc::{last_os_error, sys_fill_exact}; use crate::{use_file, Error}; -use core::num::NonZeroU32; -use std::io; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { static HAS_GETRANDOM: LazyBool = LazyBool::new(); @@ -29,7 +25,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { fn is_getrandom_available() -> bool { let res = unsafe { libc::syscall(libc::SYS_getrandom, 0, 0, libc::GRND_NONBLOCK) }; if res < 0 { - match io::Error::last_os_error().raw_os_error() { + match last_os_error().raw_os_error() { Some(libc::ENOSYS) => false, // No kernel support Some(libc::EPERM) => false, // Blocked by seccomp _ => true, @@ -38,8 +34,3 @@ fn is_getrandom_available() -> bool { true } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/macos.rs b/src/macos.rs index 84d95565..c3bc5334 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -7,13 +7,9 @@ // except according to those terms. //! Implementation for macOS -extern crate std; - -use crate::util_libc::Weak; +use crate::util_libc::{last_os_error, Weak}; use crate::{use_file, Error}; use core::mem; -use core::num::NonZeroU32; -use std::io; type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; @@ -24,8 +20,9 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len()) }; if ret != 0 { - error!("getentropy syscall failed with ret={}", ret); - return Err(io::Error::last_os_error().into()); + let err = last_os_error(); + error!("getentropy syscall failed"); + return Err(err); } } Ok(()) @@ -35,8 +32,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { use_file::getrandom_inner(dest) } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/openbsd.rs b/src/openbsd.rs index e213e5f5..e1ac179f 100644 --- a/src/openbsd.rs +++ b/src/openbsd.rs @@ -7,24 +7,17 @@ // except according to those terms. //! Implementation for OpenBSD -extern crate std; - +use crate::util_libc::last_os_error; use crate::Error; -use core::num::NonZeroU32; -use std::io; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { let ret = unsafe { libc::getentropy(chunk.as_mut_ptr() as *mut libc::c_void, chunk.len()) }; if ret == -1 { + let err = last_os_error(); error!("libc::getentropy call failed"); - return Err(io::Error::last_os_error().into()); + return Err(err); } } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/rdrand.rs b/src/rdrand.rs index c55d2074..96229673 100644 --- a/src/rdrand.rs +++ b/src/rdrand.rs @@ -7,12 +7,12 @@ // except according to those terms. //! Implementation for SGX using RDRAND instruction +use crate::error::{FAILED_RDRAND, NO_RDRAND}; #[cfg(not(target_feature = "rdrand"))] use crate::util::LazyBool; use crate::Error; use core::arch::x86_64::_rdrand64_step; use core::mem; -use core::num::NonZeroU32; // Recommendation from "IntelĀ® Digital Random Number Generator (DRNG) Software // Implementation Guide" - Section 5.2.1 and "IntelĀ® 64 and IA-32 Architectures @@ -37,8 +37,7 @@ unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> { // Keep looping in case this was a false positive. } } - error!("RDRAND failed, CPU issue likely"); - Err(Error::UNKNOWN) + Err(FAILED_RDRAND) } // "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653. @@ -65,7 +64,7 @@ fn is_rdrand_supported() -> bool { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { if !is_rdrand_supported() { - return Err(Error::UNAVAILABLE); + return Err(NO_RDRAND); } // SAFETY: After this point, rdrand is supported, so calling the rdrand @@ -89,8 +88,3 @@ unsafe fn rdrand_exact(dest: &mut [u8]) -> Result<(), Error> { } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/solaris_illumos.rs b/src/solaris_illumos.rs index 8539971b..7550fce9 100644 --- a/src/solaris_illumos.rs +++ b/src/solaris_illumos.rs @@ -20,7 +20,6 @@ use crate::util_libc::{sys_fill_exact, Weak}; use crate::{use_file, Error}; use core::mem; -use core::num::NonZeroU32; #[cfg(target_os = "illumos")] type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; @@ -43,8 +42,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { use_file::getrandom_inner(dest) } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/use_file.rs b/src/use_file.rs index adc1b3cd..74a12ef7 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -9,15 +9,11 @@ //! Implementations that just need to read from a file extern crate std; -use crate::util_libc::LazyFd; +use crate::util_libc::{last_os_error, LazyFd}; use crate::Error; use core::mem::ManuallyDrop; -use core::num::NonZeroU32; use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; -use std::{ - fs::File, - io::{self, Read}, -}; +use std::{fs::File, io::Read}; #[cfg(target_os = "redox")] const FILE_PATH: &str = "rand:"; @@ -35,7 +31,7 @@ const FILE_PATH: &str = "/dev/random"; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { static FD: LazyFd = LazyFd::new(); - let fd = FD.init(init_file).ok_or(io::Error::last_os_error())?; + let fd = FD.init(init_file).ok_or(last_os_error())?; let file = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) }); let mut file_ref: &File = &file; @@ -60,9 +56,3 @@ fn init_file() -> Option { } Some(File::open(FILE_PATH).ok()?.into_raw_fd()) } - -#[inline(always)] -#[allow(dead_code)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/util_libc.rs b/src/util_libc.rs index 606bc1ff..015d1a04 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -5,12 +5,34 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate std; - +use crate::error::ERRNO_NOT_POSITIVE; use crate::util::LazyUsize; use crate::Error; +use core::num::NonZeroU32; use core::ptr::NonNull; -use std::io; + +cfg_if! { + if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] { + use libc::__errno as errno_location; + } else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "redox"))] { + use libc::__errno_location as errno_location; + } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { + use libc::___errno as errno_location; + } else if #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly"))] { + use libc::__error as errno_location; + } else if #[cfg(target_os = "haiku")] { + use libc::_errnop as errno_location; + } +} + +pub fn last_os_error() -> Error { + let errno = unsafe { *errno_location() }; + if errno > 0 { + Error::from(NonZeroU32::new(errno as u32).unwrap()) + } else { + ERRNO_NOT_POSITIVE + } +} // Fill a buffer by repeatedly invoking a system call. The `sys_fill` function: // - should return -1 and set errno on failure @@ -22,10 +44,10 @@ pub fn sys_fill_exact( while !buf.is_empty() { let res = sys_fill(buf); if res < 0 { - let err = io::Error::last_os_error(); + let err = last_os_error(); // We should try again if the call was interrupted. if err.raw_os_error() != Some(libc::EINTR) { - return Err(err.into()); + return Err(err); } } else { // We don't check for EOF (ret = 0) as the data we are reading diff --git a/src/wasi.rs b/src/wasi.rs index 10b91788..0920752f 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -14,14 +14,9 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { libc::__wasi_random_get(dest.as_mut_ptr() as *mut libc::c_void, dest.len()) }; if let Some(code) = NonZeroU32::new(ret as u32) { - error!("WASI: __wasi_random_get failed with return value {}", code); + error!("WASI: __wasi_random_get: failed with {}", ret); Err(Error::from(code)) } else { Ok(()) // Zero means success for WASI } } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/wasm32_bindgen.rs b/src/wasm32_bindgen.rs index 08df426b..c6eef5fd 100644 --- a/src/wasm32_bindgen.rs +++ b/src/wasm32_bindgen.rs @@ -11,17 +11,13 @@ extern crate std; use core::cell::RefCell; use core::mem; -use core::num::NonZeroU32; use std::thread_local; use wasm_bindgen::prelude::*; -use crate::error::CODE_PREFIX; +use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF}; use crate::Error; -const CODE_CRYPTO_UNDEF: u32 = CODE_PREFIX | 0x80; -const CODE_GRV_UNDEF: u32 = CODE_PREFIX | 0x81; - #[derive(Clone, Debug)] enum RngSource { Node(NodeCrypto), @@ -83,17 +79,13 @@ fn getrandom_init() -> Result { // we're in an older web browser and the OS RNG isn't available. let crypto = this.crypto(); if crypto.is_undefined() { - return Err(Error::from(unsafe { - NonZeroU32::new_unchecked(CODE_CRYPTO_UNDEF) - })); + return Err(BINDGEN_CRYPTO_UNDEF); } // Test if `crypto.getRandomValues` is undefined as well let crypto: BrowserCrypto = crypto.into(); if crypto.get_random_values_fn().is_undefined() { - return Err(Error::from(unsafe { - NonZeroU32::new_unchecked(CODE_GRV_UNDEF) - })); + return Err(BINDGEN_GRV_UNDEF); } // Ok! `self.crypto.getRandomValues` is a defined value, so let's @@ -101,15 +93,6 @@ fn getrandom_init() -> Result { Ok(RngSource::Browser(crypto)) } -#[inline(always)] -pub fn error_msg_inner(n: NonZeroU32) -> Option<&'static str> { - match n.get() { - CODE_CRYPTO_UNDEF => Some("getrandom: self.crypto is undefined"), - CODE_GRV_UNDEF => Some("crypto.getRandomValues is undefined"), - _ => None, - } -} - #[wasm_bindgen] extern "C" { type Function; diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs index 32a5686c..c59c9c42 100644 --- a/src/wasm32_stdweb.rs +++ b/src/wasm32_stdweb.rs @@ -8,12 +8,12 @@ //! Implementation for WASM via stdweb use core::mem; -use core::num::NonZeroU32; use stdweb::unstable::TryInto; use stdweb::web::error::Error as WebError; use stdweb::{_js_impl, js}; +use crate::error::{STDWEB_NO_RNG, STDWEB_RNG_FAILED}; use crate::Error; use std::sync::Once; @@ -26,7 +26,7 @@ enum RngSource { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { assert_eq!(mem::size_of::(), 4); static ONCE: Once = Once::new(); - static mut RNG_SOURCE: Result = Err(Error::UNAVAILABLE); + static mut RNG_SOURCE: Result = Ok(RngSource::Node); // SAFETY: RNG_SOURCE is only written once, before being read. ONCE.call_once(|| unsafe { @@ -69,7 +69,7 @@ fn getrandom_init() -> Result { } else { let err: WebError = js! { return @{ result }.error }.try_into().unwrap(); error!("getrandom unavailable: {}", err); - Err(Error::UNAVAILABLE) + Err(STDWEB_NO_RNG) } } @@ -105,13 +105,8 @@ fn getrandom_fill(source: RngSource, dest: &mut [u8]) -> Result<(), Error> { if js! { return @{ result.as_ref() }.success } != true { let err: WebError = js! { return @{ result }.error }.try_into().unwrap(); error!("getrandom failed: {}", err); - return Err(Error::UNKNOWN); + return Err(STDWEB_RNG_FAILED); } } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -} diff --git a/src/windows.rs b/src/windows.rs index c52e9f10..e1b8df66 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -7,10 +7,7 @@ // except according to those terms. //! Implementation for Windows -extern crate std; - -use crate::Error; -use core::num::NonZeroU32; +use crate::{error::RTL_GEN_RANDOM_FAILED, Error}; extern "system" { #[link_name = "SystemFunction036"] @@ -22,14 +19,8 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(u32::max_value() as usize) { let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr(), chunk.len() as u32) }; if ret == 0 { - error!("RtlGenRandom call failed"); - return Err(Error::UNKNOWN); + return Err(RTL_GEN_RANDOM_FAILED); } } Ok(()) } - -#[inline(always)] -pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { - None -}