new error
This commit is contained in:
parent
f860bde8d8
commit
1e2a5aa75e
@ -21,3 +21,7 @@ fuchsia-cprng = "0.1"
|
||||
[target.wasm32-unknown-unknown.dependencies]
|
||||
wasm-bindgen = { version = "0.2.12", optional = true }
|
||||
stdweb = { version = "0.4", optional = true }
|
||||
|
||||
[features]
|
||||
# Forces syscall usage on Linux, Android and Solaris
|
||||
force_syscall = []
|
||||
|
@ -16,6 +16,8 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
if errno == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Unknown)
|
||||
Err(Error(unsafe {
|
||||
NonZeroU32::new_unchecked(errno as u32)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
|
||||
|
||||
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
RNG_FILE.with(|f| {
|
||||
use_init(f, || File::open("/dev/random"), |f| f.read_exact(dest))
|
||||
}).map_err(|_| Error::Unknown)
|
||||
use_init(f,
|
||||
|| File::open("/dev/random").map_err(From::from),
|
||||
|f| f.read_exact(dest).map_err(From::from),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -7,9 +7,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! A dummy implementation for unsupported targets which always returns
|
||||
//! `Err(Error::Unavailable)`
|
||||
use super::Error;
|
||||
//! `Err(UNAVAILABLE_ERROR)`
|
||||
use super::UNAVAILABLE_ERROR;
|
||||
|
||||
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
Err(Error::Unavailable)
|
||||
Err(UNAVAILABLE_ERROR)
|
||||
}
|
||||
|
@ -21,11 +21,11 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
// task length variation, partition large randomBytes requests when
|
||||
// doing so as part of fulfilling a client request.
|
||||
RNG_FILE.with(|f| {
|
||||
use_init(f, || File::open("/dev/random"), |f| {
|
||||
use_init(f, || File::open("/dev/random").map_err(From::from), |f| {
|
||||
for chunk in dest.chunks_mut(65536) {
|
||||
f.read_exact(chunk)?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}).map_err(|_| Error::Unknown)
|
||||
})
|
||||
}
|
||||
|
70
src/error.rs
70
src/error.rs
@ -6,16 +6,64 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::num::NonZeroU32;
|
||||
use core::convert::From;
|
||||
use core::fmt;
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
use std::{io, error};
|
||||
|
||||
pub const UNKNOWN_ERROR: Error = Error(unsafe {
|
||||
NonZeroU32::new_unchecked(0x756e6b6e) // "unkn"
|
||||
});
|
||||
|
||||
pub const UNAVAILABLE_ERROR: Error = Error(unsafe {
|
||||
NonZeroU32::new_unchecked(0x4e416e61) // "NAna"
|
||||
});
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Error {
|
||||
/// Call was interrupted.
|
||||
///
|
||||
/// Typically it can be retried.
|
||||
Interrupted,
|
||||
/// RNG source is unavailable on a given system.
|
||||
Unavailable,
|
||||
/// Unknown error.
|
||||
Unknown,
|
||||
#[doc(hidden)]
|
||||
__Nonexhaustive,
|
||||
pub struct Error(NonZeroU32);
|
||||
|
||||
impl Error {
|
||||
pub fn code(&self) -> NonZeroU32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
UNKNOWN_ERROR => write!(f, "Getrandom Error: unknown"),
|
||||
UNAVAILABLE_ERROR => write!(f, "Getrandom Error: unavailable"),
|
||||
code => write!(f, "Getrandom Error: {}", code.0.get()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
impl From<io::Error> for Error {
|
||||
fn from(err: io::Error) -> Self {
|
||||
err.raw_os_error()
|
||||
.map(|code| Error(unsafe {
|
||||
// all supported targets use 0 as success code
|
||||
NonZeroU32::new_unchecked(code as u32)
|
||||
}))
|
||||
// in practice this should never happen
|
||||
.unwrap_or(UNKNOWN_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
impl Into<io::Error> for Error {
|
||||
fn into(self) -> io::Error {
|
||||
match self {
|
||||
UNKNOWN_ERROR => io::Error::new(io::ErrorKind::Other,
|
||||
"getrandom error: unknown"),
|
||||
UNAVAILABLE_ERROR => io::Error::new(io::ErrorKind::Other,
|
||||
"getrandom error: entropy source is unavailable"),
|
||||
code => io::Error::from_raw_os_error(code.0.get() as i32),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
impl error::Error for Error { }
|
||||
|
@ -11,6 +11,7 @@ extern crate libc;
|
||||
|
||||
use super::Error;
|
||||
use core::ptr;
|
||||
use std::io;
|
||||
|
||||
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
let mib = [libc::CTL_KERN, libc::KERN_ARND];
|
||||
@ -24,7 +25,7 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
)
|
||||
};
|
||||
if ret == -1 || len != chunk.len() {
|
||||
return Err(Error::Unknown);
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
13
src/lib.rs
13
src/lib.rs
@ -7,16 +7,7 @@
|
||||
// except according to those terms.
|
||||
#![no_std]
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "netbsd",
|
||||
target_os = "solaris",
|
||||
target_os = "redox",
|
||||
target_os = "dragonfly",
|
||||
target_os = "haiku",
|
||||
target_os = "emscripten",
|
||||
target_os = "linux",
|
||||
))]
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
#[macro_use] extern crate std;
|
||||
|
||||
#[cfg(any(
|
||||
@ -31,7 +22,7 @@
|
||||
))]
|
||||
mod utils;
|
||||
mod error;
|
||||
pub use error::Error;
|
||||
pub use error::{Error, UNKNOWN_ERROR, UNAVAILABLE_ERROR};
|
||||
|
||||
macro_rules! mod_use {
|
||||
($cond:meta, $module:ident) => {
|
||||
|
@ -58,8 +58,8 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
match f {
|
||||
RngSource::GetRandom => syscall_getrandom(dest),
|
||||
RngSource::Device(f) => f.read_exact(dest),
|
||||
}
|
||||
}).map_err(|_| Error::Unknown)
|
||||
}.map_err(From::from)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
//! Implementation for MacOS / iOS
|
||||
use super::Error;
|
||||
use std::io;
|
||||
|
||||
// TODO: check correctness
|
||||
#[allow(non_upper_case_globals)]
|
||||
@ -29,7 +30,7 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
)
|
||||
};
|
||||
if ret == -1 {
|
||||
Err(Error::Unknown)
|
||||
Err(io::Error::last_os_error().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
|
||||
RNG_INIT.store(true, Ordering::Relaxed)
|
||||
}
|
||||
File::open("/dev/urandom")
|
||||
}, |f| f.read_exact(dest))
|
||||
}).map_err(|_| Error::Unknown)
|
||||
File::open("/dev/urandom").map_err(From::from)
|
||||
}, |f| f.read_exact(dest).map_err(From::from))
|
||||
})
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
extern crate libc;
|
||||
|
||||
use super::Error;
|
||||
use std::io;
|
||||
|
||||
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
for chunk in dest.chunks_mut(256) {
|
||||
@ -20,7 +21,7 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
)
|
||||
};
|
||||
if ret == -1 {
|
||||
return Err(Error::Unknown);
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -17,6 +17,9 @@ thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
|
||||
|
||||
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
RNG_FILE.with(|f| {
|
||||
use_init(f, || File::open("rand:"), |f| f.read_exact(dest))
|
||||
}).map_err(|_| Error::Unknown)
|
||||
use_init(f,
|
||||
|| File::open("rand:").map_err(From::from),
|
||||
|f| f.read_exact(dest).map_err(From::from),
|
||||
)
|
||||
}).map_err(From::from)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation for SGX using RDRAND instruction
|
||||
use super::Error;
|
||||
use super::{Error, UNKNOWN_ERROR};
|
||||
|
||||
use core::{mem, ptr};
|
||||
use core::arch::x86_64::_rdrand64_step;
|
||||
@ -26,7 +26,7 @@ fn get_rand_u64() -> Result<u64, Error> {
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(Error::Unknown)
|
||||
Err(UNKNOWN_ERROR)
|
||||
}
|
||||
|
||||
pub fn getrandom(mut dest: &mut [u8]) -> Result<(), Error> {
|
||||
|
@ -36,7 +36,7 @@ thread_local!(
|
||||
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
|
||||
);
|
||||
|
||||
fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
|
||||
fn syscall_getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
// repalce with libc?
|
||||
const SYS_GETRANDOM: libc::c_long = 143;
|
||||
|
||||
@ -48,7 +48,7 @@ fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
|
||||
syscall(SYS_GETRANDOM, dest.as_mut_ptr(), dest.len(), 0)
|
||||
};
|
||||
if ret == -1 || ret != dest.len() as i64 {
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(io::Error::last_os_error().from());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -71,7 +71,7 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
syscall_getrandom(chunk)
|
||||
},
|
||||
RngSource::Device(f) => for chunk in dest.chunks_mut(1040) {
|
||||
f.read_exact(dest)
|
||||
f.read_exact(dest).map_err(From::from)
|
||||
},
|
||||
}
|
||||
})
|
||||
|
10
src/utils.rs
10
src/utils.rs
@ -5,16 +5,16 @@
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
use std::cell::RefCell;
|
||||
use std::ops::DerefMut;
|
||||
use std::io;
|
||||
use super::Error;
|
||||
use core::cell::RefCell;
|
||||
use core::ops::DerefMut;
|
||||
|
||||
/// If `f` contains `Some(T)` call `use_f` using contents of `f` as an argument,
|
||||
/// otherwise initialize `f` value using `init_f`, store resulting value in `f`
|
||||
/// and call `use_f`.
|
||||
pub(crate) fn use_init<T, F, U>(f: &RefCell<Option<T>>, init_f: F, mut use_f: U)
|
||||
-> io::Result<()>
|
||||
where F: FnOnce() -> io::Result<T>, U: FnMut(&mut T) -> io::Result<()>
|
||||
-> Result<(), Error>
|
||||
where F: FnOnce() -> Result<T, Error>, U: FnMut(&mut T) -> Result<(), Error>
|
||||
{
|
||||
let mut f = f.borrow_mut();
|
||||
let f: &mut Option<T> = f.deref_mut();
|
||||
|
@ -12,12 +12,13 @@ extern crate winapi;
|
||||
use self::winapi::shared::minwindef::ULONG;
|
||||
use self::winapi::um::ntsecapi::RtlGenRandom;
|
||||
use self::winapi::um::winnt::PVOID;
|
||||
use std::io;
|
||||
use super::Error;
|
||||
|
||||
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
||||
let ret = unsafe {
|
||||
RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG)
|
||||
};
|
||||
if ret == 0 { return Err(Error::Unknown); }
|
||||
if ret == 0 { return Err(io::Error::last_os_error().into()); }
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user