rlibdht 0.1.0

Rust DHT library
Documentation
use std::net::{IpAddr, SocketAddr};
use std::time::{SystemTime, UNIX_EPOCH};
use std::{cmp, fmt};
use std::fmt::Formatter;
use super::uid::UID;
use super::hash::crc32c::Crc32c;

pub const V4_MASK: [u8; 4] = [0x03, 0x0f, 0x3f, 0xff];
pub const V6_MASK: [u8; 8] = [0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff];
const QUERY_TIME: u128 = 3600000;

#[derive(Debug, Copy, Clone)]
pub struct Node {
    pub(crate) uid: UID,
    pub(crate) address: SocketAddr,
    pub(crate) stale: u32,
    pub(crate) last_seen: u128,
}

impl Node {

    pub fn new(uid: UID, address: SocketAddr) -> Self {
        Self {
            uid,
            address,
            stale: 0,
            last_seen: 0,
        }
    }

    pub fn has_secure_id(&self) -> bool {
        let mut ip: Vec<u8> = match self.address.ip() {
            IpAddr::V4(v4) => v4.octets().to_vec(),
            IpAddr::V6(v6) => v6.octets().to_vec(),
        };

        let mask: Vec<u8> = if ip.len() == 4 {
            V4_MASK.to_vec()
        } else {
            V6_MASK.to_vec()
        };

        for i in 0..mask.len() {
            ip[i] &= mask[i];
        }

        let r = self.uid.bid[19] & 0x7;
        ip[0] |= r << 5;

        let mut c = Crc32c::new();
        c.update(&ip, 0, cmp::min(ip.len(), 8));
        let crc = c.get_value();

        let uid_crc = ((u32::from(self.uid.bid[0]) << 24)
            | (u32::from(self.uid.bid[1]) << 16)
            | (u32::from(self.uid.bid[2]) << 8)
            | u32::from(self.uid.bid[3]))
            ^ crc;

        (uid_crc & 0xff_ff_f8_00) == 0
    }

    pub fn seen(&mut self) {
        self.stale = 0;
        self.last_seen = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .expect("Time went backwards")
            .as_millis();
    }

    pub fn mark_stale(&mut self) {
        self.stale += 1;
    }

    pub fn has_queried(&self, now: u128) -> bool {
        self.last_seen > 0 && now - self.last_seen < QUERY_TIME
    }

    pub fn verify(&self, other: &Self) -> bool {
        self.uid == other.uid
    }
}

impl PartialEq for Node {
    fn eq(&self, other: &Node) -> bool {
        self.address == other.address
    }
}

impl fmt::Display for Node {

    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{{ \x1b[34mUID\x1b[0m: \x1b[35m{}\x1b[0m, \x1b[34mADDRESS\x1b[0m: \x1b[35m{}\x1b[0m, \x1b[34mPORT\x1b[0m: \x1b[35m{}\x1b[0m, \x1b[34mSECURE\x1b[0m: \x1b[35m{}\x1b[0m }}",
                self.uid.to_string(),
                self.address.ip(),
                self.address.port(),
                false)
    }
}