1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/* Copyright (c) Fortanix, Inc.
 *
 * Licensed under the GNU General Public License, version 2 <LICENSE-GPL or
 * https://www.gnu.org/licenses/gpl-2.0.html> or the Apache License, Version
 * 2.0 <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>, at your
 * option. This file may not be copied, modified, or distributed except
 * according to those terms. */

use mbedtls_sys::types::raw_types::{c_int, c_uchar, c_void};
use mbedtls_sys::types::size_t;
use mbedtls_sys::*;

use error::IntoResult;

callback!(EntropySourceCallback(data: *mut c_uchar, size: size_t, out: *mut size_t) -> c_int);

define!(struct OsEntropy<'source>(entropy_context) {
	pub fn new=entropy_init;
	fn drop=entropy_free;
});

#[cfg(feature = "threading")]
unsafe impl<'source> Sync for OsEntropy<'source> {}

impl<'source> OsEntropy<'source> {
    pub fn add_source<F: EntropySourceCallback>(
        &mut self,
        source: &'source mut F,
        threshold: size_t,
        strong: bool,
    ) -> ::Result<()> {
        unsafe {
            try!(
                entropy_add_source(
                    &mut self.inner,
                    Some(F::call),
                    source.data_ptr(),
                    threshold,
                    if strong {
                        ENTROPY_SOURCE_STRONG
                    } else {
                        ENTROPY_SOURCE_WEAK
                    }
                ).into_result()
            )
        };
        Ok(())
    }

    pub fn gather(&mut self) -> ::Result<()> {
        unsafe { try!(entropy_gather(&mut self.inner).into_result()) };
        Ok(())
    }

    pub fn update_manual(&mut self, data: &[u8]) -> ::Result<()> {
        unsafe {
            try!(entropy_update_manual(&mut self.inner, data.as_ptr(), data.len()).into_result())
        };
        Ok(())
    }

    // TODO
    // entropy_write_seed_file
    // entropy_update_seed_file
    //
}

impl<'source> super::EntropyCallback for OsEntropy<'source> {
    #[inline(always)]
    unsafe extern "C" fn call(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int {
        entropy_func(user_data, data, len)
    }

    fn data_ptr(&mut self) -> *mut c_void {
        &mut self.inner as *mut _ as *mut _
    }
}