rqbit/crates/dht/src/dht.rs

976 lines
32 KiB
Rust
Raw Normal View History

2021-07-12 19:42:48 +01:00
use std::{
cmp::Reverse,
2021-07-12 19:42:48 +01:00
net::SocketAddr,
2023-11-28 07:40:27 +00:00
sync::{
2023-11-29 19:34:29 +00:00
atomic::{AtomicU16, Ordering},
2023-11-28 07:40:27 +00:00
Arc,
},
2021-07-14 15:29:59 +01:00
task::Poll,
2023-11-28 16:14:49 +00:00
time::{Duration, Instant},
2021-07-12 19:42:48 +01:00
};
use crate::{
bprotocol::{
2023-11-29 19:34:29 +00:00
self, CompactNodeInfo, ErrorDescription, FindNodeRequest, GetPeersRequest, Message,
MessageKind, Node, PingRequest, Response,
2021-07-12 19:42:48 +01:00
},
routing_table::{InsertResult, RoutingTable},
REQUERY_INTERVAL, RESPONSE_TIMEOUT,
2021-07-12 19:42:48 +01:00
};
use anyhow::{bail, Context};
use backoff::{backoff::Backoff, ExponentialBackoffBuilder};
2023-11-28 11:35:28 +00:00
use bencode::ByteString;
use dashmap::DashMap;
2023-11-29 19:34:29 +00:00
use futures::{stream::FuturesUnordered, Stream, StreamExt, TryFutureExt};
2023-11-22 21:56:00 +00:00
use leaky_bucket::RateLimiter;
2023-11-25 15:15:16 +00:00
use librqbit_core::{id20::Id20, peer_id::generate_peer_id, spawn_utils::spawn};
2022-12-07 22:01:29 +00:00
use parking_lot::RwLock;
2023-11-29 19:34:29 +00:00
2021-07-14 00:48:53 +01:00
use serde::Serialize;
2021-07-12 19:42:48 +01:00
use tokio::{
net::UdpSocket,
2023-11-29 19:34:29 +00:00
sync::mpsc::{channel, unbounded_channel, Sender, UnboundedReceiver, UnboundedSender},
2021-07-12 19:42:48 +01:00
};
2023-11-29 19:34:29 +00:00
use tracing::{debug, debug_span, error, error_span, info, trace, warn, Instrument};
2021-07-12 19:42:48 +01:00
2021-07-14 00:48:53 +01:00
#[derive(Debug, Serialize)]
pub struct DhtStats {
2021-07-14 13:40:56 +01:00
#[serde(serialize_with = "crate::utils::serialize_id20")]
2021-07-14 00:48:53 +01:00
pub id: Id20,
pub outstanding_requests: usize,
pub routing_table_size: usize,
2021-07-12 19:42:48 +01:00
}
2023-11-28 08:56:27 +00:00
struct OutstandingRequest {
done: tokio::sync::oneshot::Sender<anyhow::Result<ResponseOrError>>,
2023-11-28 08:56:27 +00:00
}
2023-11-28 15:55:13 +00:00
pub struct WorkerSendRequest {
our_tid: Option<u16>,
message: Message<ByteString>,
addr: SocketAddr,
}
#[derive(Debug)]
struct MaybeUsefulNode {
id: Id20,
addr: SocketAddr,
last_request: Instant,
last_response: Option<Instant>,
2023-11-29 18:22:00 +00:00
errors_in_a_row: usize,
returned_peers: bool,
}
fn make_rate_limiter() -> RateLimiter {
// TODO: move to configuration, i'm lazy.
let dht_queries_per_second = std::env::var("DHT_QUERIES_PER_SECOND")
.map(|v| v.parse().expect("couldn't parse DHT_QUERIES_PER_SECOND"))
.unwrap_or(250usize);
let per_100_ms = dht_queries_per_second / 10;
RateLimiter::builder()
.initial(per_100_ms)
.max(dht_queries_per_second)
.interval(Duration::from_millis(100))
.fair(false)
.refill(per_100_ms)
.build()
}
2023-11-29 19:34:29 +00:00
trait RecursiveRequestCallbacks: Sized + Send + Sync + 'static {
fn on_request_start(&self, req: &RecursiveRequest<Self>, target_node: Id20, addr: SocketAddr);
2023-11-29 19:34:29 +00:00
fn on_request_end(
&self,
req: &RecursiveRequest<Self>,
2023-11-29 19:34:29 +00:00
target_node: Id20,
addr: SocketAddr,
resp: &anyhow::Result<ResponseOrError>,
);
}
struct RecursiveRequestCallbacksGetPeers {}
impl RecursiveRequestCallbacks for RecursiveRequestCallbacksGetPeers {
fn on_request_start(&self, _: &RecursiveRequest<Self>, _: Id20, _: SocketAddr) {}
2023-11-29 19:34:29 +00:00
fn on_request_end(
&self,
_: &RecursiveRequest<Self>,
2023-11-29 19:34:29 +00:00
_: Id20,
_: SocketAddr,
_: &anyhow::Result<ResponseOrError>,
) {
}
}
struct RecursiveRequestCallbacksFindNodes {}
impl RecursiveRequestCallbacks for RecursiveRequestCallbacksFindNodes {
fn on_request_start(&self, req: &RecursiveRequest<Self>, target_node: Id20, addr: SocketAddr) {
2023-11-29 19:34:29 +00:00
match req.dht.routing_table_add_node(target_node, addr) {
InsertResult::WasExisting | InsertResult::ReplacedBad(_) | InsertResult::Added => {
req.dht
.routing_table
.write()
.mark_outgoing_request(&target_node);
}
InsertResult::Ignored => {}
}
}
fn on_request_end(
&self,
req: &RecursiveRequest<Self>,
2023-11-29 19:34:29 +00:00
target_node: Id20,
_addr: SocketAddr,
resp: &anyhow::Result<ResponseOrError>,
) {
let mut table = req.dht.routing_table.write();
if resp.is_ok() {
table.mark_response(&target_node);
} else {
table.mark_error(&target_node);
}
}
}
struct RecursiveRequest<C: RecursiveRequestCallbacks> {
info_hash: Id20,
2023-11-29 19:34:29 +00:00
request: Request,
dht: Arc<DhtState>,
useful_nodes: RwLock<Vec<MaybeUsefulNode>>,
peer_tx: tokio::sync::mpsc::UnboundedSender<SocketAddr>,
node_tx: tokio::sync::mpsc::UnboundedSender<(Option<Id20>, SocketAddr)>,
2023-11-29 19:34:29 +00:00
callbacks: C,
}
struct RequestPeersStream {
rx: tokio::sync::mpsc::UnboundedReceiver<SocketAddr>,
cancel_join_handle: tokio::task::JoinHandle<()>,
}
impl RequestPeersStream {
fn new(dht: Arc<DhtState>, info_hash: Id20) -> Self {
2023-11-29 18:22:00 +00:00
let (peer_tx, peer_rx) = unbounded_channel();
let (node_tx, node_rx) = unbounded_channel();
2023-11-29 19:34:29 +00:00
let rp = Arc::new(RecursiveRequest {
info_hash,
2023-11-29 19:34:29 +00:00
request: Request::GetPeers(info_hash),
dht,
useful_nodes: RwLock::new(Vec::new()),
peer_tx,
node_tx,
2023-11-29 19:34:29 +00:00
callbacks: RecursiveRequestCallbacksGetPeers {},
});
let join_handle = rp.request_peers_forever(node_rx);
Self {
2023-11-29 18:22:00 +00:00
rx: peer_rx,
cancel_join_handle: join_handle,
}
}
}
impl Drop for RequestPeersStream {
fn drop(&mut self) {
self.cancel_join_handle.abort();
}
}
impl Stream for RequestPeersStream {
type Item = SocketAddr;
fn poll_next(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> Poll<Option<Self::Item>> {
self.rx.poll_recv(cx)
}
}
2023-11-29 19:34:29 +00:00
impl RecursiveRequest<RecursiveRequestCallbacksFindNodes> {
async fn bootstrap(dht: Arc<DhtState>, target: Id20, hostname: &str) -> anyhow::Result<()> {
let addrs = tokio::net::lookup_host(hostname)
.await
.with_context(|| format!("error looking up {}", hostname))?;
2023-11-29 19:34:29 +00:00
let (node_tx, mut node_rx) = unbounded_channel();
let req = RecursiveRequest {
2023-11-29 19:34:29 +00:00
info_hash: target,
request: Request::FindNode(target),
dht,
useful_nodes: RwLock::new(Vec::new()),
peer_tx: unbounded_channel().0,
node_tx,
2023-11-29 19:34:29 +00:00
callbacks: RecursiveRequestCallbacksFindNodes {},
};
let request_one = |id, addr| {
req.request_one(id, addr)
.map_err(|e| {
debug!("error: {e:?}");
e
})
.instrument(error_span!(
"find_node",
target = format!("{target:?}"),
addr = addr.to_string()
))
};
2023-11-29 19:34:29 +00:00
let mut futs = FuturesUnordered::new();
let mut initial_addrs = 0;
for addr in addrs {
futs.push(request_one(None, addr));
initial_addrs += 1;
2023-11-29 19:34:29 +00:00
}
2023-11-29 18:22:00 +00:00
let mut successes = 0;
let mut errors = 0;
2023-11-29 19:34:29 +00:00
loop {
tokio::select! {
biased;
2023-11-29 19:34:29 +00:00
r = node_rx.recv() => {
let (id, addr) = r.unwrap();
futs.push(request_one(id, addr))
2023-11-29 19:34:29 +00:00
},
f = futs.next() => {
let f = match f {
Some(f) => f,
None => {
// find_node recursion finished.
break;
}
};
if f.is_ok() {
successes += 1;
} else {
errors += 1;
2023-11-29 19:34:29 +00:00
}
}
}
}
if successes == 0 {
bail!("no successful lookups, errors = {errors}");
}
debug!(
"finished, successes = {successes}, errors = {errors}, initial_addrs = {initial_addrs}"
);
2023-11-29 19:34:29 +00:00
Ok(())
}
}
impl RecursiveRequest<RecursiveRequestCallbacksGetPeers> {
2023-11-29 18:22:00 +00:00
fn request_peers_forever(
self: &Arc<Self>,
2023-11-29 19:34:29 +00:00
mut node_rx: tokio::sync::mpsc::UnboundedReceiver<(Option<Id20>, SocketAddr)>,
2023-11-29 18:22:00 +00:00
) -> tokio::task::JoinHandle<()> {
let this = self.clone();
spawn(
error_span!(parent: None, "get_peers", info_hash = format!("{:?}", self.info_hash)),
async move {
let this = &this;
2023-11-29 18:22:00 +00:00
// Looper adds root nodes to the queue every 60 seconds.
let looper = {
async move {
let mut iteration = 0;
loop {
debug!("iteration {}", iteration);
let sleep = match this.get_peers_root() {
2023-11-29 18:22:00 +00:00
Ok(0) => Duration::from_secs(1),
Ok(n) if n < 8 => REQUERY_INTERVAL / 2,
Ok(_) => REQUERY_INTERVAL,
Err(e) => {
error!("error in get_peers_root(): {e:?}");
2023-11-29 18:22:00 +00:00
return Err::<(), anyhow::Error>(e);
}
};
tokio::time::sleep(sleep).await;
iteration += 1;
}
}
};
tokio::pin!(looper);
let mut futs = FuturesUnordered::new();
loop {
2023-11-29 18:22:00 +00:00
tokio::select! {
addr = node_rx.recv() => {
2023-11-29 19:34:29 +00:00
let (id, addr) = addr.unwrap();
2023-11-29 18:22:00 +00:00
futs.push(
this.request_one(id, addr)
2023-11-29 18:22:00 +00:00
.map_err(|e| debug!("error: {e:?}"))
.instrument(error_span!("addr", addr=addr.to_string()))
);
}
2023-11-29 18:22:00 +00:00
Some(_) = futs.next(), if !futs.is_empty() => {}
_ = &mut looper => {}
}
}
},
)
}
fn get_peers_root(&self) -> anyhow::Result<usize> {
2023-11-29 19:34:29 +00:00
let mut count = 0;
for (id, addr) in self
2023-11-29 18:22:00 +00:00
.dht
2023-11-29 19:34:29 +00:00
.routing_table
.read()
.sorted_by_distance_from(self.info_hash)
.iter()
.map(|n| (n.id(), n.addr()))
.take(8)
{
count += 1;
self.node_tx.send((Some(id), addr))?;
2023-11-29 19:34:29 +00:00
}
Ok(count)
}
}
impl<C: RecursiveRequestCallbacks> RecursiveRequest<C> {
async fn request_one(&self, id: Option<Id20>, addr: SocketAddr) -> anyhow::Result<()> {
2023-11-29 19:34:29 +00:00
if let Some(id) = id {
self.callbacks.on_request_start(self, id, addr);
}
let response = self.dht.request(self.request, addr).await.map(|r| {
self.mark_node_responded(addr, &r);
r
});
if let Some(id) = id {
self.callbacks.on_request_end(self, id, addr, &response);
}
let response = match self.dht.request(self.request, addr).await {
Ok(ResponseOrError::Response(r)) => r,
Ok(ResponseOrError::Error(e)) => bail!("error response: {:?}", e),
Err(e) => {
2023-11-29 18:22:00 +00:00
self.mark_node_error(addr);
2023-11-29 19:34:29 +00:00
return Err(e);
}
2023-11-29 18:22:00 +00:00
};
trace!("received {response:?}");
2023-11-29 18:22:00 +00:00
if let Some(peers) = response.values {
for peer in peers {
self.peer_tx.send(SocketAddr::V4(peer.addr))?;
}
2023-11-29 18:22:00 +00:00
}
2023-11-29 18:22:00 +00:00
if let Some(nodes) = response.nodes {
for node in nodes.nodes {
let addr = SocketAddr::V4(node.addr);
let should_request = self.should_request_node(node.id, addr);
trace!(
"should_request={}, id={:?}, addr={}",
should_request,
node.id,
addr
);
if should_request {
self.node_tx.send((Some(node.id), addr))?;
}
}
2023-11-29 18:22:00 +00:00
}
Ok(())
}
2023-11-29 18:22:00 +00:00
fn mark_node_error(&self, addr: SocketAddr) -> bool {
self.useful_nodes
.write()
.iter_mut()
.find(|n| n.addr == addr)
.map(|n| {
n.errors_in_a_row += 1;
})
.is_some()
}
fn mark_node_responded(&self, addr: SocketAddr, response: &ResponseOrError) -> bool {
self.useful_nodes
.write()
.iter_mut()
.find(|n| n.addr == addr)
.map(|node| {
node.last_response = Some(Instant::now());
2023-11-29 18:22:00 +00:00
node.errors_in_a_row = 0;
match response {
ResponseOrError::Response(r) => {
node.returned_peers =
r.values.as_ref().map(|c| !c.is_empty()).unwrap_or(false)
}
ResponseOrError::Error(_) => {
node.returned_peers = false;
}
}
})
.is_some()
}
fn should_request_node(&self, node_id: Id20, addr: SocketAddr) -> bool {
let mut closest_nodes = self.useful_nodes.write();
// If recently requested, ignore
if let Some(existing) = closest_nodes.iter_mut().find(|n| n.id == node_id) {
if existing.last_request.elapsed() > Duration::from_secs(60) {
existing.last_request = Instant::now();
return true;
}
return false;
}
closest_nodes.push(MaybeUsefulNode {
id: node_id,
addr,
last_request: Instant::now(),
last_response: None,
returned_peers: false,
2023-11-29 18:22:00 +00:00
errors_in_a_row: 0,
});
const LIMIT: usize = 256;
closest_nodes.sort_by_key(|n| {
let has_returned_peers_desc = Reverse(n.returned_peers);
let has_responded_desc = Reverse(n.last_response.is_some() as u8);
let distance = n.id.distance(&self.info_hash);
(has_returned_peers_desc, has_responded_desc, distance)
});
if closest_nodes.len() > LIMIT {
let popped = closest_nodes.pop().unwrap();
if popped.id == node_id {
return false;
}
}
true
}
}
2023-11-28 08:03:12 +00:00
pub struct DhtState {
2021-07-12 19:42:48 +01:00
id: Id20,
2023-11-28 07:40:27 +00:00
next_transaction_id: AtomicU16,
2023-11-27 19:03:39 +00:00
// Created requests: (transaction_id, addr) => Requests.
// If we get a response, it gets removed from here.
inflight_by_transaction_id: DashMap<(u16, SocketAddr), OutstandingRequest>,
2023-11-27 19:03:39 +00:00
2023-11-28 08:03:12 +00:00
routing_table: RwLock<RoutingTable>,
2021-07-18 15:53:23 +01:00
listen_addr: SocketAddr,
2021-07-13 16:28:53 +01:00
// Sending requests to the worker.
rate_limiter: RateLimiter,
2023-11-28 15:55:13 +00:00
sender: UnboundedSender<WorkerSendRequest>,
2021-07-12 19:42:48 +01:00
}
impl DhtState {
2023-11-28 08:03:12 +00:00
fn new_internal(
2021-07-18 10:53:33 +01:00
id: Id20,
2023-11-28 15:55:13 +00:00
sender: UnboundedSender<WorkerSendRequest>,
2021-07-18 10:53:33 +01:00
routing_table: Option<RoutingTable>,
2021-07-18 15:53:23 +01:00
listen_addr: SocketAddr,
2021-07-18 10:53:33 +01:00
) -> Self {
let routing_table = routing_table.unwrap_or_else(|| RoutingTable::new(id));
2021-07-12 19:42:48 +01:00
Self {
id,
2023-11-28 07:40:27 +00:00
next_transaction_id: AtomicU16::new(0),
inflight_by_transaction_id: Default::default(),
2023-11-28 08:03:12 +00:00
routing_table: RwLock::new(routing_table),
2021-07-12 19:42:48 +01:00
sender,
2021-07-18 15:53:23 +01:00
listen_addr,
rate_limiter: make_rate_limiter(),
2021-07-12 19:42:48 +01:00
}
}
async fn request(&self, request: Request, addr: SocketAddr) -> anyhow::Result<ResponseOrError> {
self.rate_limiter.acquire_one().await;
2023-11-28 15:55:13 +00:00
let (tid, message) = self.create_request(request);
let key = (tid, addr);
2023-11-28 08:56:27 +00:00
let (tx, rx) = tokio::sync::oneshot::channel();
self.inflight_by_transaction_id
.insert(key, OutstandingRequest { done: tx });
2023-11-28 15:55:13 +00:00
match self.sender.send(WorkerSendRequest {
our_tid: Some(tid),
message,
addr,
}) {
2023-11-28 08:56:27 +00:00
Ok(_) => {}
Err(e) => {
self.inflight_by_transaction_id.remove(&key);
2023-11-28 08:56:27 +00:00
return Err(e.into());
}
};
match tokio::time::timeout(RESPONSE_TIMEOUT, rx).await {
Ok(Ok(r)) => r,
Ok(Err(e)) => {
self.inflight_by_transaction_id.remove(&key);
warn!("recv error, did not expect this: {:?}", e);
Err(e.into())
}
Err(_) => {
self.inflight_by_transaction_id.remove(&key);
bail!("timeout")
}
}
2023-11-28 07:40:27 +00:00
}
2023-11-28 08:03:12 +00:00
fn create_request(&self, request: Request) -> (u16, Message<ByteString>) {
2023-11-28 07:40:27 +00:00
let transaction_id = self.next_transaction_id.fetch_add(1, Ordering::Relaxed);
2021-07-12 19:42:48 +01:00
let transaction_id_buf = [(transaction_id >> 8) as u8, (transaction_id & 0xff) as u8];
2023-04-23 17:55:52 +02:00
2021-07-12 19:42:48 +01:00
let message = match request {
Request::GetPeers(info_hash) => Message {
transaction_id: ByteString::from(transaction_id_buf.as_ref()),
version: None,
ip: None,
kind: MessageKind::GetPeersRequest(GetPeersRequest {
id: self.id,
info_hash,
}),
},
Request::FindNode(target) => Message {
transaction_id: ByteString::from(transaction_id_buf.as_ref()),
version: None,
ip: None,
kind: MessageKind::FindNodeRequest(FindNodeRequest {
id: self.id,
target,
}),
},
2023-11-27 18:53:20 +00:00
Request::Ping => Message {
transaction_id: ByteString::from(transaction_id_buf.as_ref()),
version: None,
ip: None,
kind: MessageKind::PingRequest(PingRequest { id: self.id }),
},
2021-07-12 19:42:48 +01:00
};
2023-11-28 07:40:27 +00:00
(transaction_id, message)
2021-07-12 19:42:48 +01:00
}
2023-11-27 19:03:39 +00:00
fn on_received_message(
2023-11-28 08:03:12 +00:00
self: &Arc<Self>,
2021-07-12 19:42:48 +01:00
msg: Message<ByteString>,
addr: SocketAddr,
) -> anyhow::Result<()> {
2021-07-13 18:27:32 +01:00
let generate_compact_nodes = |target| {
let nodes = self
.routing_table
2023-11-28 08:03:12 +00:00
.read()
2021-07-13 18:27:32 +01:00
.sorted_by_distance_from(target)
.into_iter()
.filter_map(|r| {
Some(Node {
id: r.id(),
addr: match r.addr() {
SocketAddr::V4(v4) => v4,
SocketAddr::V6(_) => return None,
},
})
})
.take(8)
.collect::<Vec<_>>();
CompactNodeInfo { nodes }
};
2021-07-12 19:42:48 +01:00
match &msg.kind {
// If it's a response to a request we made, find the request task, notify it with the response,
// and let it handle it.
2021-07-14 00:06:09 +01:00
MessageKind::Error(_) | MessageKind::Response(_) => {
let tid = msg.get_our_transaction_id().context("bad transaction id")?;
let request = match self
.inflight_by_transaction_id
.remove(&(tid, addr))
.map(|(_, v)| v)
{
2021-07-14 00:48:53 +01:00
Some(req) => req,
None => bail!("outstanding request not found. Message: {:?}", msg),
2021-07-14 00:48:53 +01:00
};
let response_or_error = match msg.kind {
MessageKind::Error(e) => ResponseOrError::Error(e),
MessageKind::Response(r) => ResponseOrError::Response(r),
2021-07-14 00:06:09 +01:00
_ => unreachable!(),
};
match request.done.send(Ok(response_or_error)) {
Ok(_) => {}
Err(e) => {
debug!(
"recieved response, but the receiver task is closed: {:?}",
e
);
}
}
Ok(())
2021-07-14 00:06:09 +01:00
}
// Otherwise, respond to a query.
MessageKind::PingRequest(req) => {
2021-07-12 19:42:48 +01:00
let message = Message {
transaction_id: msg.transaction_id,
version: None,
ip: None,
2021-07-14 00:48:53 +01:00
kind: MessageKind::Response(bprotocol::Response {
id: self.id,
..Default::default()
}),
2021-07-12 19:42:48 +01:00
};
self.routing_table.write().mark_last_query(&req.id);
2023-11-28 15:55:13 +00:00
self.sender.send(WorkerSendRequest {
our_tid: None,
message,
addr,
})?;
2021-07-14 00:06:09 +01:00
Ok(())
2021-07-12 19:42:48 +01:00
}
2021-07-13 18:27:32 +01:00
MessageKind::GetPeersRequest(req) => {
// let peers = self.info_hash_meta.get(&req.info_hash).map(|meta| {
// meta.seen_peers
// .iter()
// .copied()
// .filter_map(|a| match a {
// SocketAddr::V4(v4) => Some(CompactPeerInfo { addr: v4 }),
// // this should never happen in practice
// SocketAddr::V6(_) => None,
// })
// .take(50)
// .collect::<Vec<_>>()
// });
// let token = if peers.is_some() {
// let mut token = [0u8; 20];
// rand::thread_rng().fill(&mut token);
// Some(ByteString::from(token.as_ref()))
// } else {
// None
// };
// let compact_node_info = generate_compact_nodes(req.info_hash);
2023-11-28 08:03:12 +00:00
self.routing_table.write().mark_last_query(&req.id);
2021-07-13 18:27:32 +01:00
let message = Message {
transaction_id: msg.transaction_id,
version: None,
ip: None,
2021-07-14 00:48:53 +01:00
kind: MessageKind::Response(bprotocol::Response {
id: self.id,
nodes: None,
values: None,
token: None,
2021-07-14 00:48:53 +01:00
}),
2021-07-13 18:27:32 +01:00
};
2023-11-28 15:55:13 +00:00
self.sender.send(WorkerSendRequest {
our_tid: None,
message,
addr,
})?;
2021-07-14 00:06:09 +01:00
Ok(())
2021-07-13 18:27:32 +01:00
}
MessageKind::FindNodeRequest(req) => {
let compact_node_info = generate_compact_nodes(req.target);
2023-11-28 08:03:12 +00:00
self.routing_table.write().mark_last_query(&req.id);
2021-07-12 19:42:48 +01:00
let message = Message {
transaction_id: msg.transaction_id,
version: None,
ip: None,
2021-07-14 00:48:53 +01:00
kind: MessageKind::Response(bprotocol::Response {
id: self.id,
nodes: Some(compact_node_info),
..Default::default()
}),
2021-07-12 19:42:48 +01:00
};
2023-11-28 15:55:13 +00:00
self.sender.send(WorkerSendRequest {
our_tid: None,
message,
addr,
})?;
2021-07-14 00:06:09 +01:00
Ok(())
2021-07-12 19:42:48 +01:00
}
}
}
2021-07-14 00:48:53 +01:00
pub fn get_stats(&self) -> DhtStats {
DhtStats {
id: self.id,
outstanding_requests: self.inflight_by_transaction_id.len(),
2023-11-28 08:03:12 +00:00
routing_table_size: self.routing_table.read().len(),
2021-07-14 00:48:53 +01:00
}
}
2023-11-28 08:03:12 +00:00
fn routing_table_add_node(self: &Arc<Self>, id: Id20, addr: SocketAddr) -> InsertResult {
2023-11-27 18:53:20 +00:00
let mut questionable_nodes = Vec::new();
2023-11-28 08:03:12 +00:00
let res = self.routing_table.write().add_node(id, addr, |addr| {
2023-11-27 18:53:20 +00:00
questionable_nodes.push(addr);
true
});
for addr in questionable_nodes {
2023-11-29 19:34:29 +00:00
let (_, req) = self.create_request(Request::Ping);
let _ = self.sender.send(WorkerSendRequest {
our_tid: None,
message: req,
addr,
});
2023-11-27 18:53:20 +00:00
}
res
}
2021-07-12 19:42:48 +01:00
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Request {
GetPeers(Id20),
FindNode(Id20),
2023-11-27 18:53:20 +00:00
Ping,
2021-07-12 19:42:48 +01:00
}
#[derive(Debug)]
enum ResponseOrError {
Response(Response<ByteString>),
Error(ErrorDescription<ByteString>),
}
2021-07-12 19:42:48 +01:00
struct DhtWorker {
socket: UdpSocket,
dht: Arc<DhtState>,
2021-07-12 19:42:48 +01:00
}
impl DhtWorker {
fn on_send_error(&self, tid: u16, addr: SocketAddr, err: anyhow::Error) {
if let Some((_, OutstandingRequest { done })) =
self.dht.inflight_by_transaction_id.remove(&(tid, addr))
{
let _ = done.send(Err(err)).is_err();
};
}
async fn bootstrap_hostname(&self, hostname: &str) -> anyhow::Result<()> {
RecursiveRequest::bootstrap(self.dht.clone(), self.dht.id, hostname)
.instrument(error_span!("bootstrap", hostname = hostname))
.await
}
async fn bootstrap_hostname_with_backoff(&self, addr: &str) -> anyhow::Result<()> {
let mut backoff = ExponentialBackoffBuilder::new()
.with_initial_interval(Duration::from_secs(10))
.with_multiplier(1.5)
.with_max_interval(Duration::from_secs(60))
.with_max_elapsed_time(Some(Duration::from_secs(86400)))
.build();
loop {
let backoff = match self.bootstrap_hostname(addr).await {
Ok(_) => return Ok(()),
Err(e) => {
warn!("error: {}", e);
backoff.next_backoff()
}
};
if let Some(backoff) = backoff {
tokio::time::sleep(backoff).await;
continue;
}
bail!("bootstrap failed")
}
}
async fn bootstrap(&self, bootstrap_addrs: &[String]) -> anyhow::Result<()> {
let mut futs = FuturesUnordered::new();
for addr in bootstrap_addrs.iter() {
futs.push(self.bootstrap_hostname_with_backoff(addr));
}
let mut successes = 0;
while let Some(resp) = futs.next().await {
if resp.is_ok() {
successes += 1
}
}
if successes == 0 {
bail!("bootstrapping failed")
}
Ok(())
}
async fn framer(
&self,
socket: &UdpSocket,
2023-11-28 15:55:13 +00:00
mut input_rx: UnboundedReceiver<WorkerSendRequest>,
output_tx: Sender<(Message<ByteString>, SocketAddr)>,
) -> anyhow::Result<()> {
let writer = async {
let mut buf = Vec::new();
2023-11-28 15:55:13 +00:00
while let Some(WorkerSendRequest {
our_tid,
message,
addr,
}) = input_rx.recv().await
{
trace!("{}: sending {:?}", addr, &message);
buf.clear();
bprotocol::serialize_message(
&mut buf,
2023-11-28 15:55:13 +00:00
message.transaction_id,
message.version,
message.ip,
message.kind,
)
.unwrap();
if let Err(e) = socket.send_to(&buf, addr).await {
debug!("error sending to {addr}: {e:?}");
2023-11-28 15:55:13 +00:00
if let Some(tid) = our_tid {
self.on_send_error(tid, addr, e.into());
}
}
}
Err::<(), _>(anyhow::anyhow!(
"DHT UDP socket writer over, nowhere to read messages from"
))
};
let reader = async {
let mut buf = vec![0u8; 16384];
loop {
let (size, addr) = socket
.recv_from(&mut buf)
.await
.context("error reading from UDP socket")?;
match bprotocol::deserialize_message::<ByteString>(&buf[..size]) {
Ok(msg) => {
trace!("{}: received {:?}", addr, &msg);
match output_tx.send((msg, addr)).await {
Ok(_) => {}
Err(_) => break,
}
}
Err(e) => debug!("{}: error deserializing incoming message: {}", addr, e),
}
}
Err::<(), _>(anyhow::anyhow!(
"DHT UDP socket reader over, nowhere to send responses to"
))
};
let result = tokio::select! {
err = writer => err,
err = reader => err,
};
result.context("DHT UDP framer closed")
}
2021-07-12 19:42:48 +01:00
async fn start(
self,
2023-11-28 15:55:13 +00:00
in_rx: UnboundedReceiver<WorkerSendRequest>,
2021-07-12 19:42:48 +01:00
bootstrap_addrs: &[String],
) -> anyhow::Result<()> {
let (out_tx, mut out_rx) = channel(1);
let framer = self
.framer(&self.socket, in_rx, out_tx)
.instrument(debug_span!("dht_framer"));
2021-07-12 19:42:48 +01:00
let bootstrap = self.bootstrap(bootstrap_addrs);
2021-07-12 19:42:48 +01:00
let mut bootstrap_done = false;
let response_reader = {
let this = &self;
async move {
while let Some((response, addr)) = out_rx.recv().await {
if let Err(e) = this.dht.on_received_message(response, addr) {
2021-07-12 19:42:48 +01:00
debug!("error in on_response, addr={:?}: {}", addr, e)
}
}
Err::<(), _>(anyhow::anyhow!(
"closed response reader, nowhere to send results to, DHT closed"
))
}
2023-11-25 15:15:16 +00:00
}
.instrument(debug_span!("dht_responese_reader"));
2021-07-12 19:42:48 +01:00
tokio::pin!(framer);
tokio::pin!(bootstrap);
tokio::pin!(response_reader);
loop {
tokio::select! {
err = &mut framer => {
anyhow::bail!("framer quit: {:?}", err)
},
result = &mut bootstrap, if !bootstrap_done => {
bootstrap_done = true;
result?;
},
err = &mut response_reader => {anyhow::bail!("response reader quit: {:?}", err)}
}
}
}
}
2021-07-18 10:53:33 +01:00
#[derive(Default)]
pub struct DhtConfig {
pub peer_id: Option<Id20>,
pub bootstrap_addrs: Option<Vec<String>>,
pub routing_table: Option<RoutingTable>,
2021-07-18 15:53:23 +01:00
pub listen_addr: Option<SocketAddr>,
2021-07-18 10:53:33 +01:00
}
2023-11-28 08:03:12 +00:00
impl DhtState {
pub async fn new() -> anyhow::Result<Arc<Self>> {
2021-07-18 10:53:33 +01:00
Self::with_config(DhtConfig::default()).await
2021-07-12 21:59:08 +01:00
}
2023-11-28 08:03:12 +00:00
pub async fn with_config(config: DhtConfig) -> anyhow::Result<Arc<Self>> {
2021-07-18 15:53:23 +01:00
let socket = match config.listen_addr {
Some(addr) => UdpSocket::bind(addr)
.await
2022-12-07 22:01:29 +00:00
.with_context(|| format!("error binding socket, address {addr}")),
None => UdpSocket::bind("0.0.0.0:0")
.await
.context("error binding socket, address 0.0.0.0:0"),
}?;
2021-07-18 15:53:23 +01:00
let listen_addr = socket
.local_addr()
.context("cannot determine UDP listen addr")?;
info!("DHT listening on {:?}", listen_addr);
2021-07-18 10:53:33 +01:00
let peer_id = config.peer_id.unwrap_or_else(generate_peer_id);
2021-07-12 19:42:48 +01:00
info!("starting up DHT with peer id {:?}", peer_id);
2021-07-18 10:53:33 +01:00
let bootstrap_addrs = config
.bootstrap_addrs
.unwrap_or_else(|| crate::DHT_BOOTSTRAP.iter().map(|v| v.to_string()).collect());
2021-07-12 19:42:48 +01:00
2021-07-13 16:10:36 +01:00
let (in_tx, in_rx) = unbounded_channel();
2023-11-28 08:03:12 +00:00
let state = Arc::new(Self::new_internal(
2021-07-18 10:53:33 +01:00
peer_id,
2023-11-28 07:40:27 +00:00
in_tx,
2021-07-18 10:53:33 +01:00
config.routing_table,
2021-07-18 15:53:23 +01:00
listen_addr,
2023-11-28 08:03:12 +00:00
));
2021-07-13 16:10:36 +01:00
2023-11-25 15:15:16 +00:00
spawn(error_span!("dht"), {
2021-07-13 16:10:36 +01:00
let state = state.clone();
async move {
let worker = DhtWorker { socket, dht: state };
2023-11-28 07:40:27 +00:00
worker.start(in_rx, &bootstrap_addrs).await?;
2023-11-25 15:15:16 +00:00
Ok(())
2021-07-13 16:10:36 +01:00
}
2021-07-12 19:42:48 +01:00
});
2023-11-28 08:03:12 +00:00
Ok(state)
2021-07-12 19:42:48 +01:00
}
2023-11-24 14:19:39 +00:00
pub fn get_peers(
2023-11-28 08:03:12 +00:00
self: &Arc<Self>,
2021-07-13 16:10:36 +01:00
info_hash: Id20,
2021-07-14 15:29:59 +01:00
) -> anyhow::Result<impl Stream<Item = SocketAddr> + Unpin> {
Ok(RequestPeersStream::new(self.clone(), info_hash))
2021-07-12 19:42:48 +01:00
}
2021-07-14 00:48:53 +01:00
2021-07-18 15:53:23 +01:00
pub fn listen_addr(&self) -> SocketAddr {
2023-11-28 08:03:12 +00:00
self.listen_addr
2021-07-18 15:53:23 +01:00
}
2021-07-14 00:48:53 +01:00
pub fn stats(&self) -> DhtStats {
2023-11-28 08:03:12 +00:00
self.get_stats()
2021-07-14 00:48:53 +01:00
}
pub fn with_routing_table<R, F: FnOnce(&RoutingTable) -> R>(&self, f: F) -> R {
2023-11-28 08:03:12 +00:00
f(&self.routing_table.read())
2021-07-14 00:48:53 +01:00
}
pub fn clone_routing_table(&self) -> RoutingTable {
2023-11-28 08:03:12 +00:00
self.routing_table.read().clone()
2021-07-14 00:48:53 +01:00
}
2021-07-12 19:42:48 +01:00
}