From 764f31cc21638ef46af8d9a6f855f5ec69b52569 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 9 Jan 2018 12:05:53 +0000 Subject: [PATCH] Inline fill_via_try_fill implicit error handling, and revise --- src/impls.rs | 36 ------------------------------------ src/os.rs | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index 0ca19fc97c..f8bf316cb8 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -167,40 +167,4 @@ pub fn next_u64_via_fill(rng: &mut R) -> u64 { impl_uint_from_fill!(rng, u64, 8) } -/// Implement `fill` via `try_fill` with implicit error handling. -pub fn fill_via_try_fill(rng: &mut R, dest: &mut [u8]) { - const WAIT_DUR_MS: u32 = 100; - const MAX_WAIT: u32 = (1 * 60 * 1000) / WAIT_DUR_MS; - const TRANSIENT_STEP: u32 = MAX_WAIT / 8; - let mut err_count = 0; - - loop { - if let Err(e) = rng.try_fill(dest) { - if e.kind().should_retry() { - if err_count > MAX_WAIT { - // TODO: log details & cause? - panic!("Too many RNG errors or timeout; last error: {}", e.msg()); - } - - if e.kind().should_wait() { - #[cfg(feature="std")]{ - let dur = ::std::time::Duration::from_millis(WAIT_DUR_MS as u64); - ::std::thread::sleep(dur); - } - err_count += 1; - } else { - err_count += TRANSIENT_STEP; - } - - continue; - } - - // TODO: log details & cause? - panic!("Fatal RNG error: {}", e.msg()); - } - - break; - } -} - // TODO: implement tests for the above diff --git a/src/os.rs b/src/os.rs index 5e0924d11e..166bfb8df1 100644 --- a/src/os.rs +++ b/src/os.rs @@ -61,7 +61,38 @@ impl Rng for OsRng { } fn fill(&mut self, dest: &mut [u8]) { - impls::fill_via_try_fill(self, dest) + // We cannot return Err(..), so we try to handle before panicking. + const WAIT_DUR_MS: u32 = 100; // retry every 100ms + const MAX_WAIT: u32 = (10 * 1000) / WAIT_DUR_MS; // max 10s + const TRANSIENT_STEP: u32 = MAX_WAIT / 8; + let mut err_count = 0; + + loop { + if let Err(e) = self.try_fill(dest) { + // TODO: add logging to explain why we wait and the full cause + if e.kind().should_retry() { + if err_count > MAX_WAIT { + panic!("Too many RNG errors or timeout; last error: {}", e.msg()); + } + + if e.kind().should_wait() { + #[cfg(feature="std")]{ + let dur = ::std::time::Duration::from_millis(WAIT_DUR_MS as u64); + ::std::thread::sleep(dur); + } + err_count += 1; + } else { + err_count += TRANSIENT_STEP; + } + + continue; + } + + panic!("Fatal RNG error: {}", e.msg()); + } + + break; + } } fn try_fill(&mut self, v: &mut [u8]) -> Result<(), Error> {