mainline/common/
node.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! Struct and implementation of the Node entry in the Kademlia routing table
use std::{
    fmt::{self, Debug, Formatter},
    net::SocketAddr,
    time::{Duration, Instant},
};

use crate::common::Id;

/// The age of a node's last_seen time before it is considered stale and removed from a full bucket
/// on inserting a new node.
pub const STALE_TIME: Duration = Duration::from_secs(15 * 60);
const MIN_PING_BACKOFF_INTERVAL: Duration = Duration::from_secs(10);
pub const TOKEN_ROTATE_INTERVAL: Duration = Duration::from_secs(60 * 5);

#[derive(Clone, PartialEq)]
/// Node entry in Kademlia routing table
pub struct Node {
    pub id: Id,
    pub address: SocketAddr,
    pub token: Option<Vec<u8>>,
    last_seen: Instant,
}

impl Debug for Node {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        fmt.debug_struct("Node")
            .field("id", &self.id)
            .field("address", &self.address)
            .field("last_seen", &self.last_seen.elapsed().as_secs())
            .finish()
    }
}

impl Node {
    /// Creates a new Node from an id and socket address.
    pub fn new(id: Id, address: SocketAddr) -> Node {
        Node {
            id,
            address,
            token: None,
            last_seen: Instant::now(),
        }
    }

    /// Creates a random node for testing purposes.
    #[cfg(test)]
    pub fn random() -> Node {
        Node {
            id: Id::random(),
            address: SocketAddr::from(([0, 0, 0, 0], 0)),
            token: None,
            last_seen: Instant::now(),
        }
    }

    pub fn with_id(mut self, id: Id) -> Self {
        self.id = id;
        self
    }

    pub fn with_address(mut self, address: SocketAddr) -> Self {
        self.address = address;
        self
    }

    pub fn with_token(mut self, token: Vec<u8>) -> Self {
        self.token = Some(token);
        self
    }

    /// Node is last seen more than a threshold ago.
    pub fn is_stale(&self) -> bool {
        self.last_seen.elapsed() > STALE_TIME
    }

    /// Node's token was received 5 minutes ago or less
    pub fn valid_token(&self) -> bool {
        self.last_seen.elapsed() <= TOKEN_ROTATE_INTERVAL
    }

    pub(crate) fn should_ping(&self) -> bool {
        self.last_seen.elapsed() > MIN_PING_BACKOFF_INTERVAL
    }

    /// Returns true if both nodes have the same id and address
    pub fn same_adress(&self, other: &Self) -> bool {
        self.address == other.address
    }

    /// Check [BEP0042](https://www.bittorrent.org/beps/bep_0042.html).
    pub(crate) fn is_secure(&self) -> bool {
        self.id.is_valid_for_ip(&self.address.ip())
    }
}