diff --git a/network-hypervisor/src/vl1/endpoint.rs b/network-hypervisor/src/vl1/endpoint.rs index 9dab128ea..1f8069d5e 100644 --- a/network-hypervisor/src/vl1/endpoint.rs +++ b/network-hypervisor/src/vl1/endpoint.rs @@ -3,6 +3,7 @@ use std::hash::{Hash, Hasher}; use crate::vl1::{Address, MAC}; use crate::vl1::inetaddress::InetAddress; use crate::vl1::buffer::Buffer; +use std::cmp::Ordering; const TYPE_NIL: u8 = 0; const TYPE_ZEROTIER: u8 = 1; @@ -15,6 +16,7 @@ const TYPE_IPTCP: u8 = 7; const TYPE_HTTP: u8 = 8; const TYPE_WEBRTC: u8 = 9; +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] pub enum Type { Nil = TYPE_NIL, @@ -29,7 +31,7 @@ pub enum Type { WebRTC = TYPE_WEBRTC, } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, PartialEq, Eq)] pub enum Endpoint { Nil, ZeroTier(Address), @@ -206,6 +208,119 @@ impl Hash for Endpoint { } } +impl PartialOrd for Endpoint { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Endpoint { + fn cmp(&self, other: &Self) -> Ordering { + // This ordering is done explicitly instead of using derive() so it will be certain + // to be consistent with the integer order in the Type enum. Make sure it stays this + // way if new types are added in future revisions. + match self { + Endpoint::Nil => { + match other { + Endpoint::Nil => Ordering::Equal, + _ => Ordering::Greater, + } + } + Endpoint::ZeroTier(a) => { + match other { + Endpoint::Nil => Ordering::Less, + Endpoint::ZeroTier(b) => a.cmp(b), + _ => Ordering::Greater, + } + } + Endpoint::Ethernet(a) => { + match other { + Endpoint::Nil => Ordering::Less, + Endpoint::ZeroTier(_) => Ordering::Less, + Endpoint::Ethernet(b) => a.cmp(b), + _ => Ordering::Greater, + } + } + Endpoint::WifiDirect(a) => { + match other { + Endpoint::Nil => Ordering::Less, + Endpoint::ZeroTier(_) => Ordering::Less, + Endpoint::Ethernet(_) => Ordering::Less, + Endpoint::WifiDirect(b) => a.cmp(b), + _ => Ordering::Greater, + } + } + Endpoint::Bluetooth(a) => { + match other { + Endpoint::Nil => Ordering::Less, + Endpoint::ZeroTier(_) => Ordering::Less, + Endpoint::Ethernet(_) => Ordering::Less, + Endpoint::WifiDirect(_) => Ordering::Less, + Endpoint::Bluetooth(b) => a.cmp(b), + _ => Ordering::Greater, + } + } + Endpoint::Ip(a) => { + match other { + Endpoint::Nil => Ordering::Less, + Endpoint::ZeroTier(_) => Ordering::Less, + Endpoint::Ethernet(_) => Ordering::Less, + Endpoint::WifiDirect(_) => Ordering::Less, + Endpoint::Bluetooth(_) => Ordering::Less, + Endpoint::Ip(b) => a.cmp(b), + _ => Ordering::Greater, + } + } + Endpoint::IpUdp(a) => { + match other { + Endpoint::Nil => Ordering::Less, + Endpoint::ZeroTier(_) => Ordering::Less, + Endpoint::Ethernet(_) => Ordering::Less, + Endpoint::WifiDirect(_) => Ordering::Less, + Endpoint::Bluetooth(_) => Ordering::Less, + Endpoint::Ip(_) => Ordering::Less, + Endpoint::IpUdp(b) => a.cmp(b), + _ => Ordering::Greater, + } + } + Endpoint::IpTcp(a) => { + match other { + Endpoint::Nil => Ordering::Less, + Endpoint::ZeroTier(_) => Ordering::Less, + Endpoint::Ethernet(_) => Ordering::Less, + Endpoint::WifiDirect(_) => Ordering::Less, + Endpoint::Bluetooth(_) => Ordering::Less, + Endpoint::Ip(_) => Ordering::Less, + Endpoint::IpUdp(_) => Ordering::Less, + Endpoint::IpTcp(b) => a.cmp(b), + _ => Ordering::Greater, + } + } + Endpoint::Http(a) => { + match other { + Endpoint::Nil => Ordering::Less, + Endpoint::ZeroTier(_) => Ordering::Less, + Endpoint::Ethernet(_) => Ordering::Less, + Endpoint::WifiDirect(_) => Ordering::Less, + Endpoint::Bluetooth(_) => Ordering::Less, + Endpoint::Ip(_) => Ordering::Less, + Endpoint::IpUdp(_) => Ordering::Less, + Endpoint::IpTcp(_) => Ordering::Less, + Endpoint::Http(b) => a.cmp(b), + _ => Ordering::Greater, + } + } + Endpoint::WebRTC(a) => { + match other { + Endpoint::WebRTC(b) => a.cmp(b), + _ => Ordering::Less, + } + } + } + } +} + impl ToString for Endpoint { fn to_string(&self) -> String { match self { diff --git a/network-hypervisor/src/vl1/locator.rs b/network-hypervisor/src/vl1/locator.rs index 73ce7c705..5d0ea27bf 100644 --- a/network-hypervisor/src/vl1/locator.rs +++ b/network-hypervisor/src/vl1/locator.rs @@ -1 +1,43 @@ -pub struct Locator; +use crate::vl1::{Endpoint, Address, Identity}; +use std::hash::{Hash, Hasher}; + +/// A signed object generated by nodes to inform the network where they may be found. +/// +/// By default this will just enumerate the roots used by this node, but nodes with +/// static IPs can also list physical IP/port addresses where they can be reached with +/// no involvement from a root at all. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Locator { + pub(crate) signer: Address, + pub(crate) timestamp: i64, + pub(crate) endpoints: Vec, + pub(crate) signature: Vec, +} + +impl Locator { + pub fn create(id: &Identity, ts: i64, endpoints: &[Endpoint]) -> Option { + let mut loc = Locator { + signer: id.address(), + timestamp: ts, + endpoints: endpoints.to_vec(), + signature: Vec::new() + }; + loc.endpoints.sort_unstable(); + loc.endpoints.dedup(); + Some(loc) + } +} + +impl Hash for Locator { + fn hash(&self, state: &mut H) { + if !self.signature.is_empty() { + state.write(self.signature.as_slice()); + } else { + state.write_u64(self.signer.to_u64()); + state.write_i64(self.timestamp); + for e in self.endpoints.iter() { + e.hash(state); + } + } + } +}