mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-03 19:13:43 +02:00
Pool, concurrent map adapter, other Rusty stuff.
This commit is contained in:
parent
ed142273d0
commit
69176d47e8
19 changed files with 637 additions and 162 deletions
121
network-hypervisor/Cargo.lock
generated
121
network-hypervisor/Cargo.lock
generated
|
@ -86,6 +86,16 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "4.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
|
@ -162,6 +172,24 @@ dependencies = [
|
|||
"libgpg-error-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.98"
|
||||
|
@ -190,12 +218,40 @@ dependencies = [
|
|||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lz4_flex"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827b976d911b5d2e42b2ccfc7c0d2461a1414e8280436885218762fc529b3f8"
|
||||
dependencies = [
|
||||
"twox-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
|
@ -208,6 +264,31 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
|
@ -273,6 +354,21 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.126"
|
||||
|
@ -298,6 +394,18 @@ version = "1.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
|
@ -327,6 +435,16 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "twox-hash"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.13.0"
|
||||
|
@ -426,9 +544,12 @@ version = "2.0.0"
|
|||
dependencies = [
|
||||
"aes-gmac-siv",
|
||||
"base64",
|
||||
"dashmap",
|
||||
"ed25519-dalek",
|
||||
"gcrypt",
|
||||
"libc",
|
||||
"lz4_flex",
|
||||
"parking_lot",
|
||||
"rand_core",
|
||||
"urlencoding",
|
||||
"winapi",
|
||||
|
|
|
@ -3,11 +3,6 @@ name = "zerotier-network-hypervisor"
|
|||
version = "2.0.0"
|
||||
edition = "2018"
|
||||
|
||||
# [profile.test]
|
||||
# opt-level = 3
|
||||
# lto = true
|
||||
# codegen-units = 1
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 'z'
|
||||
|
@ -22,9 +17,12 @@ ed25519-dalek = "^1"
|
|||
gcrypt = "^0"
|
||||
base64 = "^0"
|
||||
urlencoding = "^2"
|
||||
lz4_flex = { version = "^0", features = ["safe-encode", "safe-decode", "checked-decode"] }
|
||||
dashmap = "^4"
|
||||
parking_lot = "^0"
|
||||
|
||||
[target."cfg(not(windows))".dependencies]
|
||||
libc = "^0"
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
winapi = { version = "0.3.9", features = ["handleapi", "ws2ipdef", "ws2tcpip"] }
|
||||
winapi = { version = "0.3.9", features = ["ws2tcpip"] }
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::mem::MaybeUninit;
|
|||
#[inline(always)]
|
||||
fn hash_int_le(sha: &mut crate::crypto::hash::SHA512, i: u64) {
|
||||
#[cfg(target_endian = "big")] {
|
||||
sha.update(i.to_le_bytes());
|
||||
sha.update(&i.to_le_bytes());
|
||||
}
|
||||
#[cfg(target_endian = "little")] {
|
||||
sha.update(unsafe { &*(&i as *const u64).cast::<[u8; 8]>() });
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
pub mod hex;
|
||||
pub(crate) mod pool;
|
||||
|
||||
pub(crate) const ZEROES: [u8; 64] = [0_u8; 64];
|
||||
|
||||
|
|
199
network-hypervisor/src/util/pool.rs
Normal file
199
network-hypervisor/src/util/pool.rs
Normal file
|
@ -0,0 +1,199 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use std::mem::size_of;
|
||||
|
||||
/// Trait for objects that can be used with Pool.
|
||||
pub trait Reusable: Default + Sized {
|
||||
fn reset(&mut self);
|
||||
}
|
||||
|
||||
struct PoolEntry<O: Reusable> {
|
||||
obj: O,
|
||||
return_pool: Weak<PoolInner<O>>,
|
||||
}
|
||||
|
||||
type PoolInner<O> = Mutex<Vec<*mut PoolEntry<O>>>;
|
||||
|
||||
/// Container for pooled objects that have been checked out of the pool.
|
||||
/// When this is dropped the object is returned to the pool or if the pool or is
|
||||
/// dropped if the pool has been dropped. There is also an into_raw() and from_raw()
|
||||
/// functionality that allows conversion to/from naked pointers to O for
|
||||
/// interoperation with C/C++ APIs.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone)]
|
||||
pub struct Pooled<O: Reusable>(*mut PoolEntry<O>);
|
||||
|
||||
impl<O: Reusable> Pooled<O> {
|
||||
/// Get a raw pointer to the object wrapped by this pooled object container.
|
||||
/// The returned raw pointer MUST be restored into a Pooled instance with
|
||||
/// from_raw() or memory will leak.
|
||||
#[inline(always)]
|
||||
pub unsafe fn into_raw(self) -> *mut O {
|
||||
debug_assert!(!self.0.is_null());
|
||||
debug_assert_eq!(self.0.cast::<u8>(), (&mut (*self.0).obj as *mut O).cast::<u8>());
|
||||
self.0.cast()
|
||||
}
|
||||
|
||||
/// Restore a raw pointer from into_raw() into a Pooled object.
|
||||
/// The supplied pointer MUST have been obtained from a Pooled object or
|
||||
/// undefined behavior will occur. Pointers from other sources can't be used
|
||||
/// here. None is returned if the pointer is null.
|
||||
#[inline(always)]
|
||||
pub unsafe fn from_raw(raw: *mut O) -> Option<Self> {
|
||||
if !raw.is_null() {
|
||||
Some(Self(raw.cast()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: Reusable> Deref for Pooled<O> {
|
||||
type Target = O;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
debug_assert!(!self.0.is_null());
|
||||
unsafe { &(*self.0).obj }
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: Reusable> AsRef<O> for Pooled<O> {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &O {
|
||||
debug_assert!(!self.0.is_null());
|
||||
unsafe { &(*self.0).obj }
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: Reusable> DerefMut for Pooled<O> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
debug_assert!(!self.0.is_null());
|
||||
unsafe { &mut (*self.0).obj }
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: Reusable> AsMut<O> for Pooled<O> {
|
||||
#[inline(always)]
|
||||
fn as_mut(&mut self) -> &mut O {
|
||||
debug_assert!(!self.0.is_null());
|
||||
unsafe { &mut (*self.0).obj }
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: Reusable> Drop for Pooled<O> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
Weak::upgrade(&(*self.0).return_pool).map_or_else(|| {
|
||||
drop(Box::from_raw(self.0))
|
||||
}, |p| {
|
||||
(*self.0).obj.reset();
|
||||
p.lock().push(self.0)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An object pool for Reusable objects.
|
||||
/// The pool is safe in that checked out objects return automatically when their Pooled
|
||||
/// transparent container is dropped, or deallocate if the pool has been dropped.
|
||||
pub struct Pool<O: Reusable>(Arc<PoolInner<O>>);
|
||||
|
||||
impl<O: Reusable> Pool<O> {
|
||||
pub fn new(initial_stack_capacity: usize) -> Self {
|
||||
Self(Arc::new(Mutex::new(Vec::with_capacity(initial_stack_capacity))))
|
||||
}
|
||||
|
||||
/// Get a pooled object, or allocate one if the pool is empty.
|
||||
pub fn get(&self) -> Pooled<O> {
|
||||
Pooled::<O>(self.0.lock().pop().map_or_else(|| {
|
||||
Box::into_raw(Box::new(PoolEntry::<O> {
|
||||
obj: O::default(),
|
||||
return_pool: Arc::downgrade(&self.0),
|
||||
}))
|
||||
}, |obj| {
|
||||
debug_assert!(!obj.is_null());
|
||||
obj
|
||||
}))
|
||||
}
|
||||
|
||||
/// Get approximate memory use in bytes (does not include checked out objects).
|
||||
#[inline(always)]
|
||||
pub fn pool_memory_bytes(&self) -> usize {
|
||||
self.0.lock().len() * (size_of::<PoolEntry<O>>() + size_of::<usize>())
|
||||
}
|
||||
|
||||
/// Dispose of all pooled objects, freeing any memory they use.
|
||||
/// If get() is called after this new objects will be allocated, and any outstanding
|
||||
/// objects will still be returned on drop unless the pool itself is dropped. This can
|
||||
/// be done to free some memory if there has been a spike in memory use.
|
||||
pub fn purge(&self) {
|
||||
let mut p = self.0.lock();
|
||||
for obj in p.iter() {
|
||||
drop(unsafe { Box::from_raw(*obj) });
|
||||
}
|
||||
p.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: Reusable> Drop for Pool<O> {
|
||||
fn drop(&mut self) {
|
||||
self.purge();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<O: Reusable> Sync for Pool<O> {}
|
||||
|
||||
unsafe impl<O: Reusable> Send for Pool<O> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::ops::DerefMut;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::util::pool::{Reusable, Pool};
|
||||
use std::sync::Arc;
|
||||
|
||||
struct ReusableTestObject(usize);
|
||||
|
||||
impl Default for ReusableTestObject {
|
||||
fn default() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Reusable for ReusableTestObject {
|
||||
fn reset(&mut self) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn threaded_pool_use() {
|
||||
let p: Arc<Pool<ReusableTestObject>> = Arc::new(Pool::new(2));
|
||||
let ctr = Arc::new(AtomicUsize::new(0));
|
||||
for _ in 0..64 {
|
||||
let p2 = p.clone();
|
||||
let ctr2 = ctr.clone();
|
||||
let _ = std::thread::spawn(move || {
|
||||
for _ in 0..16384 {
|
||||
let mut o1 = p2.get();
|
||||
o1.deref_mut().0 += 1;
|
||||
let mut o2 = p2.get();
|
||||
drop(o1);
|
||||
o2.deref_mut().0 += 1;
|
||||
ctr2.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
});
|
||||
}
|
||||
loop {
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
if ctr.load(Ordering::Relaxed) >= 16384 * 8 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//println!("pool memory size: {}", p.pool_memory_bytes());
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
use std::mem::{size_of, MaybeUninit, zeroed};
|
||||
use std::ptr::write_bytes;
|
||||
use std::mem::size_of;
|
||||
use std::io::Write;
|
||||
|
||||
const OVERFLOW_ERR_MSG: &'static str = "overflow";
|
||||
|
@ -9,7 +8,7 @@ const OVERFLOW_ERR_MSG: &'static str = "overflow";
|
|||
/// This is ONLY used for packed protocol header or segment objects.
|
||||
pub unsafe trait RawObject: Sized {}
|
||||
|
||||
/// A byte array that supports safe appending of data or raw objects.
|
||||
/// A byte array that supports safe and efficient appending of data or raw objects.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Buffer<const L: usize>(usize, [u8; L]);
|
||||
|
||||
|
@ -18,25 +17,28 @@ unsafe impl<const L: usize> RawObject for Buffer<L> {}
|
|||
impl<const L: usize> Default for Buffer<L> {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
unsafe { zeroed() }
|
||||
Self(0, [0_u8; L])
|
||||
}
|
||||
}
|
||||
|
||||
impl<const L: usize> Buffer<L> {
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
unsafe { zeroed() }
|
||||
Self(0, [0_u8; L])
|
||||
}
|
||||
|
||||
/// Create a buffer that contains a copy of a slice, truncating if the slice is too long.
|
||||
/// Get a Buffer that is a copy of a byte slice, or return None if the slice doesn't fit.
|
||||
#[inline(always)]
|
||||
pub fn from_bytes_lossy(b: &[u8]) -> Self {
|
||||
let l = b.len().min(L);
|
||||
let mut tmp = unsafe { MaybeUninit::<Self>::uninit().assume_init() };
|
||||
tmp.0 = l;
|
||||
tmp.1[0..l].copy_from_slice(b);
|
||||
tmp.1[l..L].fill(0);
|
||||
tmp
|
||||
pub fn from_bytes(b: &[u8]) -> Option<Self> {
|
||||
let l = b.len();
|
||||
if l <= L {
|
||||
let mut tmp = Self::new();
|
||||
tmp.0 = l;
|
||||
tmp.1[0..l].copy_from_slice(b);
|
||||
Some(tmp)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a slice containing the entire buffer in raw form including the header.
|
||||
|
@ -51,10 +53,11 @@ impl<const L: usize> Buffer<L> {
|
|||
&mut self.1[0..self.0]
|
||||
}
|
||||
|
||||
/// Erase contents and reset size to the size of the header.
|
||||
/// Erase contents and zero size.
|
||||
#[inline(always)]
|
||||
pub fn clear(&mut self) {
|
||||
unsafe { write_bytes((self as *mut Self).cast::<u8>(), 0, size_of::<Self>()) }
|
||||
pub fn reset(&mut self) {
|
||||
self.0 = 0;
|
||||
self.1.fill(0);
|
||||
}
|
||||
|
||||
/// Get the length of this buffer (including header, if any).
|
||||
|
@ -195,11 +198,28 @@ impl<const L: usize> Buffer<L> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get a structure at position 0.
|
||||
#[inline(always)]
|
||||
pub fn header<H: RawObject>(&self) -> &H {
|
||||
debug_assert!(size_of::<H>() <= L);
|
||||
debug_assert!(size_of::<H>() <= self.0);
|
||||
unsafe { &*self.1.as_ptr().cast::<H>() }
|
||||
}
|
||||
|
||||
/// Get a structure at position 0 (mutable).
|
||||
#[inline(always)]
|
||||
pub fn header_mut<H: RawObject>(&mut self) -> &mut H {
|
||||
debug_assert!(size_of::<H>() <= L);
|
||||
debug_assert!(size_of::<H>() <= self.0);
|
||||
unsafe { &mut *self.1.as_mut_ptr().cast::<H>() }
|
||||
}
|
||||
|
||||
/// Get a structure at a given position in the buffer and advance the cursor.
|
||||
#[inline(always)]
|
||||
pub fn get_struct<T: RawObject>(&self, cursor: &mut usize) -> std::io::Result<&T> {
|
||||
pub fn read_struct<T: RawObject>(&self, cursor: &mut usize) -> std::io::Result<&T> {
|
||||
let ptr = *cursor;
|
||||
let end = ptr + size_of::<T>();
|
||||
debug_assert!(end <= L);
|
||||
if end <= self.0 {
|
||||
*cursor = end;
|
||||
unsafe {
|
||||
|
@ -213,9 +233,10 @@ impl<const L: usize> Buffer<L> {
|
|||
/// Get a fixed length byte array and advance the cursor.
|
||||
/// This is slightly more efficient than reading a runtime sized byte slice.
|
||||
#[inline(always)]
|
||||
pub fn get_bytes_fixed<const S: usize>(&self, cursor: &mut usize) -> std::io::Result<&[u8; S]> {
|
||||
pub fn read_bytes_fixed<const S: usize>(&self, cursor: &mut usize) -> std::io::Result<&[u8; S]> {
|
||||
let ptr = *cursor;
|
||||
let end = ptr + S;
|
||||
debug_assert!(end <= L);
|
||||
if end <= self.0 {
|
||||
*cursor = end;
|
||||
unsafe {
|
||||
|
@ -228,9 +249,10 @@ impl<const L: usize> Buffer<L> {
|
|||
|
||||
/// Get a runtime specified length byte slice and advance the cursor.
|
||||
#[inline(always)]
|
||||
pub fn get_bytes(&self, l: usize, cursor: &mut usize) -> std::io::Result<&[u8]> {
|
||||
pub fn read_bytes(&self, l: usize, cursor: &mut usize) -> std::io::Result<&[u8]> {
|
||||
let ptr = *cursor;
|
||||
let end = ptr + l;
|
||||
debug_assert!(end <= L);
|
||||
if end <= self.0 {
|
||||
*cursor = end;
|
||||
Ok(&self.1[ptr..end])
|
||||
|
@ -241,8 +263,9 @@ impl<const L: usize> Buffer<L> {
|
|||
|
||||
/// Get the next u8 and advance the cursor.
|
||||
#[inline(always)]
|
||||
pub fn get_u8(&self, cursor: &mut usize) -> std::io::Result<u8> {
|
||||
pub fn read_u8(&self, cursor: &mut usize) -> std::io::Result<u8> {
|
||||
let ptr = *cursor;
|
||||
debug_assert!(ptr < L);
|
||||
if ptr < self.0 {
|
||||
*cursor = ptr + 1;
|
||||
Ok(self.1[ptr])
|
||||
|
@ -253,9 +276,10 @@ impl<const L: usize> Buffer<L> {
|
|||
|
||||
/// Get the next u16 and advance the cursor.
|
||||
#[inline(always)]
|
||||
pub fn get_u16(&self, cursor: &mut usize) -> std::io::Result<u16> {
|
||||
pub fn read_u16(&self, cursor: &mut usize) -> std::io::Result<u16> {
|
||||
let ptr = *cursor;
|
||||
let end = ptr + 2;
|
||||
debug_assert!(end <= L);
|
||||
if end <= self.0 {
|
||||
*cursor = end;
|
||||
Ok(crate::util::integer_load_be_u16(&self.1[ptr..end]))
|
||||
|
@ -266,9 +290,10 @@ impl<const L: usize> Buffer<L> {
|
|||
|
||||
/// Get the next u32 and advance the cursor.
|
||||
#[inline(always)]
|
||||
pub fn get_u32(&self, cursor: &mut usize) -> std::io::Result<u32> {
|
||||
pub fn read_u32(&self, cursor: &mut usize) -> std::io::Result<u32> {
|
||||
let ptr = *cursor;
|
||||
let end = ptr + 4;
|
||||
debug_assert!(end <= L);
|
||||
if end <= self.0 {
|
||||
*cursor = end;
|
||||
Ok(crate::util::integer_load_be_u32(&self.1[ptr..end]))
|
||||
|
@ -279,9 +304,10 @@ impl<const L: usize> Buffer<L> {
|
|||
|
||||
/// Get the next u64 and advance the cursor.
|
||||
#[inline(always)]
|
||||
pub fn get_u64(&self, cursor: &mut usize) -> std::io::Result<u64> {
|
||||
pub fn read_u64(&self, cursor: &mut usize) -> std::io::Result<u64> {
|
||||
let ptr = *cursor;
|
||||
let end = ptr + 8;
|
||||
debug_assert!(end <= L);
|
||||
if end <= self.0 {
|
||||
*cursor = end;
|
||||
Ok(crate::util::integer_load_be_u64(&self.1[ptr..end]))
|
||||
|
|
44
network-hypervisor/src/vl1/concurrentmap.rs
Normal file
44
network-hypervisor/src/vl1/concurrentmap.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
// This just defines a ConcurrentMap type, selecting standard locked HashMap for smaller systems
|
||||
// or DashMap on larger ones where it would be faster. It also defines some wrappers for read
|
||||
// and write locking that do nothing for DashMap and return a lock guard for RwLock<HashMap<>>.
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
#[allow(unused_imports)]
|
||||
use std::collections::HashMap;
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "powerpc64"))]
|
||||
use dashmap::DashMap;
|
||||
|
||||
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "powerpc64")))]
|
||||
pub type ConcurrentMap<K, V> = RwLock<HashMap<K, V>>;
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "powerpc64"))]
|
||||
pub type ConcurrentMap<K, V> = DashMap<K, V>;
|
||||
|
||||
/// Wrapper to get a read lock guard on a concurrent map.
|
||||
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "powerpc64")))]
|
||||
#[inline(always)]
|
||||
pub fn read<K, V>(m: &Arc<ConcurrentMap<K, V>>) -> RwLockReadGuard<HashMap<K, V>> {
|
||||
m.read().unwrap()
|
||||
}
|
||||
|
||||
/// Wrapper to get a read lock guard on a concurrent map.
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "powerpc64"))]
|
||||
#[inline(always)]
|
||||
pub fn read<K, V>(m: &Arc<ConcurrentMap<K, V>>) -> &ConcurrentMap<K, V> {
|
||||
m.as_ref()
|
||||
}
|
||||
|
||||
/// Wrapper to get a write lock guard on a concurrent map.
|
||||
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "powerpc64")))]
|
||||
#[inline(always)]
|
||||
pub fn write<K, V>(m: &Arc<ConcurrentMap<K, V>>) -> RwLockWriteGuard<HashMap<K, V>> {
|
||||
m.write().unwrap()
|
||||
}
|
||||
|
||||
/// Wrapper to get a write lock guard on a concurrent map.
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "powerpc64"))]
|
||||
#[inline(always)]
|
||||
pub fn write<K, V>(m: &Arc<ConcurrentMap<K, V>>) -> &ConcurrentMap<K, V> {
|
||||
m.as_ref()
|
||||
}
|
|
@ -27,13 +27,16 @@ pub const HEADER_FLAGS_FIELD_MASK_HOPS: u8 = 0x07;
|
|||
|
||||
/// Packet is not encrypted but contains a Poly1305 MAC of the plaintext.
|
||||
/// Poly1305 is initialized with Salsa20/12 in the same manner as SALSA2012_POLY1305.
|
||||
pub const CIPHER_NOCRYPT_POLY1305: u8 = 0;
|
||||
pub const CIPHER_NOCRYPT_POLY1305: u8 = 0x00;
|
||||
|
||||
/// Packet is encrypted and authenticated with Salsa20/12 and Poly1305.
|
||||
/// Construction is the same as that which is used in the NaCl secret box functions.
|
||||
pub const CIPHER_SALSA2012_POLY1305: u8 = 0x10;
|
||||
|
||||
/// Packet is encrypted and authenticated with AES-GMAC-SIV.
|
||||
/// Formerly 'NONE' which is deprecated; reserved for future use.
|
||||
pub const CIPHER_RESERVED: u8 = 0x20;
|
||||
|
||||
/// Packet is encrypted and authenticated with AES-GMAC-SIV (AES-256).
|
||||
pub const CIPHER_AES_GMAC_SIV: u8 = 0x30;
|
||||
|
||||
/// Header (outer) flag indicating that this packet has additional fragments.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::io::Write;
|
||||
|
||||
use crate::util::hex::HEX_CHARS;
|
||||
|
||||
/// Dictionary is an extremely simple key=value serialization format.
|
||||
|
@ -22,7 +23,7 @@ fn write_escaped<W: Write>(b: &[u8], w: &mut W) -> std::io::Result<()> {
|
|||
let l = b.len();
|
||||
while i < l {
|
||||
let ii = i + 1;
|
||||
match unsafe { b.get_unchecked(i) } {
|
||||
match b[i] {
|
||||
0 => { w.write_all(&[b'\\', b'0'])?; }
|
||||
b'\n' => { w.write_all(&[b'\\', b'n'])?; }
|
||||
b'\r' => { w.write_all(&[b'\\', b'r'])?; }
|
||||
|
@ -86,7 +87,7 @@ impl Dictionary {
|
|||
if v.is_empty() {
|
||||
Some(false)
|
||||
} else {
|
||||
Some(match unsafe { v.get_unchecked(0) } {
|
||||
Some(match v[0] {
|
||||
b'1' | b't' | b'T' | b'y' | b'Y' => true,
|
||||
_ => false
|
||||
})
|
||||
|
|
|
@ -126,7 +126,7 @@ impl Endpoint {
|
|||
}
|
||||
|
||||
pub fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<Endpoint> {
|
||||
let type_byte = buf.get_u8(cursor)?;
|
||||
let type_byte = buf.read_u8(cursor)?;
|
||||
if type_byte < 16 {
|
||||
let ip = InetAddress::unmarshal(buf, cursor)?;
|
||||
if ip.is_nil() {
|
||||
|
@ -137,20 +137,20 @@ impl Endpoint {
|
|||
} else {
|
||||
match type_byte - 16 {
|
||||
TYPE_NIL => Ok(Endpoint::Nil),
|
||||
TYPE_ZEROTIER => Ok(Endpoint::ZeroTier(Address::from(buf.get_bytes_fixed(cursor)?))),
|
||||
TYPE_ETHERNET => Ok(Endpoint::Ethernet(MAC::from(buf.get_bytes_fixed(cursor)?))),
|
||||
TYPE_WIFIDIRECT => Ok(Endpoint::WifiDirect(MAC::from(buf.get_bytes_fixed(cursor)?))),
|
||||
TYPE_BLUETOOTH => Ok(Endpoint::Bluetooth(MAC::from(buf.get_bytes_fixed(cursor)?))),
|
||||
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_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.get_u16(cursor)?;
|
||||
Ok(Endpoint::Http(String::from_utf8_lossy(buf.get_bytes(l as usize, cursor)?).to_string()))
|
||||
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.get_u16(cursor)?;
|
||||
Ok(Endpoint::WebRTC(String::from_utf8_lossy(buf.get_bytes(l as usize, cursor)?).to_string()))
|
||||
let l = buf.read_u16(cursor)?;
|
||||
Ok(Endpoint::WebRTC(String::from_utf8_lossy(buf.read_bytes(l as usize, cursor)?).to_string()))
|
||||
}
|
||||
_ => std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "unrecognized endpoint type in stream"))
|
||||
}
|
||||
|
|
124
network-hypervisor/src/vl1/headers.rs
Normal file
124
network-hypervisor/src/vl1/headers.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
use std::ops::Not;
|
||||
|
||||
use crate::vl1::buffer::{RawObject, Buffer};
|
||||
use crate::vl1::constants::{HEADER_FLAGS_FIELD_MASK_CIPHER, HEADER_FLAGS_FIELD_MASK_HOPS, HEADER_FLAG_FRAGMENTED, FRAGMENT_INDICATOR};
|
||||
use crate::vl1::Address;
|
||||
|
||||
/// A unique packet identifier, also the cryptographic nonce.
|
||||
/// Packet IDs are stored as u64s for efficiency but they should be treated as
|
||||
/// [u8; 8] fields in that their endianness is "wire" endian. If for some reason
|
||||
/// packet IDs need to be portably compared or shared across systems they should
|
||||
/// be treated as bytes not integers.
|
||||
type PacketID = u64;
|
||||
|
||||
/// ZeroTier unencrypted outer header
|
||||
/// This is the header for a complete packet. If the fragmented flag is set, it will
|
||||
/// arrive with one or more fragments that must be assembled to complete it.
|
||||
#[derive(Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct PacketHeader {
|
||||
pub id: PacketID,
|
||||
pub dest: [u8; 5],
|
||||
pub src: [u8; 5],
|
||||
pub flags_cipher_hops: u8,
|
||||
pub message_auth: [u8; 8],
|
||||
}
|
||||
|
||||
unsafe impl RawObject for PacketHeader {}
|
||||
|
||||
impl PacketHeader {
|
||||
#[inline(always)]
|
||||
pub fn cipher(&self) -> u8 {
|
||||
self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_CIPHER
|
||||
}
|
||||
|
||||
/// Get this packet's hops field.
|
||||
/// This is the only field in the unencrypted header that is not authenticated, allowing intermediate
|
||||
/// nodes to increment it as they forward packets between indirectly connected peers.
|
||||
#[inline(always)]
|
||||
pub fn hops(&self) -> u8 {
|
||||
self.flags_cipher_hops & HEADER_FLAGS_FIELD_MASK_HOPS
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn increment_hops(&mut self) {
|
||||
let f = self.flags_cipher_hops;
|
||||
self.flags_cipher_hops = (f & HEADER_FLAGS_FIELD_MASK_HOPS.not()) | ((f + 1) & HEADER_FLAGS_FIELD_MASK_HOPS);
|
||||
}
|
||||
|
||||
/// If true, this packet requires one or more fragments to fully assemble.
|
||||
/// The one with the full header is always fragment 0. Note that is_fragment() is checked first
|
||||
/// to see if this IS a fragment.
|
||||
#[inline(always)]
|
||||
pub fn is_fragmented(&self) -> bool {
|
||||
(self.flags_cipher_hops & HEADER_FLAG_FRAGMENTED) != 0
|
||||
}
|
||||
|
||||
/// If true, this packet is actually a fragment and its header should be interpreted as a FragmentHeader instead.
|
||||
#[inline(always)]
|
||||
pub fn is_fragment(&self) -> bool {
|
||||
self.src[0] == FRAGMENT_INDICATOR
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn destination(&self) -> Address {
|
||||
Address::from(&self.dest)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn source(&self) -> Address {
|
||||
Address::from(&self.src)
|
||||
}
|
||||
}
|
||||
|
||||
/// ZeroTier fragment header
|
||||
/// Fragments are indicated by byte 0xff at the start of the source address, which
|
||||
/// is normally illegal since addresses can't begin with that. Fragmented packets
|
||||
/// will arrive with the first fragment carrying a normal header with the fragment
|
||||
/// bit set and remaining fragments being these.
|
||||
#[derive(Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct FragmentHeader {
|
||||
pub id: PacketID, // packet ID
|
||||
pub dest: [u8; 5], // destination address
|
||||
pub fragment_indicator: u8, // always 0xff in fragments
|
||||
pub total_and_fragment_no: u8, // TTTTNNNN (fragment number, total fragments)
|
||||
pub reserved_hops: u8, // rrrrrHHH (3 hops bits, rest reserved)
|
||||
}
|
||||
|
||||
unsafe impl crate::vl1::buffer::RawObject for FragmentHeader {}
|
||||
|
||||
impl FragmentHeader {
|
||||
#[inline(always)]
|
||||
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
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn hops(&self) -> u8 {
|
||||
self.reserved_hops & HEADER_FLAGS_FIELD_MASK_HOPS
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn destination(&self) -> Address {
|
||||
Address::from(&self.dest)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::mem::size_of;
|
||||
use crate::vl1::headers::{PacketHeader, FragmentHeader};
|
||||
use crate::vl1::constants::{PACKET_HEADER_SIZE, FRAGMENT_SIZE_MIN};
|
||||
|
||||
#[test]
|
||||
fn object_sizing() {
|
||||
assert_eq!(size_of::<PacketHeader>(), PACKET_HEADER_SIZE);
|
||||
assert_eq!(size_of::<FragmentHeader>(), FRAGMENT_SIZE_MIN);
|
||||
}
|
||||
}
|
|
@ -51,8 +51,7 @@ pub struct Identity {
|
|||
/// Compute result from the bespoke "frankenhash" from the old V0 work function.
|
||||
/// The supplied genmem_ptr must be of size V0_IDENTITY_GEN_MEMORY and aligned to an 8-byte boundary.
|
||||
fn v0_frankenhash(digest: &mut [u8; 64], genmem_ptr: *mut u8) {
|
||||
let genmem = unsafe { &mut *slice_from_raw_parts_mut(genmem_ptr, V0_IDENTITY_GEN_MEMORY) };
|
||||
let genmem_alias_hack = unsafe { &*slice_from_raw_parts(genmem_ptr, V0_IDENTITY_GEN_MEMORY) };
|
||||
let (genmem, genmem_alias_hack) = unsafe { (&mut *slice_from_raw_parts_mut(genmem_ptr, V0_IDENTITY_GEN_MEMORY), &*slice_from_raw_parts(genmem_ptr, V0_IDENTITY_GEN_MEMORY)) };
|
||||
let genmem_u64_ptr = genmem_ptr.cast::<u64>();
|
||||
|
||||
let mut s20 = Salsa::new(&digest[0..32], &digest[32..40], false).unwrap();
|
||||
|
@ -67,13 +66,15 @@ fn v0_frankenhash(digest: &mut [u8; 64], genmem_ptr: *mut u8) {
|
|||
|
||||
i = 0;
|
||||
while i < (V0_IDENTITY_GEN_MEMORY / 8) {
|
||||
let idx1 = ((unsafe { *genmem_u64_ptr.offset(i as isize) }.to_be() % 8) * 8) as usize;
|
||||
let idx2 = (unsafe { *genmem_u64_ptr.offset((i + 1) as isize) }.to_be() % (V0_IDENTITY_GEN_MEMORY as u64 / 8)) as usize;
|
||||
let genmem_u64_at_idx2_ptr = unsafe { genmem_u64_ptr.offset(idx2 as isize) };
|
||||
let tmp = unsafe { *genmem_u64_at_idx2_ptr };
|
||||
let digest_u64_ptr = unsafe { digest.as_mut_ptr().offset(idx1 as isize).cast::<u64>() };
|
||||
unsafe { *genmem_u64_at_idx2_ptr = *digest_u64_ptr };
|
||||
unsafe { *digest_u64_ptr = tmp };
|
||||
unsafe {
|
||||
let idx1 = (((*genmem_u64_ptr.offset(i as isize)).to_be() % 8) * 8) as usize;
|
||||
let idx2 = ((*genmem_u64_ptr.offset((i + 1) as isize)).to_be() % (V0_IDENTITY_GEN_MEMORY as u64 / 8)) as usize;
|
||||
let genmem_u64_at_idx2_ptr = genmem_u64_ptr.offset(idx2 as isize);
|
||||
let tmp = *genmem_u64_at_idx2_ptr;
|
||||
let digest_u64_ptr = digest.as_mut_ptr().offset(idx1 as isize).cast::<u64>();
|
||||
*genmem_u64_at_idx2_ptr = *digest_u64_ptr;
|
||||
*digest_u64_ptr = tmp;
|
||||
}
|
||||
s20.crypt_in_place(digest);
|
||||
i += 2;
|
||||
}
|
||||
|
@ -255,7 +256,7 @@ impl Identity {
|
|||
//
|
||||
// For NIST P-521 key agreement, we use a single step key derivation function to derive
|
||||
// the final shared secret using the C25519 shared secret as a "salt." This should be
|
||||
// FIPS140-compliant as per section 8.2 of:
|
||||
// FIPS-compliant as per section 8.2 of:
|
||||
//
|
||||
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Cr2.pdf
|
||||
//
|
||||
|
@ -382,15 +383,15 @@ impl Identity {
|
|||
/// Deserialize an Identity from a buffer.
|
||||
/// The supplied cursor is advanced.
|
||||
pub fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<Identity> {
|
||||
let addr = Address::from_bytes(buf.get_bytes_fixed::<5>(cursor)?).unwrap();
|
||||
let id_type = buf.get_u8(cursor)?;
|
||||
let addr = Address::from_bytes(buf.read_bytes_fixed::<5>(cursor)?).unwrap();
|
||||
let id_type = buf.read_u8(cursor)?;
|
||||
if id_type == Type::C25519 as u8 {
|
||||
let c25519_public_bytes = buf.get_bytes_fixed::<{ C25519_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let ed25519_public_bytes = buf.get_bytes_fixed::<{ ED25519_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let secrets_len = buf.get_u8(cursor)?;
|
||||
let c25519_public_bytes = buf.read_bytes_fixed::<{ C25519_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let ed25519_public_bytes = buf.read_bytes_fixed::<{ ED25519_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let secrets_len = buf.read_u8(cursor)?;
|
||||
if secrets_len == (C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE) as u8 {
|
||||
let c25519_secret_bytes = buf.get_bytes_fixed::<{ C25519_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let ed25519_secret_bytes = buf.get_bytes_fixed::<{ ED25519_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let c25519_secret_bytes = buf.read_bytes_fixed::<{ C25519_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let ed25519_secret_bytes = buf.read_bytes_fixed::<{ ED25519_SECRET_KEY_SIZE }>(cursor)?;
|
||||
Ok(Identity {
|
||||
address: addr,
|
||||
c25519: c25519_public_bytes.clone(),
|
||||
|
@ -414,18 +415,18 @@ impl Identity {
|
|||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "unrecognized scret key length (type 0)"))
|
||||
}
|
||||
} else if id_type == Type::P521 as u8 {
|
||||
let c25519_public_bytes = buf.get_bytes_fixed::<{ C25519_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let ed25519_public_bytes = buf.get_bytes_fixed::<{ ED25519_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let p521_ecdh_public_bytes = buf.get_bytes_fixed::<{ P521_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let p521_ecdsa_public_bytes = buf.get_bytes_fixed::<{ P521_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let p521_signature = buf.get_bytes_fixed::<{ P521_ECDSA_SIGNATURE_SIZE }>(cursor)?;
|
||||
let bh_digest = buf.get_bytes_fixed::<{ SHA512_HASH_SIZE }>(cursor)?;
|
||||
let secrets_len = buf.get_u8(cursor)?;
|
||||
let c25519_public_bytes = buf.read_bytes_fixed::<{ C25519_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let ed25519_public_bytes = buf.read_bytes_fixed::<{ ED25519_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let p521_ecdh_public_bytes = buf.read_bytes_fixed::<{ P521_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let p521_ecdsa_public_bytes = buf.read_bytes_fixed::<{ P521_PUBLIC_KEY_SIZE }>(cursor)?;
|
||||
let p521_signature = buf.read_bytes_fixed::<{ P521_ECDSA_SIGNATURE_SIZE }>(cursor)?;
|
||||
let bh_digest = buf.read_bytes_fixed::<{ SHA512_HASH_SIZE }>(cursor)?;
|
||||
let secrets_len = buf.read_u8(cursor)?;
|
||||
if secrets_len == (C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE) as u8 {
|
||||
let c25519_secret_bytes = buf.get_bytes_fixed::<{ C25519_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let ed25519_secret_bytes = buf.get_bytes_fixed::<{ ED25519_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let p521_ecdh_secret_bytes = buf.get_bytes_fixed::<{ P521_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let p521_ecdsa_secret_bytes = buf.get_bytes_fixed::<{ P521_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let c25519_secret_bytes = buf.read_bytes_fixed::<{ C25519_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let ed25519_secret_bytes = buf.read_bytes_fixed::<{ ED25519_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let p521_ecdh_secret_bytes = buf.read_bytes_fixed::<{ P521_SECRET_KEY_SIZE }>(cursor)?;
|
||||
let p521_ecdsa_secret_bytes = buf.read_bytes_fixed::<{ P521_SECRET_KEY_SIZE }>(cursor)?;
|
||||
Ok(Identity {
|
||||
address: addr,
|
||||
c25519: c25519_public_bytes.clone(),
|
||||
|
@ -464,10 +465,14 @@ impl Identity {
|
|||
/// On success the identity and the number of bytes actually read from the slice are
|
||||
/// returned.
|
||||
pub fn unmarshal_from_bytes(bytes: &[u8]) -> std::io::Result<(Identity, usize)> {
|
||||
let buf = Buffer::<2048>::from_bytes_lossy(bytes);
|
||||
let mut cursor: usize = 0;
|
||||
let id = Self::unmarshal(&buf, &mut cursor)?;
|
||||
Ok((id, cursor))
|
||||
let buf = Buffer::<2048>::from_bytes(bytes);
|
||||
if buf.is_none() {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "data object too large"))
|
||||
} else {
|
||||
let mut cursor: usize = 0;
|
||||
let id = Self::unmarshal(buf.as_ref().unwrap(), &mut cursor)?;
|
||||
Ok((id, cursor))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get this identity in string format, including its secret keys.
|
||||
|
|
|
@ -225,6 +225,24 @@ impl InetAddress {
|
|||
}
|
||||
}
|
||||
|
||||
/// Fills in the InetAddress specific parts of a path lookup key.
|
||||
/// This assumes that the key's default contents are zero bits and does not clear unused regions.
|
||||
pub(crate) fn fill_path_lookup_key(&self, k: &mut [u64; 4]) {
|
||||
unsafe {
|
||||
match self.sa.sa_family as u8 {
|
||||
AF_INET => {
|
||||
k[1] |= self.sin.sin_port as u64 | 0x40000; // OR because most significant 32 bits contain endpoint info
|
||||
k[2] = self.sin.sin_addr.s_addr as u64;
|
||||
}
|
||||
AF_INET6 => {
|
||||
k[1] |= self.sin6.sin6_port as u64 | 0x60000; // OR because most significant 32 bits contain endpoint info
|
||||
copy_nonoverlapping((&(self.sin6.sin6_addr) as *const in6_addr).cast::<u8>(), k.as_mut_ptr().cast::<u8>().offset(16), 16);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the IP port.
|
||||
#[inline(always)]
|
||||
pub fn set_port(&mut self, port: u16) {
|
||||
|
@ -400,13 +418,13 @@ impl InetAddress {
|
|||
}
|
||||
|
||||
pub fn unmarshal<const BL: usize>(buf: &Buffer<BL>, cursor: &mut usize) -> std::io::Result<InetAddress> {
|
||||
match buf.get_u8(cursor)? {
|
||||
match buf.read_u8(cursor)? {
|
||||
4 => {
|
||||
let b: &[u8; 6] = buf.get_bytes_fixed(cursor)?;
|
||||
let b: &[u8; 6] = buf.read_bytes_fixed(cursor)?;
|
||||
Ok(InetAddress::from_ip_port(&b[0..4], crate::util::integer_load_be_u16(&b[4..6])))
|
||||
}
|
||||
6 => {
|
||||
let b: &[u8; 18] = buf.get_bytes_fixed(cursor)?;
|
||||
let b: &[u8; 18] = buf.read_bytes_fixed(cursor)?;
|
||||
Ok(InetAddress::from_ip_port(&b[0..16], crate::util::integer_load_be_u16(&b[16..18])))
|
||||
}
|
||||
_ => Ok(InetAddress::new())
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
pub(crate) mod concurrentmap;
|
||||
pub(crate) mod constants;
|
||||
pub(crate) mod protocol;
|
||||
pub(crate) mod headers;
|
||||
pub(crate) mod buffer;
|
||||
pub(crate) mod node;
|
||||
pub(crate) mod path;
|
||||
pub(crate) mod peer;
|
||||
pub(crate) mod state;
|
||||
|
||||
pub mod dictionary;
|
||||
pub mod identity;
|
||||
pub mod inetaddress;
|
||||
pub mod endpoint;
|
||||
|
||||
mod dictionary;
|
||||
mod address;
|
||||
mod mac;
|
||||
|
||||
|
@ -17,3 +19,4 @@ pub use address::Address;
|
|||
pub use mac::MAC;
|
||||
pub use identity::Identity;
|
||||
pub use endpoint::Endpoint;
|
||||
pub use dictionary::Dictionary;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::vl1::{Address, Identity};
|
||||
use crate::vl1::concurrentmap::ConcurrentMap;
|
||||
use crate::vl1::path::Path;
|
||||
use crate::vl1::peer::Peer;
|
||||
|
||||
pub struct Node {
|
||||
identity: Identity,
|
||||
paths: ConcurrentMap<[u64; 4], Arc<Path>>,
|
||||
peers: ConcurrentMap<Address, Arc<Peer>>,
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub struct Path;
|
|
@ -0,0 +1 @@
|
|||
pub struct Peer;
|
|
@ -1,82 +0,0 @@
|
|||
use crate::vl1::constants::{HEADER_FLAGS_FIELD_MASK_CIPHER, HEADER_FLAGS_FIELD_MASK_HOPS, HEADER_FLAG_FRAGMENTED};
|
||||
use std::ops::Not;
|
||||
use crate::vl1::buffer::RawObject;
|
||||
|
||||
type PacketID = u64;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct PacketHeader {
|
||||
pub id: PacketID,
|
||||
pub dest: [u8; 5],
|
||||
pub src: [u8; 5],
|
||||
pub flags_cipher_hops: u8,
|
||||
pub message_auth: [u8; 8],
|
||||
}
|
||||
|
||||
unsafe impl RawObject for PacketHeader {}
|
||||
|
||||
impl PacketHeader {
|
||||
#[inline(always)]
|
||||
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
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn increment_hops(&mut self) {
|
||||
let f = self.flags_cipher_hops;
|
||||
self.flags_cipher_hops = (f & HEADER_FLAGS_FIELD_MASK_HOPS.not()) | ((f + 1) & HEADER_FLAGS_FIELD_MASK_HOPS);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_fragmented(&self) -> bool {
|
||||
(self.flags_cipher_hops & HEADER_FLAG_FRAGMENTED) != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct FragmentHeader {
|
||||
pub id: PacketID,
|
||||
pub dest: [u8; 5],
|
||||
pub fragment_indicator: u8,
|
||||
pub total_and_fragment_no: u8,
|
||||
pub hops: u8,
|
||||
}
|
||||
|
||||
unsafe impl crate::vl1::buffer::RawObject for FragmentHeader {}
|
||||
|
||||
impl FragmentHeader {
|
||||
#[inline(always)]
|
||||
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
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn hops(&self) -> u8 {
|
||||
self.hops & HEADER_FLAGS_FIELD_MASK_HOPS
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::mem::size_of;
|
||||
use crate::vl1::protocol::{PacketHeader, FragmentHeader};
|
||||
use crate::vl1::constants::{PACKET_HEADER_SIZE, FRAGMENT_SIZE_MIN};
|
||||
|
||||
#[test]
|
||||
fn object_sizing() {
|
||||
assert_eq!(size_of::<PacketHeader>(), PACKET_HEADER_SIZE);
|
||||
assert_eq!(size_of::<FragmentHeader>(), FRAGMENT_SIZE_MIN);
|
||||
}
|
||||
}
|
0
network-hypervisor/src/vl1/state.rs
Normal file
0
network-hypervisor/src/vl1/state.rs
Normal file
Loading…
Add table
Reference in a new issue