pub mod bencode;
mod flight;
mod frontier;
mod items;
pub mod krpc;
mod lookup;
pub mod mutable;
pub mod transport;
pub use krpc::{Node, NodeId};
pub use mutable::{Keypair, Mutable, target_of};
pub use transport::{Transport, Udp};
use ring::rand::SecureRandom;
use std::collections::BTreeMap;
use std::net::SocketAddr;
use std::time::Duration;
#[derive(Clone, Debug)]
pub struct Config {
pub alpha: usize,
pub k: usize,
pub deadline: Duration,
pub max_queries: usize,
}
impl Default for Config {
fn default() -> Config {
Config {
alpha: 8,
k: 8,
deadline: Duration::from_secs(1),
max_queries: 64,
}
}
}
pub struct Dht {
transport: Box<dyn Transport>,
bootstrap: Vec<SocketAddr>,
config: Config,
id: NodeId,
tid: u16,
claims: Vec<SocketAddr>,
}
impl Dht {
pub fn new(
transport: Box<dyn Transport>,
bootstrap: Vec<SocketAddr>,
config: Config,
) -> Result<Dht, String> {
let mut id = [0u8; 20];
random(&mut id)?;
Ok(Dht {
transport,
bootstrap,
config,
id: NodeId(id),
tid: 0,
claims: Vec::new(),
})
}
pub fn observed(&self) -> Vec<SocketAddr> {
[true, false]
.into_iter()
.filter_map(|v4| plurality(self.claims.iter().copied().filter(|a| a.is_ipv4() == v4)))
.collect()
}
pub(crate) fn next_tid(&mut self) -> Vec<u8> {
self.tid = self.tid.wrapping_add(1);
self.tid.to_be_bytes().to_vec()
}
}
fn plurality(claims: impl Iterator<Item = SocketAddr>) -> Option<SocketAddr> {
let mut counts: BTreeMap<SocketAddr, usize> = BTreeMap::new();
for claim in claims {
*counts.entry(claim).or_default() += 1;
}
let top = counts.values().max()?;
let mut leaders = counts.iter().filter(|(_, n)| *n == top);
let (winner, _) = leaders.next()?;
leaders.next().is_none().then_some(*winner)
}
pub(crate) fn random(buf: &mut [u8]) -> Result<(), String> {
ring::rand::SystemRandom::new()
.fill(buf)
.map_err(|_| "the system offered no randomness".to_string())
}
#[cfg(test)]
pub(crate) mod tests;