#![allow(unused)]
use std::iter::Filter;
use std::net::{Ipv4Addr, SocketAddrV4, SocketAddr};
use std::slice::Iter;
use bip_util::bt::{self, NodeId};
use routing::node::{Node, NodeStatus};
pub const MAX_BUCKET_SIZE: usize = 8;
pub struct Bucket {
nodes: [Node; MAX_BUCKET_SIZE],
}
impl Bucket {
pub fn new() -> Bucket {
let id = NodeId::from([0u8; bt::NODE_ID_LEN]);
let ip = Ipv4Addr::new(127, 0, 0, 1);
let addr = SocketAddr::V4(SocketAddrV4::new(ip, 0));
Bucket {
nodes: [Node::as_bad(id, addr),
Node::as_bad(id, addr),
Node::as_bad(id, addr),
Node::as_bad(id, addr),
Node::as_bad(id, addr),
Node::as_bad(id, addr),
Node::as_bad(id, addr),
Node::as_bad(id, addr)],
}
}
pub fn good_nodes<'a>(&'a self) -> GoodNodes<'a> {
GoodNodes::new(&self.nodes)
}
pub fn pingable_nodes<'a>(&'a self) -> PingableNodes<'a> {
PingableNodes::new(&self.nodes)
}
pub fn iter(&self) -> Iter<Node> {
self.nodes.iter()
}
pub fn needs_refresh(&self) -> bool {
self.nodes.iter().fold(true, |prev, node| prev && node.status() != NodeStatus::Good)
}
pub fn add_node(&mut self, new_node: Node) -> bool {
let new_node_status = new_node.status();
if new_node_status == NodeStatus::Bad {
return true;
}
if let Some(index) = self.nodes.iter().position(|node| *node == new_node) {
let other_node_status = self.nodes[index].status();
if new_node_status >= other_node_status {
self.nodes[index] = new_node;
}
return true;
}
let replace_index = self.nodes.iter().position(|node| node.status() < new_node_status);
if let Some(index) = replace_index {
self.nodes[index] = new_node;
true
} else {
false
}
}
}
pub struct GoodNodes<'a> {
iter: Filter<Iter<'a, Node>, fn(&&Node) -> bool>,
}
impl<'a> GoodNodes<'a> {
fn new(nodes: &'a [Node]) -> GoodNodes<'a> {
GoodNodes { iter: nodes.iter().filter(good_nodes_filter) }
}
}
fn good_nodes_filter(node: &&Node) -> bool {
node.status() == NodeStatus::Good
}
impl<'a> Iterator for GoodNodes<'a> {
type Item = &'a Node;
fn next(&mut self) -> Option<&'a Node> {
self.iter.next()
}
}
pub struct PingableNodes<'a> {
iter: Filter<Iter<'a, Node>, fn(&&Node) -> bool>,
}
impl<'a> PingableNodes<'a> {
fn new(nodes: &'a [Node]) -> PingableNodes<'a> {
PingableNodes { iter: nodes.iter().filter(pingable_nodes_filter) }
}
}
fn pingable_nodes_filter(node: &&Node) -> bool {
let status = node.status();
status == NodeStatus::Good || status == NodeStatus::Questionable
}
impl<'a> Iterator for PingableNodes<'a> {
type Item = &'a Node;
fn next(&mut self) -> Option<&'a Node> {
self.iter.next()
}
}
#[cfg(test)]
mod tests {
use bip_util::sha::{self, ShaHash};
use bip_util::test as bip_test;
use routing::bucket::{self, Bucket};
use routing::node::{Node, NodeStatus};
#[test]
fn positive_initial_no_nodes() {
let bucket = Bucket::new();
assert_eq!(bucket.good_nodes().count(), 0);
assert_eq!(bucket.pingable_nodes().count(), 0);
}
#[test]
fn positive_all_questionable_nodes() {
let mut bucket = Bucket::new();
let dummy_addr = bip_test::dummy_socket_addr_v4();
let dummy_ids = bip_test::dummy_block_node_ids(super::MAX_BUCKET_SIZE as u8);
for index in 0..super::MAX_BUCKET_SIZE {
let node = Node::as_questionable(dummy_ids[index], dummy_addr);
bucket.add_node(node);
}
assert_eq!(bucket.good_nodes().count(), 0);
assert_eq!(bucket.pingable_nodes().count(), super::MAX_BUCKET_SIZE);
}
#[test]
fn positive_all_good_nodes() {
let mut bucket = Bucket::new();
let dummy_addr = bip_test::dummy_socket_addr_v4();
let dummy_ids = bip_test::dummy_block_node_ids(super::MAX_BUCKET_SIZE as u8);
for index in 0..super::MAX_BUCKET_SIZE {
let node = Node::as_good(dummy_ids[index], dummy_addr);
bucket.add_node(node);
}
assert_eq!(bucket.good_nodes().count(), super::MAX_BUCKET_SIZE);
assert_eq!(bucket.pingable_nodes().count(), super::MAX_BUCKET_SIZE);
}
#[test]
fn positive_replace_questionable_node() {
let mut bucket = Bucket::new();
let dummy_addr = bip_test::dummy_socket_addr_v4();
let dummy_ids = bip_test::dummy_block_node_ids(super::MAX_BUCKET_SIZE as u8);
for index in 0..super::MAX_BUCKET_SIZE {
let node = Node::as_questionable(dummy_ids[index], dummy_addr);
bucket.add_node(node);
}
assert_eq!(bucket.good_nodes().count(), 0);
assert_eq!(bucket.pingable_nodes().count(), super::MAX_BUCKET_SIZE);
let good_node = Node::as_good(dummy_ids[0], dummy_addr);
bucket.add_node(good_node.clone());
assert_eq!(bucket.good_nodes().next().unwrap(), &good_node);
assert_eq!(bucket.good_nodes().count(), 1);
assert_eq!(bucket.pingable_nodes().count(), super::MAX_BUCKET_SIZE);
}
#[test]
fn positive_resist_good_node_churn() {
let mut bucket = Bucket::new();
let dummy_addr = bip_test::dummy_socket_addr_v4();
let dummy_ids = bip_test::dummy_block_node_ids((super::MAX_BUCKET_SIZE as u8) + 1);
for index in 0..super::MAX_BUCKET_SIZE {
let node = Node::as_good(dummy_ids[index], dummy_addr);
bucket.add_node(node);
}
assert_eq!(bucket.good_nodes().count(), super::MAX_BUCKET_SIZE);
let unused_id = dummy_ids[dummy_ids.len() - 1];
let new_good_node = Node::as_good(unused_id, dummy_addr);
assert!(bucket.good_nodes().find(|node| &&new_good_node == node).is_none());
bucket.add_node(new_good_node.clone());
assert!(bucket.good_nodes().find(|node| &&new_good_node == node).is_none());
}
#[test]
fn positive_resist_questionable_node_churn() {
let mut bucket = Bucket::new();
let dummy_addr = bip_test::dummy_socket_addr_v4();
let dummy_ids = bip_test::dummy_block_node_ids((super::MAX_BUCKET_SIZE as u8) + 1);
for index in 0..super::MAX_BUCKET_SIZE {
let node = Node::as_questionable(dummy_ids[index], dummy_addr);
bucket.add_node(node);
}
assert_eq!(bucket.pingable_nodes()
.filter(|node| node.status() == NodeStatus::Questionable)
.count(),
super::MAX_BUCKET_SIZE);
let unused_id = dummy_ids[dummy_ids.len() - 1];
let new_questionable_node = Node::as_questionable(unused_id, dummy_addr);
assert!(bucket.pingable_nodes().find(|node| &&new_questionable_node == node).is_none());
bucket.add_node(new_questionable_node.clone());
assert_eq!(bucket.pingable_nodes()
.filter(|node| node.status() == NodeStatus::Questionable)
.count(),
super::MAX_BUCKET_SIZE);
}
}