diff --git a/src/os.rs b/src/os.rs index 809e34c78e3..f55ff4ad4de 100644 --- a/src/os.rs +++ b/src/os.rs @@ -53,7 +53,8 @@ fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { } #[cfg(all(unix, not(target_os = "ios"), - not(target_os = "nacl")))] + not(target_os = "nacl"), + not(target_os = "freebsd")))] mod imp { extern crate libc; @@ -245,6 +246,49 @@ mod imp { } } +#[cfg(target_os = "freebsd")] +mod imp { + extern crate libc; + + use std::{io, ptr}; + use Rng; + + use super::{next_u32, next_u64}; + + pub struct OsRng; + + impl OsRng { + pub fn new() -> io::Result { + Ok(OsRng) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + next_u32(&mut |v| self.fill_bytes(v)) + } + fn next_u64(&mut self) -> u64 { + next_u64(&mut |v| self.fill_bytes(v)) + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let mib = [libc::CTL_KERN, libc::KERN_ARND]; + // kern.arandom permits a maximum buffer size of 256 bytes + for s in v.chunks_mut(256) { + let mut s_len = s.len(); + let ret = unsafe { + libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, + s.as_mut_ptr() as *mut _, &mut s_len, + ptr::null(), 0) + }; + if ret == -1 || s_len != s.len() { + panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})", + ret, s.len(), s_len); + } + } + } + } +} + #[cfg(windows)] mod imp { use std::io;