pub(crate) mod bencode;
mod items;
pub(crate) mod krpc;
mod lookup;
pub(crate) mod mutable;
pub(crate) mod transport;
#[cfg(test)]
pub(crate) use krpc::Node;
pub(crate) use krpc::NodeId;
pub(crate) use mutable::Keypair;
pub(crate) use transport::{Transport, Udp};
#[cfg(test)]
use bencode::{Dict, bytes, entry};
use ring::rand::SecureRandom;
use std::net::SocketAddr;
use std::time::Duration;
#[derive(Clone, Debug)]
pub(crate) struct Config {
pub(crate) alpha: usize,
pub(crate) k: usize,
pub(crate) round: Duration,
pub(crate) max_queries: usize,
}
impl Default for Config {
fn default() -> Config {
Config {
alpha: 3,
k: 8,
round: Duration::from_secs(2),
max_queries: 64,
}
}
}
pub(crate) struct Dht {
transport: Box<dyn Transport>,
bootstrap: Vec<SocketAddr>,
config: Config,
id: NodeId,
tid: u16,
}
impl Dht {
pub(crate) 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,
})
}
#[cfg(test)]
pub(crate) fn lookup(&mut self, target: NodeId) -> Result<Vec<Node>, String> {
let out = self.search(
target,
"find_node",
Dict::from([entry("target", bytes(&target.0))]),
)?;
Ok(out
.replies
.into_iter()
.map(|(n, _)| n)
.take(self.config.k)
.collect())
}
pub(crate) fn next_tid(&mut self) -> Vec<u8> {
self.tid = self.tid.wrapping_add(1);
self.tid.to_be_bytes().to_vec()
}
}
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;