mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-27 01:13:43 +02:00
Dictionary, and cleanup and other random stuff.
This commit is contained in:
parent
0809a8f313
commit
7a2361b62c
10 changed files with 343 additions and 62 deletions
|
@ -12,37 +12,59 @@ pub fn to_string(b: &[u8]) -> String {
|
|||
s
|
||||
}
|
||||
|
||||
/// Encode an unsigned 64-bit value as a string.
|
||||
pub fn to_string_u64(mut i: u64, skip_leading_zeroes: bool) -> String {
|
||||
let mut s = String::new();
|
||||
s.reserve(16);
|
||||
for _ in 0..16 {
|
||||
let ii = i >> 60;
|
||||
if ii != 0 || !s.is_empty() || !skip_leading_zeroes {
|
||||
s.push(HEX_CHARS[ii as usize] as char);
|
||||
}
|
||||
i = i.wrapping_shl(4);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Encode an unsigned 64-bit value as a string.
|
||||
pub fn to_vec_u64(mut i: u64, skip_leading_zeroes: bool) -> Vec<u8> {
|
||||
let mut s = Vec::new();
|
||||
s.reserve(16);
|
||||
for _ in 0..16 {
|
||||
let ii = i >> 60;
|
||||
if ii != 0 || !s.is_empty() || !skip_leading_zeroes {
|
||||
s.push(HEX_CHARS[ii as usize]);
|
||||
}
|
||||
i = i.wrapping_shl(4);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Decode a hex string, ignoring non-hexadecimal characters.
|
||||
pub fn from_string(s: &str) -> Vec<u8> {
|
||||
let mut b: Vec<u8> = Vec::new();
|
||||
b.reserve((s.len() / 2) + 1);
|
||||
|
||||
let mut byte = 0;
|
||||
let mut byte = 0_u8;
|
||||
let mut have_8: bool = false;
|
||||
for cc in s.as_bytes() {
|
||||
let c = *cc;
|
||||
if c >= 48 && c <= 57 {
|
||||
byte <<= 4;
|
||||
byte |= c - 48;
|
||||
byte = (byte.wrapping_shl(4)) | (c - 48);
|
||||
if have_8 {
|
||||
b.push(byte);
|
||||
byte = 0;
|
||||
}
|
||||
have_8 = !have_8;
|
||||
} else if c >= 65 && c <= 70 {
|
||||
byte <<= 4;
|
||||
byte |= c - 55;
|
||||
byte = (byte.wrapping_shl(4)) | (c - 55);
|
||||
if have_8 {
|
||||
b.push(byte);
|
||||
byte = 0;
|
||||
}
|
||||
have_8 = !have_8;
|
||||
} else if c >= 97 && c <= 102 {
|
||||
byte <<= 4;
|
||||
byte |= c - 87;
|
||||
byte = (byte.wrapping_shl(4)) | (c - 87);
|
||||
if have_8 {
|
||||
b.push(byte);
|
||||
byte = 0;
|
||||
}
|
||||
have_8 = !have_8;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
pub mod hex;
|
||||
|
||||
pub(crate) const ZEROES: [u8; 64] = [0_u8; 64];
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn equal_bytes(a: *const u8, b: *const u8, l: usize) -> bool {
|
||||
for i in 0..l {
|
||||
if *a.offset(i as isize) != *b.offset(i as isize) {
|
||||
|
@ -49,5 +52,3 @@ pub(crate) fn integer_load_be_u32(d: &[u8]) -> u32 {
|
|||
pub(crate) fn integer_load_be_u64(d: &[u8]) -> u64 {
|
||||
(d[0] as u64) << 56 | (d[1] as u64) << 48 | (d[2] as u64) << 40 | (d[3] as u64) << 32 | (d[4] as u64) << 24 | (d[5] as u64) << 16 | (d[6] as u64) << 8 | (d[7] as u64)
|
||||
}
|
||||
|
||||
pub(crate) const ZEROES: [u8; 64] = [0_u8; 64];
|
||||
|
|
|
@ -6,7 +6,6 @@ use crate::error::InvalidFormatError;
|
|||
use crate::util::hex::HEX_CHARS;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
pub struct Address(u64);
|
||||
|
||||
impl Address {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::mem::{size_of, MaybeUninit, transmute};
|
||||
use std::marker::PhantomData;
|
||||
use std::io::Write;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
const OVERFLOW_ERR_MSG: &'static str = "overflow";
|
||||
|
||||
|
@ -30,7 +29,7 @@ unsafe impl<H: RawObject, const L: usize> RawObject for Buffer<H, L> {}
|
|||
impl<H: RawObject, const L: usize> Default for Buffer<H, L> {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
assert!(size_of::<H>() <= L);
|
||||
debug_assert!(size_of::<H>() <= L);
|
||||
Buffer(size_of::<H>(), [0_u8; L], PhantomData::default())
|
||||
}
|
||||
}
|
||||
|
@ -38,31 +37,30 @@ impl<H: RawObject, const L: usize> Default for Buffer<H, L> {
|
|||
impl<H: RawObject, const L: usize> Buffer<H, L> {
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
assert!(size_of::<H>() <= L);
|
||||
debug_assert!(size_of::<H>() <= L);
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Change the header "personality" of this buffer.
|
||||
/// Note that the new buffer must be of the same size and both the old and
|
||||
/// new headers must be RawObjects with size less than or equal to this size.
|
||||
pub fn change_header_type<NH: RawObject>(self) -> Buffer<NH, L> {
|
||||
assert!(size_of::<NH>() <= L);
|
||||
unsafe { transmute(self) }
|
||||
/// This is a free operation, but the returned reference obviously only lives as long as the source.
|
||||
#[inline(always)]
|
||||
pub fn transmute_header<NH: RawObject>(&self) -> &Buffer<NH, L> {
|
||||
debug_assert!(size_of::<H>() <= L);
|
||||
debug_assert!(size_of::<NH>() <= L);
|
||||
unsafe {
|
||||
&*(self as *const Self).cast::<Buffer<NH, L>>()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a buffer that contains a copy of a slice.
|
||||
/// If the slice is larger than the maximum size L of the buffer, only the first L bytes
|
||||
/// are copied and the rest is ignored.
|
||||
/// Create a buffer that contains a copy of a slice, truncating if the slice is too long.
|
||||
#[inline(always)]
|
||||
pub fn from_bytes_truncate(b: &[u8]) -> Self {
|
||||
pub fn from_bytes_lossy(b: &[u8]) -> Self {
|
||||
let l = b.len().min(L);
|
||||
unsafe {
|
||||
let mut tmp = MaybeUninit::<Self>::uninit().assume_init();
|
||||
tmp.0 = l;
|
||||
tmp.1[0..l].copy_from_slice(b);
|
||||
tmp.1[l..L].fill(0);
|
||||
tmp
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
/// Get a slice containing the entire buffer in raw form including the header.
|
||||
|
@ -239,7 +237,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
/// Get the index of the start of the payload after the header.
|
||||
#[inline(always)]
|
||||
pub fn cursor_after_header(&self) -> usize {
|
||||
size_of::<usize>()
|
||||
size_of::<H>()
|
||||
}
|
||||
|
||||
/// Get a structure at a given position in the buffer and advance the cursor.
|
||||
|
@ -386,14 +384,6 @@ impl<H: RawObject, const L: usize> AsMut<H> for Buffer<H, L> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<H: RawObject, const L: usize> Hash for Buffer<H, L> {
|
||||
#[inline(always)]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
state.write_u32(self.0 as u32);
|
||||
state.write(&self.1[0..self.0]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::mem::size_of;
|
||||
|
|
212
network-hypervisor/src/vl1/dictionary.rs
Normal file
212
network-hypervisor/src/vl1/dictionary.rs
Normal file
|
@ -0,0 +1,212 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::io::Write;
|
||||
use crate::util::hex::HEX_CHARS;
|
||||
|
||||
/// Dictionary is an extremely simple key=value serialization format.
|
||||
/// It's designed for extreme parsing simplicity and is human readable if keys and values are strings.
|
||||
/// It also supports binary keys and values which will be minimally escaped but render the result not
|
||||
/// entirely human readable. Keys are serialized in natural sort order so the result can be consistently
|
||||
/// checksummed or hashed.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Dictionary(BTreeMap<String, Vec<u8>>);
|
||||
|
||||
impl Default for Dictionary {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Self(BTreeMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_escaped<W: Write>(b: &[u8], w: &mut W) -> std::io::Result<()> {
|
||||
let mut i = 0_usize;
|
||||
let l = b.len();
|
||||
while i < l {
|
||||
let ii = i + 1;
|
||||
match unsafe { b.get_unchecked(i) } {
|
||||
0 => { w.write_all(&[b'\\', b'0'])?; }
|
||||
b'\n' => { w.write_all(&[b'\\', b'n'])?; }
|
||||
b'\r' => { w.write_all(&[b'\\', b'r'])?; }
|
||||
b'=' => { w.write_all(&[b'\\', b'e'])?; }
|
||||
b'\\' => { w.write_all(&[b'\\', b'\\'])?; }
|
||||
_ => { w.write_all(&b[i..ii])?; }
|
||||
}
|
||||
i = ii;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn append_printable(s: &mut String, b: &[u8]) {
|
||||
for c in b {
|
||||
let c = *c as char;
|
||||
if c.is_alphanumeric() || c.is_whitespace() {
|
||||
s.push(c);
|
||||
} else {
|
||||
s.push('\\');
|
||||
s.push('x');
|
||||
s.push(HEX_CHARS[((c as u8) >> 4) as usize] as char);
|
||||
s.push(HEX_CHARS[((c as u8) & 0xf) as usize] as char);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dictionary {
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
Self(BTreeMap::new())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
|
||||
pub fn get_bytes(&self, k: &str) -> Option<&[u8]> {
|
||||
self.0.get(k).map_or(None, |v| Some(v.as_slice()))
|
||||
}
|
||||
|
||||
pub fn get_u64(&self, k: &str) -> Option<u64> {
|
||||
self.get_str(k).map_or(None, |s| u64::from_str_radix(s, 16).map_or(None, |i| Some(i)))
|
||||
}
|
||||
|
||||
pub fn get_i64(&self, k: &str) -> Option<i64> {
|
||||
self.get_str(k).map_or(None, |s| i64::from_str_radix(s, 16).map_or(None, |i| Some(i)))
|
||||
}
|
||||
|
||||
pub fn get_bool(&self, k: &str) -> Option<bool> {
|
||||
self.0.get(k).map_or(None, |v| {
|
||||
if v.is_empty() {
|
||||
Some(false)
|
||||
} else {
|
||||
Some(match unsafe { v.get_unchecked(0) } {
|
||||
b'1' | b't' | b'T' | b'y' | b'Y' => true,
|
||||
_ => false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_str(&mut self, k: &str, v: &str) {
|
||||
let _ = self.0.insert(String::from(k), v.as_bytes().to_vec());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_u64(&mut self, k: &str, v: u64) {
|
||||
let _ = self.0.insert(String::from(k), crate::util::hex::to_vec_u64(v, true));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_bytes(&mut self, k: &str, v: Vec<u8>) {
|
||||
let _ = self.0.insert(String::from(k), v);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_bool(&mut self, k: &str, v: bool) {
|
||||
let _ = self.0.insert(String::from(k), (if v { [b'1'] } else { [b'0'] }).to_vec());
|
||||
}
|
||||
|
||||
/// Write a dictionary in transport format to a writer.
|
||||
pub fn write_to<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
|
||||
for kv in self.0.iter() {
|
||||
write_escaped(kv.0.as_bytes(), w)?;
|
||||
w.write_all(&[b'='])?;
|
||||
write_escaped(kv.1.as_slice(), w)?;
|
||||
w.write_all(&[b'\n'])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write a dictionary in transport format to a byte vector.
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut b: Vec<u8> = Vec::new();
|
||||
b.reserve(32 * self.0.len());
|
||||
let _ = self.write_to(&mut b);
|
||||
b
|
||||
}
|
||||
|
||||
/// Decode a dictionary in byte format, or return None if the input is invalid.
|
||||
pub fn from_bytes(b: &[u8]) -> Option<Dictionary> {
|
||||
let mut d = Dictionary::new();
|
||||
let mut kv: [Vec<u8>; 2] = [Vec::new(), Vec::new()];
|
||||
let mut state = 0;
|
||||
let mut escape = false;
|
||||
for c in b {
|
||||
let c = *c;
|
||||
if escape {
|
||||
escape = false;
|
||||
kv[state].push(match c {
|
||||
b'0' => 0,
|
||||
b'n' => b'\n',
|
||||
b'r' => b'\r',
|
||||
_ => c // =, \, and escapes before other characters are unnecessary but not errors
|
||||
});
|
||||
} else if c == b'\\' {
|
||||
escape = true;
|
||||
} else if c == b'=' {
|
||||
if state != 0 {
|
||||
return None;
|
||||
}
|
||||
state = 1;
|
||||
} else if c == b'\n' {
|
||||
if state != 1 {
|
||||
return None;
|
||||
}
|
||||
state = 0;
|
||||
if !kv[0].is_empty() {
|
||||
if String::from_utf8(kv[0].clone()).map_or(true, |key| {
|
||||
d.0.insert(key, kv[1].clone());
|
||||
false
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
kv[0].clear();
|
||||
kv[1].clear();
|
||||
} else if c != b'\r' {
|
||||
kv[state].push(c);
|
||||
}
|
||||
}
|
||||
Some(d)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for Dictionary {
|
||||
/// Get the dictionary in an always readable format with non-printable characters replaced by '\xXX'.
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = String::new();
|
||||
for kv in self.0.iter() {
|
||||
append_printable(&mut s, kv.0.as_bytes());
|
||||
s.push('=');
|
||||
append_printable(&mut s, kv.1.as_slice());
|
||||
s.push('\n');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::vl1::dictionary::Dictionary;
|
||||
|
||||
#[test]
|
||||
fn dictionary() {
|
||||
let mut d = Dictionary::new();
|
||||
d.set_str("foo", "bar");
|
||||
d.set_u64("bar", 0xfeedcafebabebeef);
|
||||
d.set_bytes("baz", vec![1,2,3,4,5,6,7,8,9]);
|
||||
d.set_bool("lala", true);
|
||||
d.set_bool("haha", false);
|
||||
let bytes = d.to_bytes();
|
||||
let d2 = Dictionary::from_bytes(bytes.as_slice()).unwrap();
|
||||
assert!(d.eq(&d2));
|
||||
}
|
||||
}
|
|
@ -1,6 +1,18 @@
|
|||
use crate::vl1::{Address, MAC};
|
||||
use crate::vl1::inetaddress::InetAddress;
|
||||
use crate::vl1::buffer::{RawObject, Buffer};
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
const TYPE_NIL: u8 = 0;
|
||||
const TYPE_ZEROTIER: u8 = 1;
|
||||
const TYPE_ETHERNET: u8 = 2;
|
||||
const TYPE_WIFIDIRECT: u8 = 3;
|
||||
const TYPE_BLUETOOTH: u8 = 4;
|
||||
const TYPE_IP: u8 = 5;
|
||||
const TYPE_IPUDP: u8 = 6;
|
||||
const TYPE_IPTCP: u8 = 7;
|
||||
const TYPE_HTTP: u8 = 8;
|
||||
const TYPE_WEBRTC: u8 = 9;
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum Type {
|
||||
|
@ -16,7 +28,7 @@ pub enum Type {
|
|||
WebRTC = 9,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Endpoint {
|
||||
Nil,
|
||||
ZeroTier(Address),
|
||||
|
@ -120,23 +132,70 @@ impl Endpoint {
|
|||
Ok(Endpoint::IpUdp(ip))
|
||||
}
|
||||
} else {
|
||||
match (type_byte - 16) as Type {
|
||||
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::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 => {
|
||||
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_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()))
|
||||
}
|
||||
Type::WebRTC => {
|
||||
TYPE_WEBRTC => {
|
||||
let l = buf.get_u16(cursor)?;
|
||||
Ok(Endpoint::WebRTC(String::from_utf8_lossy(buf.get_bytes(l as usize, cursor)?).to_string()))
|
||||
}
|
||||
_ => std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "unrecognized endpoint type in stream"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Endpoint {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
match self {
|
||||
Endpoint::Nil => {
|
||||
state.write_u8(Type::Nil as u8);
|
||||
},
|
||||
Endpoint::ZeroTier(a) => {
|
||||
state.write_u8(Type::ZeroTier as u8);
|
||||
state.write_u64(a.to_u64())
|
||||
},
|
||||
Endpoint::Ethernet(m) => {
|
||||
state.write_u8(Type::Ethernet as u8);
|
||||
state.write_u64(m.to_u64())
|
||||
},
|
||||
Endpoint::WifiDirect(m) => {
|
||||
state.write_u8(Type::WifiDirect as u8);
|
||||
state.write_u64(m.to_u64())
|
||||
},
|
||||
Endpoint::Bluetooth(m) => {
|
||||
state.write_u8(Type::Bluetooth as u8);
|
||||
state.write_u64(m.to_u64())
|
||||
},
|
||||
Endpoint::Ip(ip) => {
|
||||
state.write_u8(Type::Ip as u8);
|
||||
ip.hash(state);
|
||||
},
|
||||
Endpoint::IpUdp(ip) => {
|
||||
state.write_u8(Type::IpUdp as u8);
|
||||
ip.hash(state);
|
||||
},
|
||||
Endpoint::IpTcp(ip) => {
|
||||
state.write_u8(Type::IpTcp as u8);
|
||||
ip.hash(state);
|
||||
},
|
||||
Endpoint::Http(url) => {
|
||||
state.write_u8(Type::Http as u8);
|
||||
url.hash(state);
|
||||
},
|
||||
Endpoint::WebRTC(offer) => {
|
||||
state.write_u8(Type::WebRTC as u8);
|
||||
offer.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,13 +207,13 @@ impl ToString for Endpoint {
|
|||
Endpoint::Nil => format!("nil"),
|
||||
Endpoint::ZeroTier(a) => format!("zt:{}", a.to_string()),
|
||||
Endpoint::Ethernet(m) => format!("eth:{}", m.to_string()),
|
||||
Endpoint::WifiDirect(m) => format!("wifid:{}", m.to_string()),
|
||||
Endpoint::WifiDirect(m) => format!("wifip2p:{}", m.to_string()),
|
||||
Endpoint::Bluetooth(m) => format!("bt:{}", m.to_string()),
|
||||
Endpoint::Ip(ip) => format!("ip:{}", ip.to_ip_string()),
|
||||
Endpoint::IpUdp(ip) => format!("udp:{}", ip.to_string()),
|
||||
Endpoint::IpTcp(ip) => format!("tcp:{}", ip.to_string()),
|
||||
Endpoint::Http(url) => url,
|
||||
Endpoint::WebRTC(offer) => format!("webrtc:offer:{}", urlencoding::encode(offer.as_str())),
|
||||
Endpoint::Http(url) => url.clone(),
|
||||
Endpoint::WebRTC(offer) => format!("webrtc:{}", urlencoding::encode(offer.as_str())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -422,7 +422,7 @@ 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::<NoHeader, 2048>::from_bytes_truncate(bytes);
|
||||
let buf = Buffer::<NoHeader, 2048>::from_bytes_lossy(bytes);
|
||||
let mut cursor: usize = 0;
|
||||
let id = Self::unmarshal(&buf, &mut cursor)?;
|
||||
Ok((id, cursor))
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::hash::{Hash, Hasher};
|
|||
use crate::error::InvalidFormatError;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
pub struct MAC(u64);
|
||||
|
||||
impl MAC {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
pub(crate) mod protocol;
|
||||
pub(crate) mod packet;
|
||||
pub(crate) mod buffer;
|
||||
pub(crate) mod node;
|
||||
|
||||
pub mod dictionary;
|
||||
pub mod identity;
|
||||
pub mod inetaddress;
|
||||
pub mod endpoint;
|
||||
pub(crate) mod node;
|
||||
|
||||
mod address;
|
||||
mod mac;
|
||||
|
|
|
@ -3,9 +3,6 @@ use std::ops::Not;
|
|||
|
||||
type PacketID = u64;
|
||||
|
||||
/// A packet buffer, but with no header "personality."
|
||||
pub type Buffer = crate::vl1::buffer::Buffer<crate::vl1::buffer::NoHeader, { crate::vl1::protocol::PACKET_SIZE_MAX }>;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(packed)]
|
||||
pub struct Header {
|
||||
|
|
Loading…
Add table
Reference in a new issue