(index<- )        ./libstd/rand/os.rs

   1  // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  //! Interfaces to the operating system provided random number
  12  //! generators.
  13  
  14  use rand::Rng;
  15  use ops::Drop;
  16  
  17  #[cfg(unix)]
  18  use rand::reader::ReaderRng;
  19  #[cfg(unix)]
  20  use rt::io::{file, Open, Read};
  21  
  22  #[cfg(windows)]
  23  use cast;
  24  #[cfg(windows)]
  25  use libc::{c_long, DWORD, BYTE};
  26  #[cfg(windows)]
  27  type HCRYPTPROV = c_long;
  28  // the extern functions imported from the runtime on Windows are
  29  // implemented so that they either succeed or abort(), so we can just
  30  // assume they work when we call them.
  31  
  32  /// A random number generator that retrieves randomness straight from
  33  /// the operating system. On Unix-like systems this reads from
  34  /// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
  35  ///
  36  /// This does not block.
  37  #[cfg(unix)]
  38  pub struct OSRng {
  39      priv inner: ReaderRng<file::FileStream>
  40  }
  41  /// A random number generator that retrieves randomness straight from
  42  /// the operating system. On Unix-like systems this reads from
  43  /// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
  44  ///
  45  /// This does not block.
  46  #[cfg(windows)]
  47  pub struct OSRng {
  48      priv hcryptprov: HCRYPTPROV
  49  }
  50  
  51  impl OSRng {
  52      /// Create a new `OSRng`.
  53      #[cfg(unix)]
  54      pub fn new() -> OSRng {
  55          let reader = file::open(&"/dev/urandom", Open, Read).expect("Error opening /dev/urandom");
  56          let reader_rng = ReaderRng::new(reader);
  57  
  58          OSRng { inner: reader_rng }
  59      }
  60  
  61      /// Create a new `OSRng`.
  62      #[cfg(windows)]
  63      pub fn new() -> OSRng {
  64          externfn!(fn rust_win32_rand_acquire(phProv: *mut HCRYPTPROV))
  65  
  66          let mut hcp = 0;
  67          unsafe {rust_win32_rand_acquire(&mut hcp)};
  68  
  69          OSRng { hcryptprov: hcp }
  70      }
  71  }
  72  
  73  #[cfg(unix)]
  74  impl Rng for OSRng {
  75      fn next_u32(&mut self) -> u32 {
  76          self.inner.next_u32()
  77      }
  78      fn next_u64(&mut self) -> u64 {
  79          self.inner.next_u64()
  80      }
  81      fn fill_bytes(&mut self, v&mut [u8]) {
  82          self.inner.fill_bytes(v)
  83      }
  84  }
  85  
  86  #[cfg(windows)]
  87  impl Rng for OSRng {
  88      fn next_u32(&mut self) -> u32 {
  89          let mut v = [0u8, .. 4];
  90          self.fill_bytes(v);
  91          unsafe { cast::transmute(v) }
  92      }
  93      fn next_u64(&mut self) -> u64 {
  94          let mut v = [0u8, .. 8];
  95          self.fill_bytes(v);
  96          unsafe { cast::transmute(v) }
  97      }
  98      fn fill_bytes(&mut self, v: &mut [u8]) {
  99          externfn!(fn rust_win32_rand_gen(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: *mut BYTE))
 100  
 101          do v.as_mut_buf |ptr, len| {
 102              unsafe {rust_win32_rand_gen(self.hcryptprov, len as DWORD, ptr)}
 103          }
 104      }
 105  }
 106  
 107  impl Drop for OSRng {
 108      #[cfg(unix)]
 109      fn drop(&mut self) {
 110          // ensure that OSRng is not implicitly copyable on all
 111          // platforms, for consistency.
 112      }
 113  
 114      #[cfg(windows)]
 115      fn drop(&mut self) {
 116          externfn!(fn rust_win32_rand_release(hProv: HCRYPTPROV))
 117  
 118          unsafe {rust_win32_rand_release(self.hcryptprov)}
 119      }
 120  }
 121  
 122  
 123  #[cfg(test)]
 124  mod test {
 125      use super::*;
 126      use rand::Rng;
 127  
 128      #[test]
 129      fn test_os_rng() {
 130          let mut r = OSRng::new();
 131  
 132          r.next_u32();
 133          r.next_u64();
 134  
 135          let mut v = [0u8, .. 1000];
 136          r.fill_bytes(v);
 137      }
 138  
 139      #[test]
 140      fn test_os_rng_tasks() {
 141          use task;
 142          use comm;
 143          use comm::{GenericChan, GenericPort};
 144          use option::{None, Some};
 145          use iter::{Iterator, range};
 146          use vec::{ImmutableVector, OwnedVector};
 147  
 148          let mut chans = ~[];
 149          for _ in range(0, 20) {
 150              let (p, c) = comm::stream();
 151              chans.push(c);
 152              do task::spawn_with(p) |p| {
 153                  // wait until all the tasks are ready to go.
 154                  p.recv();
 155  
 156                  // deschedule to attempt to interleave things as much
 157                  // as possible (XXX: is this a good test?)
 158                  let mut r = OSRng::new();
 159                  task::deschedule();
 160                  let mut v = [0u8, .. 1000];
 161  
 162                  for _ in range(0, 100) {
 163                      r.next_u32();
 164                      task::deschedule();
 165                      r.next_u64();
 166                      task::deschedule();
 167                      r.fill_bytes(v);
 168                      task::deschedule();
 169                  }
 170              }
 171          }
 172  
 173          // start all the tasks
 174          for c in chans.iter() {
 175              c.send(())
 176          }
 177      }
 178  }