use embedded_nal::nb;
#[cfg(feature = "rng")]
use rand_core::impls;
#[cfg(feature = "rng")]
use rand_core::RngCore;
use crate::manager::PRNG_DATA_LENGTH;
use crate::stack::socket_callbacks::Prng;
use super::StackError;
use super::WincClient;
use super::Xfer;
const PRNG_REQUEST_TIMEOUT_MILLISECONDS: u32 = 5_000;
impl<X: Xfer> WincClient<'_, X> {
pub fn get_random_bytes(&mut self, data: &mut [u8]) -> nb::Result<(), StackError> {
match &mut self.callbacks.prng {
None => {
self.operation_countdown = PRNG_REQUEST_TIMEOUT_MILLISECONDS;
let to_recv = data.len().min(PRNG_DATA_LENGTH);
let data = Prng {
offset: 0,
rcv_buffer: None,
};
self.manager
.send_prng(&data as *const _ as u32, to_recv as u16)
.map_err(StackError::WincWifiFail)?;
self.callbacks.prng = Some(Some(data));
}
Some(op_prng) => {
match op_prng {
Some(prng) => {
if let Some(rcv_buff) = prng.rcv_buffer {
let rcvd_len = rcv_buff.len().min((data[prng.offset..]).len());
data[prng.offset..(prng.offset + rcvd_len)]
.copy_from_slice(&rcv_buff[..rcvd_len]);
let offset = prng.offset + rcvd_len;
if offset >= data.len() {
self.callbacks.prng = None;
return Ok(());
} else {
let new_data = Prng {
offset,
rcv_buffer: None,
};
let to_recv = (data[offset..]).len().min(PRNG_DATA_LENGTH);
self.manager
.send_prng(&data as *const _ as u32, to_recv as u16)
.map_err(StackError::WincWifiFail)?;
self.callbacks.prng = Some(Some(new_data));
}
} else {
self.delay_us(self.poll_loop_delay_us);
self.operation_countdown -= 1;
if self.operation_countdown == 0 {
self.callbacks.prng = None;
return Err(nb::Error::Other(StackError::GeneralTimeout));
}
}
}
_ => {
return Err(nb::Error::Other(StackError::Unexpected));
}
}
}
}
self.dispatch_events()?;
Err(nb::Error::WouldBlock)
}
}
#[cfg(feature = "rng")]
impl<X: Xfer> RngCore for WincClient<'_, X> {
fn next_u32(&mut self) -> u32 {
impls::next_u32_via_fill(self)
}
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_fill(self)
}
fn fill_bytes(&mut self, dst: &mut [u8]) {
let result = nb::block!(self.get_random_bytes(dst));
if result.is_err() {
dst.fill(0xffu8);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::client::{test_shared::*, SocketCallbacks};
use crate::manager::EventListener;
#[cfg(feature = "rng")]
use rand_core::RngCore;
#[test]
fn test_prng_timeout() {
let mut client = make_test_client();
let mut random_bytes = [0x0u8; 32];
let result = nb::block!(client.get_random_bytes(&mut random_bytes));
assert_eq!(result, Err(StackError::GeneralTimeout));
}
#[test]
fn test_prng_success() {
let mut client = make_test_client();
const TEST_LEN: usize = 16;
let test_data: [u8; TEST_LEN] = [0x01u8; TEST_LEN];
let mut random_bytes = [0x0u8; TEST_LEN];
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_prng(&test_data);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.get_random_bytes(&mut random_bytes));
assert_eq!(result, Ok(()));
assert_eq!(random_bytes, test_data);
}
#[test]
fn test_prng_large_buffer() {
let mut client = make_test_client();
let test_data: [u8; PRNG_DATA_LENGTH] = [0x01u8; PRNG_DATA_LENGTH];
const IN_BUFF_LEN: usize = 1100;
let mut input_buffer = [0x0u8; IN_BUFF_LEN];
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_prng(&test_data);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.get_random_bytes(&mut input_buffer));
assert_eq!(result, Ok(()));
let mut offset = 0;
while offset < IN_BUFF_LEN {
let remaining = IN_BUFF_LEN - offset;
let step = test_data.len().min(remaining);
assert_eq!(&input_buffer[offset..offset + step], &test_data[..step]);
offset += step;
}
}
#[cfg(feature = "rng")]
#[test]
fn test_rng_fill_bytes_success() {
let mut client = make_test_client();
let test_data: [u8; 32] = [0x01u8; 32];
let mut random_bytes = [0x0u8; 32];
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_prng(&test_data);
};
client.debug_callback = Some(&mut my_debug);
client.fill_bytes(&mut random_bytes);
assert!(random_bytes.iter().all(|&b| b != 0));
}
#[cfg(feature = "rng")]
#[test]
fn test_rng_fill_bytes_failure() {
let mut client = make_test_client();
let mut random_bytes = [0xffu8; 32];
client.fill_bytes(&mut random_bytes);
assert!(random_bytes.iter().all(|&b| b == 0xff));
}
#[cfg(feature = "rng")]
#[test]
fn test_rng_next_u32_success() {
let mut client = make_test_client();
let test_data: [u8; 32] = [0x01u8; 32];
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_prng(&test_data);
};
client.debug_callback = Some(&mut my_debug);
let random_u32 = client.next_u32();
assert!(random_u32 == 0x01010101);
}
#[cfg(feature = "rng")]
#[test]
fn test_rng_next_u32_failure() {
let mut client = make_test_client();
let random_u32 = client.next_u32();
assert!(random_u32 == 0xffffffff);
}
#[cfg(feature = "rng")]
#[test]
fn test_rng_next_u64_success() {
let mut client = make_test_client();
let test_data: [u8; 32] = [0x01u8; 32];
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_prng(&test_data);
};
client.debug_callback = Some(&mut my_debug);
let random_u64 = client.next_u64();
assert!(random_u64 == 0x0101010101010101);
}
#[cfg(feature = "rng")]
#[test]
fn test_rng_next_u64_failure() {
let mut client = make_test_client();
let random_u64 = client.next_u64();
assert!(random_u64 == 0xffffffffffffffff);
}
}