(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 }