use bloomfilter::Bloom;
use log::debug;
use crate::config::ServerType;
const BF_NUM_ENTRIES_FOR_SERVER: usize = 1_000_000;
const BF_NUM_ENTRIES_FOR_CLIENT: usize = 10_000;
const BF_ERROR_RATE_FOR_SERVER: f64 = 1e-6;
const BF_ERROR_RATE_FOR_CLIENT: f64 = 1e-15;
#[derive(Debug)]
pub struct PingPongBloom {
blooms: [Bloom<[u8]>; 2],
bloom_count: [usize; 2],
item_count: usize,
current: usize,
}
impl PingPongBloom {
pub fn new(ty: ServerType) -> Self {
let (mut item_count, fp_p) = if ty.is_local() {
(BF_NUM_ENTRIES_FOR_CLIENT, BF_ERROR_RATE_FOR_CLIENT)
} else {
(BF_NUM_ENTRIES_FOR_SERVER, BF_ERROR_RATE_FOR_SERVER)
};
item_count /= 2;
Self {
blooms: [
Bloom::new_for_fp_rate(item_count, fp_p).expect("BloomFilter1"),
Bloom::new_for_fp_rate(item_count, fp_p).expect("BloomFilter2"),
],
bloom_count: [0, 0],
item_count,
current: 0,
}
}
pub fn check_and_set(&mut self, buf: &[u8]) -> bool {
for bloom in &self.blooms {
if bloom.check(buf) {
return true;
}
}
if self.bloom_count[self.current] >= self.item_count {
self.current = (self.current + 1) % 2;
self.bloom_count[self.current] = 0;
self.blooms[self.current].clear();
debug!(
"bloom filter based replay protector full, each capacity: {}, total filters: {}",
self.item_count,
self.blooms.len(),
);
}
self.blooms[self.current].set(buf);
self.bloom_count[self.current] += 1;
false
}
}