Skip to content

Commit

Permalink
Merge pull request #53 from Nuhvi/main
Browse files Browse the repository at this point in the history
update to 5.3.1
  • Loading branch information
Nuhvi authored Feb 22, 2025
2 parents c95b502 + 5b1d83f commit 1ef76c3
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 48 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mainline"
version = "5.2.1"
version = "5.3.1"
authors = ["nuh.dev"]
edition = "2021"
description = "Simple, robust, BitTorrent's Mainline DHT implementation"
Expand All @@ -12,7 +12,7 @@ repository = "https://github.com/pubky/mainline"
exclude = ["/docs/*", "/examples/*"]

[dependencies]
rand = "0.9.0"
getrandom = "0.2"
serde_bencode = "^0.2.4"
serde = { version = "1.0.217", features = ["derive"] }
serde_bytes = "0.11.15"
Expand Down
18 changes: 7 additions & 11 deletions src/common/id.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Kademlia node Id or a lookup target
use crc::{Crc, CRC_32_ISCSI};
use rand::random;
use getrandom::getrandom;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
use std::{
Expand All @@ -23,7 +23,8 @@ pub struct Id([u8; ID_SIZE]);
impl Id {
/// Generate a random Id
pub fn random() -> Id {
let bytes: [u8; 20] = random();
let mut bytes: [u8; 20] = [0; 20];
getrandom::getrandom(&mut bytes).expect("getrandom");

Id(bytes)
}
Expand Down Expand Up @@ -89,23 +90,18 @@ impl Id {

/// Create a new Id from an Ipv4 address according to [BEP_0042](http://bittorrent.org/beps/bep_0042.html).
pub fn from_ip(ip: IpAddr) -> Id {
let r: u8 = random();

let bytes: [u8; 20] = random();

match ip {
IpAddr::V4(addr) => from_ipv4_and_r(bytes, addr, r),
IpAddr::V4(addr) => Id::from_ipv4(addr),
IpAddr::V6(_addr) => unimplemented!("Ipv6 is not supported"),
}
}

/// Create a new Id from an Ipv4 address according to [BEP_0042](http://bittorrent.org/beps/bep_0042.html).
pub fn from_ipv4(ipv4: Ipv4Addr) -> Id {
let r: u8 = random();

let bytes: [u8; 20] = random();
let mut bytes = [0_u8; 21];
getrandom(&mut bytes).expect("getrandom");

from_ipv4_and_r(bytes, ipv4, r)
from_ipv4_and_r(bytes[1..].try_into().expect("infallible"), ipv4, bytes[0])
}

/// Validate that this Id is valid with respect to [BEP_0042](http://bittorrent.org/beps/bep_0042.html).
Expand Down
15 changes: 10 additions & 5 deletions src/dht.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ use crate::{
GetPeersRequestArguments, GetValueRequestArguments, Id, MutableItem,
PutImmutableRequestArguments, PutMutableRequestArguments, PutRequestSpecific,
},
rpc::{ConcurrencyError, GetRequestSpecific, Info, PutError, PutQueryError, Response, Rpc},
rpc::{
to_socket_address, ConcurrencyError, GetRequestSpecific, Info, PutError, PutQueryError,
Response, Rpc,
},
Node, ServerSettings,
};

use crate::rpc::config::{to_socket_address, Config};
use crate::rpc::config::Config;

#[derive(Debug, Clone)]
/// Mainline Dht node.
Expand Down Expand Up @@ -50,7 +53,7 @@ impl DhtBuilder {

/// Set bootstrapping nodes.
pub fn bootstrap<T: ToSocketAddrs>(&mut self, bootstrap: &[T]) -> &mut Self {
self.0.bootstrap = to_socket_address(bootstrap);
self.0.bootstrap = Some(to_socket_address(bootstrap));

self
}
Expand All @@ -60,16 +63,18 @@ impl DhtBuilder {
/// Useful when you want to augment the default bootstrapping nodes with
/// dynamic list of nodes you have seen in previous sessions.
pub fn extra_bootstrap<T: ToSocketAddrs>(&mut self, extra_bootstrap: &[T]) -> &mut Self {
let mut bootstrap = self.0.bootstrap.clone().unwrap_or_default();
for address in to_socket_address(extra_bootstrap) {
self.0.bootstrap.push(address);
bootstrap.push(address);
}
self.0.bootstrap = Some(bootstrap);

self
}

/// Remove the existing bootstrapping nodes, usually to create the first node in a new network.
pub fn no_bootstrap(&mut self) -> &mut Self {
self.0.bootstrap = vec![];
self.0.bootstrap = Some(vec![]);

self
}
Expand Down
24 changes: 22 additions & 2 deletions src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub(crate) mod server;
mod socket;

use std::collections::HashMap;
use std::net::SocketAddrV4;
use std::net::{SocketAddr, SocketAddrV4, ToSocketAddrs};
use std::num::NonZeroUsize;
use std::time::{Duration, Instant};

Expand Down Expand Up @@ -108,7 +108,10 @@ impl Rpc {
let socket = KrpcSocket::new(&config)?;

Ok(Rpc {
bootstrap: config.bootstrap.into(),
bootstrap: config
.bootstrap
.unwrap_or(to_socket_address(&DEFAULT_BOOTSTRAP_NODES))
.into(),
socket,

routing_table: RoutingTable::new(id),
Expand Down Expand Up @@ -920,3 +923,20 @@ pub enum Response {
Immutable(Box<[u8]>),
Mutable(MutableItem),
}

pub(crate) fn to_socket_address<T: ToSocketAddrs>(bootstrap: &[T]) -> Vec<SocketAddrV4> {
bootstrap
.iter()
.flat_map(|s| {
s.to_socket_addrs().map(|addrs| {
addrs
.filter_map(|addr| match addr {
SocketAddr::V4(addr_v4) => Some(addr_v4),
_ => None,
})
.collect::<Box<[_]>>()
})
})
.flatten()
.collect()
}
29 changes: 6 additions & 23 deletions src/rpc/config.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use std::{
net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs},
net::{Ipv4Addr, SocketAddrV4},
time::Duration,
};

use super::{ServerSettings, DEFAULT_BOOTSTRAP_NODES, DEFAULT_REQUEST_TIMEOUT};
use super::{ServerSettings, DEFAULT_REQUEST_TIMEOUT};

#[derive(Debug, Clone)]
/// Dht Configurations
pub struct Config {
/// Bootstrap nodes
///
/// Defaults to [DEFAULT_BOOTSTRAP_NODES]
pub bootstrap: Vec<SocketAddrV4>,
/// Defaults to [super::DEFAULT_BOOTSTRAP_NODES]
pub bootstrap: Option<Vec<SocketAddrV4>>,
/// Explicit port to listen on.
///
/// Defaults to None
Expand All @@ -26,7 +26,7 @@ pub struct Config {
pub request_timeout: Duration,
/// Server to respond to incoming Requests
pub server_settings: ServerSettings,
/// Wether or not to start in server mode from the get go.
/// Whether or not to start in server mode from the get go.
///
/// Defaults to false where it will run in [Adaptive mode](https://github.com/pubky/mainline?tab=readme-ov-file#adaptive-mode).
pub server_mode: bool,
Expand All @@ -40,7 +40,7 @@ pub struct Config {
impl Default for Config {
fn default() -> Self {
Self {
bootstrap: to_socket_address(&DEFAULT_BOOTSTRAP_NODES),
bootstrap: None,
port: None,
request_timeout: DEFAULT_REQUEST_TIMEOUT,
server_settings: Default::default(),
Expand All @@ -49,20 +49,3 @@ impl Default for Config {
}
}
}

pub(crate) fn to_socket_address<T: ToSocketAddrs>(bootstrap: &[T]) -> Vec<SocketAddrV4> {
bootstrap
.iter()
.flat_map(|s| {
s.to_socket_addrs().map(|addrs| {
addrs
.filter_map(|addr| match addr {
SocketAddr::V4(addr_v4) => Some(addr_v4),
_ => None,
})
.collect::<Box<[_]>>()
})
})
.flatten()
.collect()
}
17 changes: 13 additions & 4 deletions src/rpc/server/peers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
use std::{net::SocketAddrV4, num::NonZeroUsize};

use rand::random_bool;

use crate::common::Id;

use getrandom::getrandom;
use lru::LruCache;

const CHANCE_SCALE: f32 = 2.0 * (1u32 << 31) as f32;

#[derive(Debug, Clone)]
/// An LRU cache of "Peers" per info hashes.
///
Expand Down Expand Up @@ -57,14 +58,22 @@ impl PeersStore {

let mut results = Vec::with_capacity(20);

let mut chunk = vec![0_u8; info_hash_lru.iter().len() * 4];
getrandom(chunk.as_mut_slice()).expect("getrandom");

for (index, (_, addr)) in info_hash_lru.iter().enumerate() {
// Calculate the chance of adding the current item based on remaining items and slots
let remaining_slots = target_size - results.len();
let remaining_items = info_hash_lru.len() - index;
let current_chance = remaining_slots as f64 / remaining_items as f64;
let current_chance =
((remaining_slots as f32 / remaining_items as f32) * CHANCE_SCALE) as u32;

// Get random integer from the chunk
let rand_int =
u32::from_le_bytes(chunk[index..index + 4].try_into().expect("infallible"));

// Randomly decide to add the item based on the current chance
if random_bool(current_chance) {
if rand_int < current_chance {
results.push(*addr);
if results.len() == target_size {
break;
Expand Down
9 changes: 8 additions & 1 deletion src/rpc/server/tokens.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Manage tokens for remote client IPs.
use crc::{Crc, CRC_32_ISCSI};
use rand::random;
use getrandom::getrandom;
use std::{
fmt::{self, Debug, Formatter},
net::SocketAddrV4,
Expand Down Expand Up @@ -96,6 +96,13 @@ impl Default for Tokens {
}
}

fn random() -> [u8; SECRET_SIZE] {
let mut bytes = [0_u8; SECRET_SIZE];
getrandom(&mut bytes).expect("getrandom");

bytes
}

#[cfg(test)]
mod test {

Expand Down

0 comments on commit 1ef76c3

Please # to comment.