A bunch of cleanup, and make MAC and Address idiomatic in the sense that they have no native nil value and use NonZero for zero-cost use of Option<>

This commit is contained in:
Adam Ierymenko 2021-08-20 11:25:36 -04:00
parent 40941a25f7
commit bd4367014e
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
15 changed files with 375 additions and 452 deletions

View file

@ -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<Address, InvalidFormatError> {
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<Address> {
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<Address> {
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<const BL: usize>(&self, buf: &mut Buffer<BL>) -> 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<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<Option<Self>> {
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<Self, Self::Err> {
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<H: Hasher>(&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<u64> for Address {
#[inline(always)]
fn from(i: u64) -> Address {
debug_assert!((i >> 24) == 0);
Address(i)
state.write_u64(self.0.get());
}
}

View file

@ -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<const L: usize> RawObject for Buffer<L> {}
impl<const L: usize> Default for Buffer<L> {
#[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<const L: usize> Buffer<L> {
#[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<const L: usize> Buffer<L> {
}
#[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<const L: usize> Buffer<L> {
}
#[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<const L: usize> Buffer<L> {
}
}
/// 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<const L: usize> Buffer<L> {
}
}
/// 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<u64> {
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<u8> {
@ -366,35 +386,25 @@ impl<const L: usize> Write for Buffer<L> {
}
#[inline(always)]
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
}
impl<const L: usize> AsRef<[u8]> for Buffer<L> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
fn as_ref(&self) -> &[u8] { self.as_bytes() }
}
impl<const L: usize> AsMut<[u8]> for Buffer<L> {
#[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<const L: usize>;
impl<const L: usize> PoolFactory<Buffer<L>> for PooledBufferFactory<L> {
#[inline(always)]
fn create(&self) -> Buffer<L> {
Buffer::new()
}
fn create(&self) -> Buffer<L> { Buffer::new() }
#[inline(always)]
fn reset(&self, obj: &mut Buffer<L>) {
obj.clear();
}
fn reset(&self, obj: &mut Buffer<L>) { obj.clear(); }
}

View file

@ -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)))

View file

@ -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<BL>, 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<Ordering> {
Some(self.cmp(other))
}
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 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 {

View file

@ -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 {

View file

@ -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::<InetAddress>::uninit().assume_init();
copy_nonoverlapping((self as *const Self).cast::<u8>(), (&mut c as *mut Self).cast::<u8>(), size_of::<Self>());
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::<u8>(), 0, size_of::<Self>()) };
}
pub fn zero(&mut self) { unsafe { write_bytes((self as *mut Self).cast::<u8>(), 0, size_of::<Self>()) }; }
/// 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<Ordering> {
Some(self.cmp(other))
}
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 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::<u8>(), size_of::<Self>())).cmp(&*slice_from_raw_parts((other as *const Self).cast::<u8>(), size_of::<Self>()))
}
}
} 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() {

View file

@ -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<Locator> {
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<const BL: usize>(&self, buf: &mut Buffer<BL>, 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<const BL: usize>(&self, buf: &mut Buffer<BL>) -> std::io::Result<()> {
self.marshal_internal(buf, false)
}
pub(crate) fn marshal<const BL: usize>(&self, buf: &mut Buffer<BL>) -> std::io::Result<()> { self.marshal_internal(buf, false) }
pub fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<Self> {
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<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<Self> {
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<Endpoint> = 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(),

View file

@ -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<MAC, InvalidFormatError> {
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<MAC> {
if i != 0 {
Some(MAC(unsafe { NonZeroU64::new_unchecked(i & 0xffffffffffff) }))
} else {
Err(InvalidFormatError)
None
}
}
#[inline(always)]
pub fn from_bytes(b: &[u8]) -> Option<MAC> {
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<const BL: usize>(&self, buf: &mut Buffer<BL>) -> 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<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<Option<Self>> {
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<Self, Self::Err> {
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<H: Hasher>(&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<u64> for MAC {
#[inline(always)]
fn from(i: u64) -> MAC {
MAC(i)
state.write_u64(self.0.get());
}
}

View file

@ -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;

View file

@ -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<Arc<Locator>> {
self.locator.lock().clone()
}
pub fn locator(&self) -> Option<Arc<Locator>> { 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<Arc<Peer>> {
self.peers.get(&a).map(|peer| peer.value().clone())
}
pub fn peer(&self, a: Address) -> Option<Arc<Peer>> { self.peers.get(&a).map(|peer| peer.value().clone()) }
/// Get all peers currently in the peer cache.
pub fn peers(&self) -> Vec<Arc<Peer>> {
@ -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<Arc<Peer>> {
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::<PacketHeader>(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::<PacketHeader>(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::<PacketHeader>(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::<PacketHeader>(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::<PacketHeader>(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::<PacketHeader>(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<Arc<Peer>> { 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

View file

@ -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.

View file

@ -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);

View file

@ -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 {

View file

@ -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();

View file

@ -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),