crate::ix!();
#[cfg(not_windows)]
pub fn get_dev_urandom(ent32: *mut u8) {
let f: i32 = unsafe {
libc::open(b"/dev/urandom\0".as_ptr() as *const i8, libc::O_RDONLY)
};
if f == -1 {
rand_failure();
}
let mut have: isize = 0;
loop {
let count: usize =
(NUM_OS_RANDOM_BYTES - (have as i32)).try_into().unwrap();
let n: isize = unsafe {
libc::read(
f,
ent32.offset(have) as *mut c_void,
count)
};
if n <= 0 || (n + have) as i32 > NUM_OS_RANDOM_BYTES {
unsafe {
libc::close(f);
}
rand_failure();
}
have += n;
if have as i32 >= NUM_OS_RANDOM_BYTES {
break;
}
}
unsafe {
libc::close(f);
}
}
#[cfg(test)]
mod dev_urandom_spec {
use super::*;
#[traced_test]
#[cfg(not_windows)]
fn fills_exactly_32_bytes_and_changes_between_calls() {
let mut a = [0u8; NUM_OS_RANDOM_BYTES as usize];
let mut b = [0u8; NUM_OS_RANDOM_BYTES as usize];
get_dev_urandom(a.as_mut_ptr());
get_dev_urandom(b.as_mut_ptr());
assert_eq!(a.len(), 32);
assert_eq!(b.len(), 32);
assert_ne!(a, [0u8; 32], "first draw from /dev/urandom was all zeros — indicates OS RNG failure");
assert_ne!(a, b, "two /dev/urandom draws were identical (2^-256 chance); re-run if fluke");
}
#[traced_test]
fn fill_bytes_fills_entire_slice() {
let mut ctx = FastRandomContext::new(true);
let mut buf = [0u8; 64];
ctx.fill_bytes(&mut buf);
assert!(buf.iter().any(|&x| x != 0)); assert!(buf.iter().filter(|&&x| x == 0).count() < 64); }
}