diff --git a/network-hypervisor/src/vl1/address.rs b/network-hypervisor/src/vl1/address.rs
index e2a35c599..195fafda3 100644
--- a/network-hypervisor/src/vl1/address.rs
+++ b/network-hypervisor/src/vl1/address.rs
@@ -1,54 +1,73 @@
use std::hash::{Hash, Hasher};
+use std::num::NonZeroU64;
use std::str::FromStr;
use crate::error::InvalidFormatError;
use crate::util::hex::HEX_CHARS;
use crate::vl1::protocol::{ADDRESS_RESERVED_PREFIX, ADDRESS_SIZE};
+use crate::vl1::buffer::Buffer;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Address(u64);
+#[repr(transparent)]
+pub struct Address(NonZeroU64);
impl Address {
+ /// Get an address from a 64-bit integer or return None if it is zero or reserved.
#[inline(always)]
- pub fn from_bytes(b: &[u8]) -> Result
{
- if b.len() >= ADDRESS_SIZE {
- Ok(Address((b[0] as u64) << 32 | (b[1] as u64) << 24 | (b[2] as u64) << 16 | (b[3] as u64) << 8 | b[4] as u64))
+ pub fn from_u64(i: u64) -> Option {
+ if i != 0 && (i >> 32) != ADDRESS_RESERVED_PREFIX as u64 {
+ Some(Address(unsafe { NonZeroU64::new_unchecked(i & 0xffffffffff) }))
} else {
- Err(InvalidFormatError)
+ None
+ }
+ }
+
+ /// Get an address from a byte slice or return None if it is zero or reserved.
+ #[inline(always)]
+ pub fn from_bytes(b: &[u8]) -> Option {
+ if b.len() >= ADDRESS_SIZE {
+ let i = (b[0] as u64) << 32 | (b[1] as u64) << 24 | (b[2] as u64) << 16 | (b[3] as u64) << 8 | b[4] as u64;
+ if i != 0 && (i >> 32) != ADDRESS_RESERVED_PREFIX as u64 {
+ Some(Address(unsafe { NonZeroU64::new_unchecked(i) }))
+ } else {
+ None
+ }
+ } else {
+ None
}
}
- #[inline(always)]
- pub fn is_reserved(&self) -> bool {
- (self.0 >> 32) as usize == ADDRESS_RESERVED_PREFIX as usize
- }
-
- #[inline(always)]
- pub fn is_nil(&self) -> bool {
- self.0 == 0
- }
-
- #[inline(always)]
- pub fn is_valid(&self) -> bool {
- !self.is_nil() && !self.is_reserved()
- }
-
#[inline(always)]
pub fn to_bytes(&self) -> [u8; ADDRESS_SIZE] {
- [(self.0 >> 32) as u8, (self.0 >> 24) as u8, (self.0 >> 16) as u8, (self.0 >> 8) as u8, self.0 as u8]
+ let i = self.0.get();
+ [(i >> 32) as u8, (i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8]
}
#[inline(always)]
- pub fn to_u64(&self) -> u64 {
- self.0
+ pub fn to_u64(&self) -> u64 { self.0.get() }
+
+ #[inline(always)]
+ pub(crate) fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> {
+ buf.append_and_init_bytes_fixed(|b: &mut [u8; ADDRESS_SIZE]| {
+ let i = self.0.get();
+ b[0] = (i >> 32) as u8;
+ b[1] = (i >> 24) as u8;
+ b[2] = (i >> 16) as u8;
+ b[3] = (i >> 8) as u8;
+ b[4] = i as u8;
+ })
+ }
+
+ #[inline(always)]
+ pub(crate) fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result> {
+ buf.read_bytes_fixed::<{ ADDRESS_SIZE }>(cursor).map(|b| Self::from_bytes(b))
}
}
impl ToString for Address {
fn to_string(&self) -> String {
- let mut v = self.0 << 24;
- let mut s = String::new();
- s.reserve(ADDRESS_SIZE * 2);
+ let mut v = self.0.get() << 24;
+ let mut s = String::with_capacity(ADDRESS_SIZE * 2);
for _ in 0..(ADDRESS_SIZE * 2) {
s.push(HEX_CHARS[(v >> 60) as usize] as char);
v <<= 4;
@@ -61,42 +80,13 @@ impl FromStr for Address {
type Err = InvalidFormatError;
fn from_str(s: &str) -> Result {
- Address::from_bytes(crate::util::hex::from_string(s).as_slice())
- }
-}
-
-impl Default for Address {
- #[inline(always)]
- fn default() -> Address {
- Address(0)
+ Address::from_bytes(crate::util::hex::from_string(s).as_slice()).map_or_else(|| Err(InvalidFormatError), |a| Ok(a))
}
}
impl Hash for Address {
#[inline(always)]
fn hash(&self, state: &mut H) {
- state.write_u64(self.0);
- }
-}
-
-impl From<&[u8; ADDRESS_SIZE]> for Address {
- #[inline(always)]
- fn from(b: &[u8; 5]) -> Address {
- Address((b[0] as u64) << 32 | (b[1] as u64) << 24 | (b[2] as u64) << 16 | (b[3] as u64) << 8 | b[4] as u64)
- }
-}
-
-impl From<[u8; ADDRESS_SIZE]> for Address {
- #[inline(always)]
- fn from(b: [u8; 5]) -> Address {
- Self::from(&b)
- }
-}
-
-impl From for Address {
- #[inline(always)]
- fn from(i: u64) -> Address {
- debug_assert!((i >> 24) == 0);
- Address(i)
+ state.write_u64(self.0.get());
}
}
diff --git a/network-hypervisor/src/vl1/buffer.rs b/network-hypervisor/src/vl1/buffer.rs
index 7607c8b08..df06a2f84 100644
--- a/network-hypervisor/src/vl1/buffer.rs
+++ b/network-hypervisor/src/vl1/buffer.rs
@@ -1,6 +1,5 @@
use std::io::Write;
-use std::mem::{size_of, MaybeUninit};
-use std::ptr::write_bytes;
+use std::mem::size_of;
use crate::util::pool::PoolFactory;
@@ -19,18 +18,14 @@ unsafe impl RawObject for Buffer {}
impl Default for Buffer {
#[inline(always)]
- fn default() -> Self {
- Self(0, [0_u8; L])
- }
+ fn default() -> Self { Self(0, [0_u8; L]) }
}
const OVERFLOW_ERR_MSG: &'static str = "overflow";
impl Buffer {
#[inline(always)]
- pub fn new() -> Self {
- Self(0, [0_u8; L])
- }
+ pub fn new() -> Self { Self(0, [0_u8; L]) }
/// Get a Buffer initialized with a copy of a byte slice.
#[inline(always)]
@@ -47,14 +42,10 @@ impl Buffer {
}
#[inline(always)]
- pub fn as_bytes(&self) -> &[u8] {
- &self.1[0..self.0]
- }
+ pub fn as_bytes(&self) -> &[u8] { &self.1[0..self.0] }
#[inline(always)]
- pub fn as_bytes_mut(&mut self) -> &mut [u8] {
- &mut self.1[0..self.0]
- }
+ pub fn as_bytes_mut(&mut self) -> &mut [u8] { &mut self.1[0..self.0] }
/// Get all bytes after a given position.
#[inline(always)]
@@ -74,14 +65,10 @@ impl Buffer {
}
#[inline(always)]
- pub fn len(&self) -> usize {
- self.0
- }
+ pub fn len(&self) -> usize { self.0 }
#[inline(always)]
- pub fn is_empty(&self) -> bool {
- self.0 == 0
- }
+ pub fn is_empty(&self) -> bool { self.0 == 0 }
/// Append a packed structure and call a function to initialize it in place.
/// Anything not initialized will be zero.
@@ -159,6 +146,22 @@ impl Buffer {
}
}
+ /// Append a variable length integer to this buffer.
+ ///
+ /// Varints are encoded as a series of 7-bit bytes terminated by a final 7-bit byte whose
+ /// most significant bit is set. Unlike fixed size integers varints are written in little
+ /// endian order (in 7-bit chunks).
+ ///
+ /// They are slower than fixed size values so they should not be used in formats that are
+ /// created or parsed in very speed-critical paths.
+ pub fn append_varint(&mut self, mut i: u64) -> std::io::Result<()> {
+ while i >= 0x80 {
+ self.append_u8((i as u8) & 0x7f)?;
+ i >>= 7;
+ }
+ self.append_u8((i as u8) | 0x80)
+ }
+
/// Append a byte
#[inline(always)]
pub fn append_u8(&mut self, i: u8) -> std::io::Result<()> {
@@ -295,6 +298,23 @@ impl Buffer {
}
}
+ /// Get the next variable length integer and advance the cursor by its length in bytes.
+ pub fn read_varint(&self, cursor: &mut usize) -> std::io::Result {
+ let mut i = 0_u64;
+ let mut p = 0;
+ loop {
+ let b = self.read_u8(cursor)?;
+ if (b & 0x80) == 0 {
+ i |= (b as u64) << p;
+ p += 7;
+ } else {
+ i |= ((b & 0x7f) as u64) << p;
+ break;
+ }
+ }
+ Ok(i)
+ }
+
/// Get the next u8 and advance the cursor.
#[inline(always)]
pub fn read_u8(&self, cursor: &mut usize) -> std::io::Result {
@@ -366,35 +386,25 @@ impl Write for Buffer {
}
#[inline(always)]
- fn flush(&mut self) -> std::io::Result<()> {
- Ok(())
- }
+ fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
}
impl AsRef<[u8]> for Buffer {
#[inline(always)]
- fn as_ref(&self) -> &[u8] {
- self.as_bytes()
- }
+ fn as_ref(&self) -> &[u8] { self.as_bytes() }
}
impl AsMut<[u8]> for Buffer {
#[inline(always)]
- fn as_mut(&mut self) -> &mut [u8] {
- self.as_bytes_mut()
- }
+ fn as_mut(&mut self) -> &mut [u8] { self.as_bytes_mut() }
}
pub struct PooledBufferFactory;
impl PoolFactory> for PooledBufferFactory {
#[inline(always)]
- fn create(&self) -> Buffer {
- Buffer::new()
- }
+ fn create(&self) -> Buffer { Buffer::new() }
#[inline(always)]
- fn reset(&self, obj: &mut Buffer) {
- obj.clear();
- }
+ fn reset(&self, obj: &mut Buffer) { obj.clear(); }
}
diff --git a/network-hypervisor/src/vl1/dictionary.rs b/network-hypervisor/src/vl1/dictionary.rs
index 4e7b23b51..06433a81d 100644
--- a/network-hypervisor/src/vl1/dictionary.rs
+++ b/network-hypervisor/src/vl1/dictionary.rs
@@ -44,25 +44,15 @@ fn append_printable(s: &mut String, b: &[u8]) {
}
impl Dictionary {
- #[inline(always)]
- pub fn new() -> Self {
- Self(BTreeMap::new())
- }
+ pub fn new() -> Self { Self(BTreeMap::new()) }
+
+ pub fn clear(&mut self) { self.0.clear() }
#[inline(always)]
- pub fn clear(&mut self) {
- self.0.clear()
- }
+ pub fn len(&self) -> usize { self.0.len() }
#[inline(always)]
- pub fn len(&self) -> usize {
- self.0.len()
- }
-
- #[inline(always)]
- pub fn is_empty(&self) -> bool {
- self.0.is_empty()
- }
+ pub fn is_empty(&self) -> bool { self.0.is_empty() }
pub fn get_str(&self, k: &str) -> Option<&str> {
self.0.get(k).map_or(None, |v| std::str::from_utf8(v.as_slice()).map_or(None, |s| Some(s)))
diff --git a/network-hypervisor/src/vl1/endpoint.rs b/network-hypervisor/src/vl1/endpoint.rs
index f2f398759..d91795203 100644
--- a/network-hypervisor/src/vl1/endpoint.rs
+++ b/network-hypervisor/src/vl1/endpoint.rs
@@ -117,13 +117,13 @@ impl Endpoint {
Endpoint::Http(url) => {
buf.append_u8(16 + TYPE_HTTP)?;
let b = url.as_bytes();
- buf.append_u16(b.len() as u16)?;
+ buf.append_varint(b.len() as u64)?;
buf.append_bytes(b)
}
Endpoint::WebRTC(offer) => {
buf.append_u8(16 + TYPE_WEBRTC)?;
let b = offer.as_slice();
- buf.append_u16(b.len() as u16)?;
+ buf.append_varint(b.len() as u64)?;
buf.append_bytes(b)
}
}
@@ -139,24 +139,33 @@ impl Endpoint {
Ok(Endpoint::IpUdp(ip))
}
} else {
+ let read_mac = |buf: &Buffer, cursor: &mut usize| {
+ let m = MAC::unmarshal(buf, cursor)?;
+ if m.is_some() {
+ Ok(m.unwrap())
+ } else {
+ Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid MAC address"))
+ }
+ };
match type_byte - 16 {
TYPE_NIL => Ok(Endpoint::Nil),
- TYPE_ZEROTIER => Ok(Endpoint::ZeroTier(Address::from(buf.read_bytes_fixed(cursor)?))),
- TYPE_ETHERNET => Ok(Endpoint::Ethernet(MAC::from(buf.read_bytes_fixed(cursor)?))),
- TYPE_WIFIDIRECT => Ok(Endpoint::WifiDirect(MAC::from(buf.read_bytes_fixed(cursor)?))),
- TYPE_BLUETOOTH => Ok(Endpoint::Bluetooth(MAC::from(buf.read_bytes_fixed(cursor)?))),
+ TYPE_ZEROTIER => {
+ let zt = Address::unmarshal(buf, cursor)?;
+ if zt.is_some() {
+ Ok(Endpoint::ZeroTier(zt.unwrap()))
+ } else {
+ Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid ZeroTier address"))
+ }
+ },
+ TYPE_ETHERNET => Ok(Endpoint::Ethernet(read_mac(buf, cursor)?)),
+ TYPE_WIFIDIRECT => Ok(Endpoint::WifiDirect(read_mac(buf, cursor)?)),
+ TYPE_BLUETOOTH => Ok(Endpoint::Bluetooth(read_mac(buf, cursor)?)),
TYPE_IP => Ok(Endpoint::Ip(InetAddress::unmarshal(buf, cursor)?)),
TYPE_IPUDP => Ok(Endpoint::IpUdp(InetAddress::unmarshal(buf, cursor)?)),
TYPE_IPTCP => Ok(Endpoint::IpTcp(InetAddress::unmarshal(buf, cursor)?)),
- TYPE_HTTP => {
- let l = buf.read_u16(cursor)?;
- Ok(Endpoint::Http(String::from_utf8_lossy(buf.read_bytes(l as usize, cursor)?).to_string()))
- }
- TYPE_WEBRTC => {
- let l = buf.read_u16(cursor)?;
- Ok(Endpoint::WebRTC(buf.read_bytes(l as usize, cursor)?.to_vec()))
- }
- _ => std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "unrecognized endpoint type in stream"))
+ TYPE_HTTP => Ok(Endpoint::Http(String::from_utf8_lossy(buf.read_bytes(buf.read_varint(cursor)? as usize, cursor)?).to_string())),
+ TYPE_WEBRTC => Ok(Endpoint::WebRTC(buf.read_bytes(buf.read_varint(cursor)? as usize, cursor)?.to_vec())),
+ _ => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "unrecognized endpoint type in stream"))
}
}
}
@@ -210,16 +219,14 @@ impl Hash for Endpoint {
impl PartialOrd for Endpoint {
#[inline(always)]
- fn partial_cmp(&self, other: &Self) -> Option {
- Some(self.cmp(other))
- }
+ fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) }
}
+// We manually implement Ord and PartialOrd to ensure that ordering is always the same, since I'm not
+// sure if Rust's derivations for this are guaranteed to remain constant forever. Endpoint ordering
+// is important in the reproducibility of digital signatures any time one is signing a vector of them.
impl Ord for Endpoint {
fn cmp(&self, other: &Self) -> Ordering {
- // This ordering is done explicitly instead of using derive(Ord) 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 {
diff --git a/network-hypervisor/src/vl1/identity.rs b/network-hypervisor/src/vl1/identity.rs
index 22329cb6b..0acd08d0a 100644
--- a/network-hypervisor/src/vl1/identity.rs
+++ b/network-hypervisor/src/vl1/identity.rs
@@ -109,11 +109,11 @@ impl Identity {
v0_frankenhash(&mut digest, genmem_ptr);
if digest[0] < 17 {
- let addr = Address::from_bytes(&digest[59..64]).unwrap();
- if addr.is_valid() {
+ let addr = Address::from_bytes(&digest[59..64]);
+ if addr.is_some() {
unsafe { dealloc(genmem_ptr, genmem_layout) };
return Identity {
- address: addr,
+ address: addr.unwrap(),
c25519: c25519_pub_bytes,
ed25519: ed25519_pub_bytes,
v1: None,
@@ -143,12 +143,12 @@ impl Identity {
let sig = p521_ecdsa.sign(&sign_buf).unwrap();
let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&sig, V1_BALLOON_SALT);
if bh[0] < 7 {
- let addr = Address::from_bytes(&bh[43..48]).unwrap();
- if addr.is_valid() {
+ let addr = Address::from_bytes(&bh[43..48]);
+ if addr.is_some() {
let p521_ecdh_pub = p521_ecdh.public_key().clone();
let p521_ecdsa_pub = p521_ecdsa.public_key().clone();
return Identity {
- address: addr,
+ address: addr.unwrap(),
c25519: c25519_pub_bytes,
ed25519: ed25519_pub_bytes,
v1: Some((p521_ecdh_pub, p521_ecdsa_pub, sig, bh)),
@@ -179,9 +179,7 @@ impl Identity {
/// Get this identity's 40-bit address.
#[inline(always)]
- pub fn address(&self) -> Address {
- self.address
- }
+ pub fn address(&self) -> Address { self.address }
/// Compute a SHA384 hash of this identity's keys, including private keys if present.
pub fn hash_all_keys(&self) -> [u8; 48] {
@@ -208,37 +206,33 @@ impl Identity {
/// This can take a few milliseconds, especially on slower systems. V0 identities are slower
/// to fully validate than V1 identities.
pub fn locally_validate(&self) -> bool {
- if self.address.is_valid() {
- if self.v1.is_none() {
- let genmem_layout = Layout::from_size_align(V0_IDENTITY_GEN_MEMORY, 8).unwrap();
- let genmem_ptr = unsafe { alloc(genmem_layout) };
- if !genmem_ptr.is_null() {
- let mut sha = SHA512::new();
- sha.update(&self.c25519);
- sha.update(&self.ed25519);
- let mut digest = sha.finish();
- v0_frankenhash(&mut digest, genmem_ptr);
- unsafe { dealloc(genmem_ptr, genmem_layout) };
- (digest[0] < 17) && Address::from_bytes(&digest[59..64]).unwrap().eq(&self.address)
- } else {
- false
- }
+ if self.v1.is_none() {
+ let genmem_layout = Layout::from_size_align(V0_IDENTITY_GEN_MEMORY, 8).unwrap();
+ let genmem_ptr = unsafe { alloc(genmem_layout) };
+ if !genmem_ptr.is_null() {
+ let mut sha = SHA512::new();
+ sha.update(&self.c25519);
+ sha.update(&self.ed25519);
+ let mut digest = sha.finish();
+ v0_frankenhash(&mut digest, genmem_ptr);
+ unsafe { dealloc(genmem_ptr, genmem_layout) };
+ (digest[0] < 17) && Address::from_bytes(&digest[59..64]).unwrap().eq(&self.address)
} else {
- let p521 = self.v1.as_ref().unwrap();
- let mut signing_buf = [0_u8; C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE];
- signing_buf[0..C25519_PUBLIC_KEY_SIZE].copy_from_slice(&self.c25519);
- signing_buf[C25519_PUBLIC_KEY_SIZE..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)].copy_from_slice(&self.ed25519);
- signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).0.public_key_bytes());
- signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).1.public_key_bytes());
- if (*p521).1.verify(&signing_buf, &(*p521).2) {
- let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&(*p521).2, V1_BALLOON_SALT);
- (bh[0] < 7) && bh.eq(&(*p521).3) && Address::from_bytes(&bh[43..48]).unwrap().eq(&self.address)
- } else {
- false
- }
+ false
}
} else {
- false
+ let p521 = self.v1.as_ref().unwrap();
+ let mut signing_buf = [0_u8; C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE];
+ signing_buf[0..C25519_PUBLIC_KEY_SIZE].copy_from_slice(&self.c25519);
+ signing_buf[C25519_PUBLIC_KEY_SIZE..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)].copy_from_slice(&self.ed25519);
+ signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).0.public_key_bytes());
+ signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).1.public_key_bytes());
+ if (*p521).1.verify(&signing_buf, &(*p521).2) {
+ let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&(*p521).2, V1_BALLOON_SALT);
+ (bh[0] < 7) && bh.eq(&(*p521).3) && Address::from_bytes(&bh[43..48]).unwrap().eq(&self.address)
+ } else {
+ false
+ }
}
}
@@ -564,7 +558,6 @@ impl FromStr for Identity {
return Err(InvalidFormatError);
}
} else {
- println!("foo");
return Err(InvalidFormatError);
}
} else {
diff --git a/network-hypervisor/src/vl1/inetaddress.rs b/network-hypervisor/src/vl1/inetaddress.rs
index 9174864b1..b5d63cd53 100644
--- a/network-hypervisor/src/vl1/inetaddress.rs
+++ b/network-hypervisor/src/vl1/inetaddress.rs
@@ -1,17 +1,17 @@
-use std::mem::{zeroed, size_of, MaybeUninit};
-use std::ptr::{write_bytes, copy_nonoverlapping, null};
-use std::str::FromStr;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
+use std::mem::{MaybeUninit, size_of, transmute_copy, zeroed};
use std::net::{IpAddr, Ipv6Addr};
+use std::ptr::{copy_nonoverlapping, null, slice_from_raw_parts, write_bytes};
+use std::str::FromStr;
+
+#[cfg(windows)]
+use winapi::um::winsock2 as winsock2;
use crate::error::InvalidFormatError;
use crate::util::equal_ptr;
use crate::vl1::buffer::Buffer;
-#[cfg(windows)]
-use winapi::um::winsock2 as winsock2;
-
#[allow(non_camel_case_types)]
#[cfg(not(windows))]
type sockaddr = libc::sockaddr;
@@ -67,28 +67,18 @@ pub union InetAddress {
impl Clone for InetAddress {
#[inline(always)]
- fn clone(&self) -> Self {
- unsafe {
- let mut c = MaybeUninit::::uninit().assume_init();
- copy_nonoverlapping((self as *const Self).cast::(), (&mut c as *mut Self).cast::(), size_of::());
- c
- }
- }
+ fn clone(&self) -> Self { unsafe { transmute_copy(self) } }
}
impl Default for InetAddress {
#[inline(always)]
- fn default() -> InetAddress {
- unsafe { zeroed() }
- }
+ fn default() -> InetAddress { unsafe { zeroed() } }
}
impl InetAddress {
/// Get a new zero/nil InetAddress.
#[inline(always)]
- pub fn new() -> InetAddress {
- unsafe { zeroed() }
- }
+ pub fn new() -> InetAddress { unsafe { zeroed() } }
/// Construct from IP and port.
/// If the IP is not either 4 or 16 bytes in length, a nil/0 InetAddress is returned.
@@ -103,9 +93,7 @@ impl InetAddress {
/// Zero the contents of this InetAddress.
#[inline(always)]
- pub fn zero(&mut self) {
- unsafe { write_bytes((self as *mut Self).cast::(), 0, size_of::()) };
- }
+ pub fn zero(&mut self) { unsafe { write_bytes((self as *mut Self).cast::(), 0, size_of::()) }; }
/// Get an instance of 127.0.0.1/port
pub fn ipv4_loopback(port: u16) -> InetAddress {
@@ -143,31 +131,23 @@ impl InetAddress {
/// Returns true if this InetAddress is the nil value (zero).
#[inline(always)]
- pub fn is_nil(&self) -> bool {
- unsafe { self.sa.sa_family == 0 }
- }
+ pub fn is_nil(&self) -> bool { unsafe { self.sa.sa_family == 0 } }
/// Check if this is an IPv4 address.
#[inline(always)]
- pub fn is_ipv4(&self) -> bool {
- unsafe { self.sa.sa_family as u8 == AF_INET }
- }
+ pub fn is_ipv4(&self) -> bool { unsafe { self.sa.sa_family as u8 == AF_INET } }
/// Check if this is an IPv6 address.
#[inline(always)]
- pub fn is_ipv6(&self) -> bool {
- unsafe { self.sa.sa_family as u8 == AF_INET6 }
- }
+ pub fn is_ipv6(&self) -> bool { unsafe { self.sa.sa_family as u8 == AF_INET6 } }
- /// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if nil.
+ /// Get the address family of this InetAddress: AF_INET, AF_INET6, or 0 if uninitialized.
#[inline(always)]
- pub fn family(&self) -> u8 {
- unsafe { self.sa.sa_family }
- }
+ pub fn family(&self) -> u8 { unsafe { self.sa.sa_family } }
/// Get a pointer to the C "sockaddr" structure and the size of the returned structure in bytes.
- /// This is useful for interacting with C-level socket APIs. If this is a nil InetAddress this
- /// returns a null pointer and 0 for the size.
+ /// This is useful for interacting with C-level socket APIs. This returns a null pointer if
+ /// the address is not initialized.
#[inline(always)]
pub fn c_sockaddr(&self) -> (*const (), usize) {
unsafe {
@@ -203,7 +183,7 @@ impl InetAddress {
}
}
- /// Get raw IP bytes, with length dependent on address family.
+ /// Get raw IP bytes, with length dependent on address family (4 or 16).
#[inline(always)]
pub fn ip_bytes(&self) -> &[u8] {
unsafe {
@@ -219,15 +199,18 @@ impl InetAddress {
#[inline(always)]
pub fn port(&self) -> u16 {
unsafe {
- match self.sa.sa_family as u8 {
- AF_INET => u16::from_be(self.sin.sin_port as u16),
- AF_INET6 => u16::from_be(self.sin6.sin6_port as u16),
+ u16::from_be(match self.sa.sa_family as u8 {
+ AF_INET => self.sin.sin_port as u16,
+ AF_INET6 => self.sin6.sin6_port as u16,
_ => 0
- }
+ })
}
}
/// Set the IP port.
+ ///
+ /// This does nothing on uninitialized InetAddress objects. An address must first
+ /// be initialized with an IP to select the correct address type.
#[inline(always)]
pub fn set_port(&mut self, port: u16) {
let port = port.to_be();
@@ -498,16 +481,19 @@ impl Eq for InetAddress {}
impl PartialOrd for InetAddress {
#[inline(always)]
- fn partial_cmp(&self, other: &Self) -> Option {
- Some(self.cmp(other))
- }
+ fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) }
}
+// Manually implement Ord to ensure consistent sort order across platforms, since we don't know exactly
+// how sockaddr structs will be laid out.
impl Ord for InetAddress {
fn cmp(&self, other: &Self) -> Ordering {
unsafe {
if self.sa.sa_family == other.sa.sa_family {
match self.sa.sa_family as u8 {
+ 0 => {
+ Ordering::Equal
+ }
AF_INET => {
let ip_ordering = u32::from_be(self.sin.sin_addr.s_addr as u32).cmp(&u32::from_be(other.sin.sin_addr.s_addr as u32));
if ip_ordering == Ordering::Equal {
@@ -527,11 +513,15 @@ impl Ord for InetAddress {
}
}
_ => {
- Ordering::Equal
+ // This shouldn't be possible, but handle it for correctness.
+ (*slice_from_raw_parts((self as *const Self).cast::(), size_of::())).cmp(&*slice_from_raw_parts((other as *const Self).cast::(), size_of::()))
}
}
} else {
match self.sa.sa_family as u8 {
+ 0 => {
+ Ordering::Less
+ }
AF_INET => {
if other.sa.sa_family as u8 == AF_INET6 {
Ordering::Less
@@ -547,6 +537,7 @@ impl Ord for InetAddress {
}
}
_ => {
+ // This likewise should not be possible.
self.sa.sa_family.cmp(&other.sa.sa_family)
}
}
@@ -576,9 +567,17 @@ impl Hash for InetAddress {
#[cfg(test)]
mod tests {
- use std::str::FromStr;
- use crate::vl1::inetaddress::{InetAddress, sockaddr_storage};
use std::mem::size_of;
+ use std::str::FromStr;
+
+ use crate::vl1::inetaddress::*;
+
+ #[test]
+ fn values() {
+ assert_ne!(AF_INET, 0);
+ assert_ne!(AF_INET6, 0);
+ assert_ne!(AF_INET, AF_INET6);
+ }
#[test]
fn layout() {
diff --git a/network-hypervisor/src/vl1/locator.rs b/network-hypervisor/src/vl1/locator.rs
index e1b269443..520f35240 100644
--- a/network-hypervisor/src/vl1/locator.rs
+++ b/network-hypervisor/src/vl1/locator.rs
@@ -4,9 +4,6 @@ use crate::vl1::{Address, Endpoint, Identity};
use crate::vl1::buffer::Buffer;
use crate::vl1::protocol::PACKET_SIZE_MAX;
-/// Maximum number of endpoints allowed in a Locator.
-pub const LOCATOR_MAX_ENDPOINTS: usize = 32;
-
/// 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
@@ -32,10 +29,6 @@ impl Locator {
/// This returns None if an error occurs, which can only be something indicating a
/// bug like too many endpoints or the identity lacking its secret keys.
pub fn create(signer_identity: &Identity, subject: Address, ts: i64, endpoints: &[Endpoint]) -> Option {
- if endpoints.len() > LOCATOR_MAX_ENDPOINTS {
- return None;
- }
-
let mut loc = Locator {
subject,
signer: signer_identity.address(),
@@ -68,29 +61,19 @@ impl Locator {
}
#[inline(always)]
- pub fn subject(&self) -> Address {
- self.subject
- }
+ pub fn subject(&self) -> Address { self.subject }
#[inline(always)]
- pub fn signer(&self) -> Address {
- self.signer
- }
+ pub fn signer(&self) -> Address { self.signer }
#[inline(always)]
- pub fn is_proxy_signed(&self) -> bool {
- self.subject != self.signer
- }
+ pub fn is_proxy_signed(&self) -> bool { self.subject != self.signer }
#[inline(always)]
- pub fn timestamp(&self) -> i64 {
- self.timestamp
- }
+ pub fn timestamp(&self) -> i64 { self.timestamp }
#[inline(always)]
- pub fn endpoints(&self) -> &[Endpoint] {
- self.endpoints.as_slice()
- }
+ pub fn endpoints(&self) -> &[Endpoint] { self.endpoints.as_slice() }
pub fn verify_signature(&self, signer_identity: &Identity) -> bool {
let mut buf: Buffer<{ PACKET_SIZE_MAX }> = Buffer::new();
@@ -106,47 +89,42 @@ impl Locator {
}
fn marshal_internal(&self, buf: &mut Buffer, exclude_signature: bool) -> std::io::Result<()> {
- buf.append_u64(self.subject.to_u64())?;
- buf.append_u64(self.signer.to_u64())?;
+ self.subject.marshal(buf)?;
+ self.signer.marshal(buf)?;
buf.append_u64(self.timestamp as u64)?;
- debug_assert!(self.endpoints.len() < 65536);
- buf.append_u16(self.endpoints.len() as u16)?;
+ buf.append_varint(self.endpoints.len() as u64);
for e in self.endpoints.iter() {
e.marshal(buf)?;
}
- buf.append_u16(0)?;
+ buf.append_varint(0); // length of any additional fields
if !exclude_signature {
- debug_assert!(self.signature.len() < 65536);
- buf.append_u16(self.signature.len() as u16)?;
+ buf.append_varint(self.signature.len() as u64);
buf.append_bytes(self.signature.as_slice())?;
}
Ok(())
}
#[inline(always)]
- pub fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> {
- self.marshal_internal(buf, false)
- }
+ pub(crate) fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> { self.marshal_internal(buf, false) }
- pub fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result {
- let subject = Address::from(buf.read_u64(cursor)?);
- let signer = Address::from(buf.read_u64(cursor)?);
- let timestamp = buf.read_u64(cursor)? as i64;
- let endpoint_count = buf.read_u16(cursor)? as usize;
- if endpoint_count > LOCATOR_MAX_ENDPOINTS {
- return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "too many endpoints"));
+ pub(crate) fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result {
+ let subject = Address::unmarshal(buf, cursor)?;
+ let signer = Address::unmarshal(buf, cursor)?;
+ if subject.is_none() || signer.is_none() {
+ return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid subject or signer address"));
}
+ let timestamp = buf.read_u64(cursor)? as i64;
+ let endpoint_count = buf.read_varint(cursor)? as usize;
let mut endpoints: Vec = Vec::new();
- endpoints.reserve(endpoint_count);
for _ in 0..endpoint_count {
endpoints.push(Endpoint::unmarshal(buf, cursor)?);
}
- *cursor += buf.read_u16(cursor)? as usize;
- let signature_len = buf.read_u16(cursor)? as usize;
+ *cursor += buf.read_varint(cursor)? as usize;
+ let signature_len = buf.read_varint(cursor)? as usize;
let signature = buf.read_bytes(signature_len, cursor)?;
Ok(Locator {
- subject,
- signer,
+ subject: subject.unwrap(),
+ signer: signer.unwrap(),
timestamp,
endpoints,
signature: signature.to_vec(),
diff --git a/network-hypervisor/src/vl1/mac.rs b/network-hypervisor/src/vl1/mac.rs
index 1213899ad..b9bd22508 100644
--- a/network-hypervisor/src/vl1/mac.rs
+++ b/network-hypervisor/src/vl1/mac.rs
@@ -1,80 +1,84 @@
+use std::num::NonZeroU64;
use std::str::FromStr;
use std::hash::{Hash, Hasher};
use crate::error::InvalidFormatError;
+use crate::vl1::buffer::Buffer;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct MAC(u64);
+#[repr(transparent)]
+pub struct MAC(NonZeroU64);
impl MAC {
#[inline(always)]
- pub fn from_bytes(b: &[u8]) -> Result {
- if b.len() >= 6 {
- Ok(MAC((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64))
+ pub fn from_u64(i: u64) -> Option {
+ if i != 0 {
+ Some(MAC(unsafe { NonZeroU64::new_unchecked(i & 0xffffffffffff) }))
} else {
- Err(InvalidFormatError)
+ None
+ }
+ }
+
+ #[inline(always)]
+ pub fn from_bytes(b: &[u8]) -> Option {
+ if b.len() >= 6 {
+ let i = (b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64;
+ if i != 0 {
+ Some(MAC(unsafe { NonZeroU64::new_unchecked(i) }))
+ } else {
+ None
+ }
+ } else {
+ None
}
}
#[inline(always)]
pub fn to_bytes(&self) -> [u8; 6] {
- [(self.0 >> 40) as u8, (self.0 >> 32) as u8, (self.0 >> 24) as u8, (self.0 >> 16) as u8, (self.0 >> 8) as u8, self.0 as u8]
+ let i = self.0.get();
+ [(i >> 40) as u8, (i >> 32) as u8, (i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8]
}
#[inline(always)]
- pub fn to_u64(&self) -> u64 {
- self.0
+ pub fn to_u64(&self) -> u64 { self.0.get() }
+
+ #[inline(always)]
+ pub(crate) fn marshal(&self, buf: &mut Buffer) -> std::io::Result<()> {
+ buf.append_and_init_bytes_fixed(|b: &mut [u8; 6]| {
+ let i = self.0.get();
+ b[0] = (i >> 40) as u8;
+ b[1] = (i >> 32) as u8;
+ b[2] = (i >> 24) as u8;
+ b[3] = (i >> 16) as u8;
+ b[4] = (i >> 8) as u8;
+ b[5] = i as u8;
+ })
+ }
+
+ #[inline(always)]
+ pub(crate) fn unmarshal(buf: &Buffer, cursor: &mut usize) -> std::io::Result> {
+ buf.read_bytes_fixed::<6>(cursor).map(|b| Self::from_bytes(b))
}
}
impl ToString for MAC {
- #[inline(always)]
fn to_string(&self) -> String {
let b: [u8; 6] = self.to_bytes();
- format!("{}:{}:{}:{}:{}:{}", b[0], b[1], b[2], b[3], b[4], b[5])
+ format!("{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}", b[0], b[1], b[2], b[3], b[4], b[5])
}
}
impl FromStr for MAC {
type Err = InvalidFormatError;
- #[inline(always)]
fn from_str(s: &str) -> Result {
- MAC::from_bytes(crate::util::hex::from_string(s).as_slice())
- }
-}
-
-impl Default for MAC {
- #[inline(always)]
- fn default() -> MAC {
- MAC(0)
+ MAC::from_bytes(crate::util::hex::from_string(s).as_slice()).map_or_else(|| Err(InvalidFormatError), |m| Ok(m))
}
}
impl Hash for MAC {
#[inline(always)]
fn hash(&self, state: &mut H) {
- state.write_u64(self.0);
- }
-}
-
-impl From<&[u8; 6]> for MAC {
- #[inline(always)]
- fn from(b: &[u8; 6]) -> MAC {
- MAC((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64)
- }
-}
-
-impl From<[u8; 6]> for MAC {
- #[inline(always)]
- fn from(b: [u8; 6]) -> MAC {
- Self::from(&b)
- }
-}
-
-impl From for MAC {
- #[inline(always)]
- fn from(i: u64) -> MAC {
- MAC(i)
+ state.write_u64(self.0.get());
}
}
diff --git a/network-hypervisor/src/vl1/mod.rs b/network-hypervisor/src/vl1/mod.rs
index 6255881a9..8e21845eb 100644
--- a/network-hypervisor/src/vl1/mod.rs
+++ b/network-hypervisor/src/vl1/mod.rs
@@ -1,3 +1,11 @@
+// Only things that should be used from outside network-hypervisor should be full "pub."
+pub mod identity;
+pub mod inetaddress;
+pub mod endpoint;
+pub mod locator;
+pub mod rootset;
+
+// These are either only used inside network-hypervisor or are selectively exported below.
pub(crate) mod protocol;
pub(crate) mod buffer;
pub(crate) mod node;
@@ -9,12 +17,7 @@ pub(crate) mod mac;
pub(crate) mod fragmentedpacket;
pub(crate) mod whois;
-pub mod identity;
-pub mod inetaddress;
-pub mod endpoint;
-pub mod locator;
-pub mod rootset;
-
+// Export some core objects into the root namespace, since these are what other code will driectly deal with.
pub use address::Address;
pub use mac::MAC;
pub use identity::Identity;
diff --git a/network-hypervisor/src/vl1/node.rs b/network-hypervisor/src/vl1/node.rs
index 33f68d80e..8e0ffae71 100644
--- a/network-hypervisor/src/vl1/node.rs
+++ b/network-hypervisor/src/vl1/node.rs
@@ -170,32 +170,22 @@ impl Node {
/// Get address, short for .identity().address()
#[inline(always)]
- pub fn address(&self) -> Address {
- self.identity.address()
- }
+ pub fn address(&self) -> Address { self.identity.address() }
/// Get identity, which includes secret keys.
#[inline(always)]
- pub fn identity(&self) -> &Identity {
- &self.identity
- }
+ pub fn identity(&self) -> &Identity { &self.identity }
/// Get this node's current locator or None if no locator created.
#[inline(always)]
- pub fn locator(&self) -> Option> {
- self.locator.lock().clone()
- }
+ pub fn locator(&self) -> Option> { self.locator.lock().clone() }
/// Get a reusable packet buffer.
/// The buffer will automatically be returned to the pool if it is dropped.
- pub fn get_packet_buffer(&self) -> PacketBuffer {
- self.buffer_pool.get()
- }
+ pub fn get_packet_buffer(&self) -> PacketBuffer { self.buffer_pool.get() }
/// Get a peer by address.
- pub fn peer(&self, a: Address) -> Option> {
- self.peers.get(&a).map(|peer| peer.value().clone())
- }
+ pub fn peer(&self, a: Address) -> Option> { self.peers.get(&a).map(|peer| peer.value().clone()) }
/// Get all peers currently in the peer cache.
pub fn peers(&self) -> Vec> {
@@ -207,14 +197,6 @@ impl Node {
v
}
- /// Get the current best root peer that we should use for WHOIS, relaying, etc.
- pub(crate) fn root(&self) -> Option> {
- self.roots.lock().first().map(|p| p.clone())
- }
-
- pub(crate) fn for_each_root_set(&self) {
- }
-
/// Run background tasks and return desired delay until next call in milliseconds.
///
/// This should only be called once at a time. It technically won't hurt anything to
@@ -252,68 +234,83 @@ impl Node {
if fragment_header.is_ok() {
let fragment_header = fragment_header.unwrap();
let time_ticks = ci.time_ticks();
- let dest = Address::from(&fragment_header.dest);
- if dest == self.identity.address() {
+ let dest = Address::from_bytes(&fragment_header.dest);
+ if dest.is_some() {
+ let dest = dest.unwrap();
+ if dest == self.identity.address() {
- let path = self.path(source_endpoint, source_local_socket, source_local_interface);
- path.log_receive(time_ticks);
- if fragment_header.is_fragment() {
+ let path = self.path(source_endpoint, source_local_socket, source_local_interface);
+ path.log_receive(time_ticks);
+ if fragment_header.is_fragment() {
- let _ = path.receive_fragment(fragment_header.id, fragment_header.fragment_no(), fragment_header.total_fragments(), data, time_ticks).map(|assembled_packet| {
- if assembled_packet.frags[0].is_some() {
- let frag0 = assembled_packet.frags[0].as_ref().unwrap();
- let packet_header = frag0.struct_at::(0);
- if packet_header.is_ok() {
- let packet_header = packet_header.unwrap();
- let source = Address::from(&packet_header.src);
+ let _ = path.receive_fragment(fragment_header.id, fragment_header.fragment_no(), fragment_header.total_fragments(), data, time_ticks).map(|assembled_packet| {
+ if assembled_packet.frags[0].is_some() {
+ let frag0 = assembled_packet.frags[0].as_ref().unwrap();
+ let packet_header = frag0.struct_at::(0);
+ if packet_header.is_ok() {
+ let packet_header = packet_header.unwrap();
+ let source = Address::from_bytes(&packet_header.src);
+ if source.is_some() {
+ let source = source.unwrap();
+ let peer = self.peer(source);
+ if peer.is_some() {
+ peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, frag0, &assembled_packet.frags[1..(assembled_packet.have as usize)]);
+ } else {
+ self.whois.query(self, ci, source, Some(QueuedPacket::Fragmented(assembled_packet)));
+ }
+ }
+ }
+ }
+ });
+
+ } else {
+
+ let packet_header = data.struct_at::(0);
+ if packet_header.is_ok() {
+ let packet_header = packet_header.unwrap();
+ let source = Address::from_bytes(&packet_header.src);
+ if source.is_some() {
+ let source = source.unwrap();
let peer = self.peer(source);
if peer.is_some() {
- peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, frag0, &assembled_packet.frags[1..(assembled_packet.have as usize)]);
+ peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, data.as_ref(), &[]);
} else {
- self.whois.query(self, ci, source, Some(QueuedPacket::Fragmented(assembled_packet)));
+ self.whois.query(self, ci, source, Some(QueuedPacket::Singular(data)));
}
}
}
- });
+
+ }
} else {
- let packet_header = data.struct_at::(0);
- if packet_header.is_ok() {
- let packet_header = packet_header.unwrap();
- let source = Address::from(&packet_header.src);
- let peer = self.peer(source);
- if peer.is_some() {
- peer.unwrap().receive(self, ci, ph, time_ticks, &path, &packet_header, data.as_ref(), &[]);
- } else {
- self.whois.query(self, ci, source, Some(QueuedPacket::Singular(data)));
- }
- }
-
- }
-
- } else {
-
- if fragment_header.is_fragment() {
- if fragment_header.increment_hops() > FORWARD_MAX_HOPS {
- return;
- }
- } else {
- let packet_header = data.struct_mut_at::(0);
- if packet_header.is_ok() {
- if packet_header.unwrap().increment_hops() > FORWARD_MAX_HOPS {
+ if fragment_header.is_fragment() {
+ if fragment_header.increment_hops() > FORWARD_MAX_HOPS {
return;
}
} else {
- return;
+ let packet_header = data.struct_mut_at::(0);
+ if packet_header.is_ok() {
+ if packet_header.unwrap().increment_hops() > FORWARD_MAX_HOPS {
+ return;
+ }
+ } else {
+ return;
+ }
}
- }
- let _ = self.peer(dest).map(|peer| peer.forward(ci, time_ticks, data.as_ref()));
+ let _ = self.peer(dest).map(|peer| peer.forward(ci, time_ticks, data.as_ref()));
- }
+ }
+ };
}
}
+ /// Get the current best root peer that we should use for WHOIS, relaying, etc.
+ pub(crate) fn root(&self) -> Option> { self.roots.lock().first().map(|p| p.clone()) }
+
+ /// Return true if a peer is a root.
+ pub(crate) fn is_peer_root(&self, peer: &Peer) -> bool { self.roots.lock().iter().any(|p| Arc::as_ptr(p) == (peer as *const Peer)) }
+
/// Get the canonical Path object for a given endpoint and local socket information.
///
/// This is a canonicalizing function that returns a unique path object for every tuple
diff --git a/network-hypervisor/src/vl1/path.rs b/network-hypervisor/src/vl1/path.rs
index 4a3566d38..be442e3e9 100644
--- a/network-hypervisor/src/vl1/path.rs
+++ b/network-hypervisor/src/vl1/path.rs
@@ -5,9 +5,9 @@ use parking_lot::Mutex;
use crate::util::U64PassThroughHasher;
use crate::vl1::Endpoint;
-use crate::vl1::fragmentedpacket::{FragmentedPacket, FRAGMENT_EXPIRATION, FRAGMENT_MAX_INBOUND_PACKETS_PER_PATH};
+use crate::vl1::fragmentedpacket::FragmentedPacket;
use crate::vl1::node::{PacketBuffer, VL1CallerInterface};
-use crate::vl1::protocol::PacketID;
+use crate::vl1::protocol::*;
/// Keepalive interval for paths in milliseconds.
pub(crate) const PATH_KEEPALIVE_INTERVAL: i64 = 20000;
@@ -41,29 +41,19 @@ impl Path {
}
#[inline(always)]
- pub fn endpoint(&self) -> &Endpoint {
- &self.endpoint
- }
+ pub fn endpoint(&self) -> &Endpoint { &self.endpoint }
#[inline(always)]
- pub fn local_socket(&self) -> i64 {
- self.local_socket
- }
+ pub fn local_socket(&self) -> i64 { self.local_socket }
#[inline(always)]
- pub fn local_interface(&self) -> i64 {
- self.local_interface
- }
+ pub fn local_interface(&self) -> i64 { self.local_interface }
#[inline(always)]
- pub fn last_send_time_ticks(&self) -> i64 {
- self.last_send_time_ticks.load(Ordering::Relaxed)
- }
+ pub fn last_send_time_ticks(&self) -> i64 { self.last_send_time_ticks.load(Ordering::Relaxed) }
#[inline(always)]
- pub fn last_receive_time_ticks(&self) -> i64 {
- self.last_receive_time_ticks.load(Ordering::Relaxed)
- }
+ pub fn last_receive_time_ticks(&self) -> i64 { self.last_receive_time_ticks.load(Ordering::Relaxed) }
/// Receive a fragment and return a FragmentedPacket if the entire packet was assembled.
/// This returns None if more fragments are needed to assemble the packet.
diff --git a/network-hypervisor/src/vl1/peer.rs b/network-hypervisor/src/vl1/peer.rs
index 2ff3a559e..cfd5e64c4 100644
--- a/network-hypervisor/src/vl1/peer.rs
+++ b/network-hypervisor/src/vl1/peer.rs
@@ -443,7 +443,7 @@ impl Peer {
dict.set_bytes(HELLO_DICT_KEY_EPHEMERAL_C25519, ephemeral_pair.c25519.public_bytes().to_vec());
dict.set_bytes(HELLO_DICT_KEY_EPHEMERAL_P521, ephemeral_pair.p521.public_key_bytes().to_vec());
});
- if node.is_root(self) {
+ if node.is_peer_root(self) {
// If the peer is a root we include some extra information for diagnostic and statistics
// purposes such as the CPU type, bits, and OS info. This is not sent to other peers.
dict.set_str(HELLO_DICT_KEY_SYS_ARCH, std::env::consts::ARCH);
@@ -480,7 +480,7 @@ impl Peer {
self.last_send_time_ticks.store(time_ticks, Ordering::Relaxed);
self.total_bytes_sent.fetch_add(packet.len() as u64, Ordering::Relaxed);
- path.map_or_else(|| {
+ path.as_ref().map_or_else(|| {
self.send_to_endpoint(ci, endpoint, None, None, packet_id, &packet)
}, |path| {
path.log_send(time_ticks);
diff --git a/network-hypervisor/src/vl1/protocol.rs b/network-hypervisor/src/vl1/protocol.rs
index db5b105f8..e13f6db00 100644
--- a/network-hypervisor/src/vl1/protocol.rs
+++ b/network-hypervisor/src/vl1/protocol.rs
@@ -149,6 +149,15 @@ pub const FORWARD_MAX_HOPS: u8 = 3;
/// Maximum difference between an OK in-re packet ID and the current packet ID counter.
pub const OK_PACKET_SEQUENCE_CUTOFF: u64 = 1000;
+/// Frequency for WHOIS retries
+pub const WHOIS_RETRY_INTERVAL: i64 = 1000;
+
+/// Maximum number of WHOIS retries
+pub const WHOIS_RETRY_MAX: u16 = 3;
+
+/// Maximum number of packets to queue up behind a WHOIS.
+pub const WHOIS_MAX_WAITING_PACKETS: usize = 64;
+
/// A unique packet identifier, also the cryptographic nonce.
///
/// Packet IDs are stored as u64s for efficiency but they should be treated as
@@ -174,14 +183,10 @@ unsafe impl RawObject for PacketHeader {}
impl PacketHeader {
#[inline(always)]
- pub fn cipher(&self) -> u8 {
- self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_CIPHER
- }
+ pub fn cipher(&self) -> u8 { self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_CIPHER }
#[inline(always)]
- pub fn hops(&self) -> u8 {
- self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_HOPS
- }
+ pub fn hops(&self) -> u8 { self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_HOPS }
#[inline(always)]
pub fn increment_hops(&mut self) -> u8 {
@@ -192,29 +197,13 @@ impl PacketHeader {
}
#[inline(always)]
- pub fn is_fragmented(&self) -> bool {
- (self.flags_cipher_hops & HEADER_FLAG_FRAGMENTED) != 0
- }
+ pub fn is_fragmented(&self) -> bool { (self.flags_cipher_hops & HEADER_FLAG_FRAGMENTED) != 0 }
#[inline(always)]
- pub fn destination(&self) -> Address {
- Address::from(&self.dest)
- }
+ pub fn id_bytes(&self) -> &[u8; 8] { unsafe { &*(self as *const Self).cast::<[u8; 8]>() } }
#[inline(always)]
- pub fn source(&self) -> Address {
- Address::from(&self.src)
- }
-
- #[inline(always)]
- pub fn id_bytes(&self) -> &[u8; 8] {
- unsafe { &*(self as *const Self).cast::<[u8; 8]>() }
- }
-
- #[inline(always)]
- pub fn as_bytes(&self) -> &[u8; PACKET_HEADER_SIZE] {
- unsafe { &*(self as *const Self).cast::<[u8; PACKET_HEADER_SIZE]>() }
- }
+ pub fn as_bytes(&self) -> &[u8; PACKET_HEADER_SIZE] { unsafe { &*(self as *const Self).cast::<[u8; PACKET_HEADER_SIZE]>() } }
#[inline(always)]
pub fn aad_bytes(&self) -> [u8; 11] {
@@ -253,24 +242,16 @@ unsafe impl RawObject for FragmentHeader {}
impl FragmentHeader {
#[inline(always)]
- pub fn is_fragment(&self) -> bool {
- self.fragment_indicator == FRAGMENT_INDICATOR
- }
+ pub fn is_fragment(&self) -> bool { self.fragment_indicator == FRAGMENT_INDICATOR }
#[inline(always)]
- pub fn total_fragments(&self) -> u8 {
- self.total_and_fragment_no >> 4
- }
+ pub fn total_fragments(&self) -> u8 { self.total_and_fragment_no >> 4 }
#[inline(always)]
- pub fn fragment_no(&self) -> u8 {
- self.total_and_fragment_no & 0x0f
- }
+ pub fn fragment_no(&self) -> u8 { self.total_and_fragment_no & 0x0f }
#[inline(always)]
- pub fn hops(&self) -> u8 {
- self.reserved_hops & HEADER_FLAGS_FIELD_MASK_HOPS
- }
+ pub fn hops(&self) -> u8 { self.reserved_hops & HEADER_FLAGS_FIELD_MASK_HOPS }
#[inline(always)]
pub fn increment_hops(&mut self) -> u8 {
@@ -281,14 +262,7 @@ impl FragmentHeader {
}
#[inline(always)]
- pub fn as_bytes(&self) -> &[u8; FRAGMENT_HEADER_SIZE] {
- unsafe { &*(self as *const Self).cast::<[u8; FRAGMENT_HEADER_SIZE]>() }
- }
-
- #[inline(always)]
- pub fn destination(&self) -> Address {
- Address::from(&self.dest)
- }
+ pub fn as_bytes(&self) -> &[u8; FRAGMENT_HEADER_SIZE] { unsafe { &*(self as *const Self).cast::<[u8; FRAGMENT_HEADER_SIZE]>() } }
}
pub(crate) mod message_component_structs {
diff --git a/network-hypervisor/src/vl1/rootset.rs b/network-hypervisor/src/vl1/rootset.rs
index b88bf516b..e4e6e388f 100644
--- a/network-hypervisor/src/vl1/rootset.rs
+++ b/network-hypervisor/src/vl1/rootset.rs
@@ -4,9 +4,9 @@ use std::io::Write;
use concat_arrays::concat_arrays;
-use crate::crypto::c25519::{ED25519_PUBLIC_KEY_SIZE, ED25519_SECRET_KEY_SIZE, ED25519_SIGNATURE_SIZE, ed25519_verify, Ed25519KeyPair};
+use crate::crypto::c25519::*;
use crate::crypto::hash::SHA384;
-use crate::crypto::p521::{P521_ECDSA_SIGNATURE_SIZE, P521_PUBLIC_KEY_SIZE, P521_SECRET_KEY_SIZE, P521KeyPair};
+use crate::crypto::p521::*;
use crate::crypto::secret::Secret;
use crate::error::InvalidFormatError;
use crate::vl1::{Endpoint, Identity};
@@ -253,11 +253,8 @@ impl RootSet {
let type_id = buf.read_u8(cursor)?;
match type_id {
ROOT_SET_TYPE_LEGACY_PLANET | ROOT_SET_TYPE_LEGACY_MOON => {
- let root_set_type = if type_id == ROOT_SET_TYPE_LEGACY_PLANET {
- Type::LegacyPlanet(buf.read_u64(cursor)?)
- } else {
- Type::LegacyMoon(buf.read_u64(cursor)?)
- };
+ let root_set_type = buf.read_u64(cursor)?;
+ let root_set_type = if type_id == ROOT_SET_TYPE_LEGACY_PLANET { Type::LegacyPlanet(root_set_type) } else { Type::LegacyMoon(root_set_type) };
let timestamp = buf.read_u64(cursor)?;
let signer = buf.read_bytes(64, cursor)?.to_vec();
let signature = buf.read_bytes(96, cursor)?.to_vec();
diff --git a/network-hypervisor/src/vl1/whois.rs b/network-hypervisor/src/vl1/whois.rs
index 561f79f8e..2f0b8ad92 100644
--- a/network-hypervisor/src/vl1/whois.rs
+++ b/network-hypervisor/src/vl1/whois.rs
@@ -4,18 +4,9 @@ use parking_lot::Mutex;
use crate::util::gate::IntervalGate;
use crate::vl1::Address;
-use crate::vl1::constants::*;
use crate::vl1::fragmentedpacket::FragmentedPacket;
use crate::vl1::node::{Node, PacketBuffer, VL1CallerInterface};
-
-/// Frequency for WHOIS retries
-pub const WHOIS_RETRY_INTERVAL: i64 = 1000;
-
-/// Maximum number of WHOIS retries
-pub const WHOIS_RETRY_MAX: u16 = 3;
-
-/// Maximum number of packets to queue up behind a WHOIS.
-pub const WHOIS_MAX_WAITING_PACKETS: usize = 64;
+use crate::vl1::protocol::{WHOIS_RETRY_INTERVAL, WHOIS_MAX_WAITING_PACKETS, WHOIS_RETRY_MAX};
pub(crate) enum QueuedPacket {
Singular(PacketBuffer),