From 5ba672274ce36937fcfa325703e8301b42a9811f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 4 Jan 2021 19:36:47 -0500 Subject: [PATCH] Rust cleanup. --- core/zerotier.h | 46 ++++++++++++++++++ rust-zerotier-core/src/buffer.rs | 67 +++++++++++++++++---------- rust-zerotier-core/src/certificate.rs | 2 +- rust-zerotier-core/src/endpoint.rs | 2 +- rust-zerotier-core/src/fingerprint.rs | 7 +-- rust-zerotier-core/src/identity.rs | 2 +- rust-zerotier-core/src/inetaddress.rs | 33 ++++++++++--- rust-zerotier-core/src/lib.rs | 4 +- rust-zerotier-core/src/mac.rs | 18 ++++--- rust-zerotier-core/src/node.rs | 19 ++++---- 10 files changed, 141 insertions(+), 59 deletions(-) diff --git a/core/zerotier.h b/core/zerotier.h index ad210c763..980b62be8 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -2943,6 +2943,9 @@ ZT_SDK_API int ZT_Fingerprint_fromString(ZT_Fingerprint *fp, const char *s); #define ZT_InetAddress_cast_const_sockaddr_in6_ptr(a) ((const struct sockaddr_in6 *)(&(a))) #define ZT_InetAddress_cast_const_sockaddr_storage_ptr(a) ((const struct sockaddr_storage *)(&(a))) +/** + * Zero the contents of an InetAddress + */ ZT_SDK_API void ZT_InetAddress_clear(ZT_InetAddress *ia); /** @@ -2955,22 +2958,65 @@ ZT_SDK_API void ZT_InetAddress_clear(ZT_InetAddress *ia); */ ZT_SDK_API char *ZT_InetAddress_toString(const ZT_InetAddress *ia, char *buf, unsigned int cap); +/** + * Parse an InetAddress in IP/port format + * + * @param ia InetAddress to fill with results + * @param str String to parse + * @return Non-zero on success, zero if IP/port is invalid + */ ZT_SDK_API int ZT_InetAddress_fromString(ZT_InetAddress *ia, const char *str); +/** + * Set to the value of a sockaddr such as sockaddr_in or sockaddr_in6. + * + * This takes a void type pointer to a sockaddr to avoid having to include + * all the network headers within zerotier.h. It's the responsibility of + * the caller to ensure that a valid sockaddr is supplied. + * + * @param ia InetAddress to fill + * @param saddr A pointer to a sockaddr + */ ZT_SDK_API void ZT_InetAddress_set(ZT_InetAddress *ia, const void *saddr); +/** + * Set raw IP bytes + * + * @param ia InetAddress to fill + * @param ipBytes Raw IP data + * @param ipLen Length of IP: 4 or 16 for IPv4 or IPv6 + * @param port IP port + */ ZT_SDK_API void ZT_InetAddress_setIpBytes(ZT_InetAddress *ia, const void *ipBytes, unsigned int ipLen, unsigned int port); +/** + * Set IP port + */ ZT_SDK_API void ZT_InetAddress_setPort(ZT_InetAddress *ia, unsigned int port); +/** + * Get IP port, which can also be used as a CIDR in some use cases. + */ ZT_SDK_API unsigned int ZT_InetAddress_port(const ZT_InetAddress *ia); +/** + * Returns non-zero if this InetAddress is nil/zero. + */ ZT_SDK_API int ZT_InetAddress_isNil(const ZT_InetAddress *ia); +/** + * Returns non-zero if this is an IPv4 address. + */ ZT_SDK_API int ZT_InetAddress_isV4(const ZT_InetAddress *ia); +/** + * Returns non-zero if this is an IPv6 address. + */ ZT_SDK_API int ZT_InetAddress_isV6(const ZT_InetAddress *ia); +/** + * Classify the network scope of this IP address (local net, global, etc.) + */ ZT_SDK_API enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddress *ia); /* ---------------------------------------------------------------------------------------------------------------- */ diff --git a/rust-zerotier-core/src/buffer.rs b/rust-zerotier-core/src/buffer.rs index 3349c2a38..d9f6468d4 100644 --- a/rust-zerotier-core/src/buffer.rs +++ b/rust-zerotier-core/src/buffer.rs @@ -1,49 +1,68 @@ -use crate::bindings::capi as ztcore; use std::os::raw::c_void; -use std::slice::{from_raw_parts_mut}; use std::ptr::null_mut; +use std::slice::{from_raw_parts, from_raw_parts_mut}; + +use crate::bindings::capi as ztcore; pub struct Buffer { pub(crate) zt_core_buf: *mut u8, - pub(crate) data_size: usize + pub(crate) data_size: u32 } impl Buffer { + pub const CAPACITY: u32 = ztcore::ZT_BUF_SIZE; + + #[inline(always)] pub fn new() -> Buffer { + let b = unsafe { ztcore::ZT_getBuffer() as *mut u8 }; + if b.is_null() { + panic!("out of memory calling ZT_getBuffer()"); + } + return Buffer { + zt_core_buf: b, + data_size: ztcore::ZT_BUF_SIZE + }; + } + + #[inline(always)] + pub fn len(&self) -> u32 { + self.data_size + } + + /// Set the size of the data held by this buffer. This is unsafe because + /// setting it to a value larger than CAPACITY will place the buffer into + /// an invalid state. + #[inline(always)] + pub unsafe fn set_len(&mut self, s: u32) { + self.data_size = s; + } +} + +impl AsRef<&[u8]> for Buffer { + #[inline(always)] + fn as_ref(&self) -> &[u8] { unsafe { - let b = ztcore::ZT_getBuffer() as *mut u8; - if b.is_null() { - panic!("out of memory calling ZT_getBuffer()"); - } - return Buffer { - zt_core_buf: b, - data_size: ztcore::ZT_BUF_SIZE as usize - }; + return from_raw_parts(self.zt_core_buf, self.data_size as usize); } } +} +impl AsMut<&[u8]> for Buffer { #[inline(always)] - pub fn get(&mut self) -> &mut [u8] { + fn as_mut(&mut self) -> &mut [u8] { unsafe { - return from_raw_parts_mut(self.zt_core_buf, ztcore::ZT_BUF_SIZE as usize); + return from_raw_parts_mut(self.zt_core_buf, self.data_size as usize); } } - - #[inline(always)] - pub fn set_data_size(&mut self, s: usize) { - self.data_size = s & (ztcore::ZT_BUF_SIZE - 1) as usize; - } - - #[inline(always)] - pub(crate) fn mark_consumed(&mut self) { - self.zt_core_buf = null_mut(); - } } impl Drop for Buffer { #[inline(always)] fn drop(&mut self) { - // ZT_freeBuffer() does nothing if passed a null pointer. + // NOTE: in node.rs std::mem::forget() is used to prevent this from + // being called on buffers that have been returned via one of the + // process_XX() methods on ZT_Node. This destructor only exists to + // return buffers that were not consumed normally. unsafe { ztcore::ZT_freeBuffer(self.zt_core_buf as *mut c_void); } diff --git a/rust-zerotier-core/src/certificate.rs b/rust-zerotier-core/src/certificate.rs index 340236f74..862a3011d 100644 --- a/rust-zerotier-core/src/certificate.rs +++ b/rust-zerotier-core/src/certificate.rs @@ -1,5 +1,5 @@ use std::cell::Cell; -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::hash::{Hash, Hasher}; use std::mem::{MaybeUninit, zeroed}; use std::os::raw::{c_char, c_uint, c_void}; diff --git a/rust-zerotier-core/src/endpoint.rs b/rust-zerotier-core/src/endpoint.rs index 7022bf81b..15718c96f 100644 --- a/rust-zerotier-core/src/endpoint.rs +++ b/rust-zerotier-core/src/endpoint.rs @@ -1,4 +1,4 @@ -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::mem::MaybeUninit; use std::os::raw::{c_char, c_int, c_void}; diff --git a/rust-zerotier-core/src/fingerprint.rs b/rust-zerotier-core/src/fingerprint.rs index 14e7c96e0..00012277e 100644 --- a/rust-zerotier-core/src/fingerprint.rs +++ b/rust-zerotier-core/src/fingerprint.rs @@ -1,8 +1,9 @@ +use std::ffi::CString; +use std::mem::MaybeUninit; +use std::os::raw::{c_char, c_int}; + use crate::*; use crate::bindings::capi as ztcore; -use std::os::raw::{c_char, c_int}; -use std::ffi::{CStr, CString}; -use std::mem::MaybeUninit; pub struct Fingerprint { pub address: Address, diff --git a/rust-zerotier-core/src/identity.rs b/rust-zerotier-core/src/identity.rs index eb1069bac..257a244e2 100644 --- a/rust-zerotier-core/src/identity.rs +++ b/rust-zerotier-core/src/identity.rs @@ -1,4 +1,4 @@ -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::mem::MaybeUninit; use std::os::raw::*; diff --git a/rust-zerotier-core/src/inetaddress.rs b/rust-zerotier-core/src/inetaddress.rs index 37d18e91c..99716d4a9 100644 --- a/rust-zerotier-core/src/inetaddress.rs +++ b/rust-zerotier-core/src/inetaddress.rs @@ -2,10 +2,23 @@ use std::ffi::CString; use std::mem::{MaybeUninit, transmute, size_of}; use serde::{Deserialize, Serialize}; +use num_derive::{FromPrimitive, ToPrimitive}; use crate::*; use crate::bindings::capi as ztcore; +#[derive(FromPrimitive,ToPrimitive)] +pub enum IpScope { + None = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_NONE as isize, + Multicast = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_MULTICAST as isize, + Loopback = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_LOOPBACK as isize, + PseudoPrivate = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_PSEUDOPRIVATE as isize, + Global = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_GLOBAL as isize, + LinkLocal = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_LINK_LOCAL as isize, + Shared = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_SHARED as isize, + Private = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_PRIVATE as isize +} + /// Opaque structure that can hold an IPv4 or IPv6 address. pub struct InetAddress { // This must be the same size as ZT_InetAddress in zerotier.h. This is @@ -27,7 +40,7 @@ impl InetAddress { if cs.is_ok() { let cs = cs.unwrap(); unsafe { - if ztcore::ZT_InetAddress_fromString(a.as_mut_ptr(), cs.as_ptr()) == 0 { + if ztcore::ZT_InetAddress_fromString(a.as_capi_mut_ptr(), cs.as_ptr()) == 0 { return None } } @@ -36,13 +49,13 @@ impl InetAddress { } #[inline(always)] - pub(crate) unsafe fn transmute_capi(a: &ztcore::ZT_InetAddress) -> &InetAddress { + pub(crate) fn transmute_capi(a: &ztcore::ZT_InetAddress) -> &InetAddress { unsafe { transmute(a) } } - pub(crate) fn new_from_capi(a: ztcore::ZT_InetAddress) -> Option { + pub(crate) fn new_from_capi(a: &ztcore::ZT_InetAddress) -> Option { if a.bits[0] != 0 { Some(InetAddress { bits: a.bits @@ -64,25 +77,31 @@ impl InetAddress { } #[inline(always)] - pub(crate) fn as_ptr(&self) -> *const ztcore::ZT_InetAddress { + pub(crate) fn as_capi_ptr(&self) -> *const ztcore::ZT_InetAddress { unsafe { transmute(self as *const InetAddress) } } #[inline(always)] - pub(crate) fn as_mut_ptr(&mut self) -> *mut ztcore::ZT_InetAddress { + pub(crate) fn as_capi_mut_ptr(&mut self) -> *mut ztcore::ZT_InetAddress { unsafe { transmute(self as *mut InetAddress) } } + + pub fn ip_scope(&self) -> IpScope { + unsafe { + IpScope::from_u32(ztcore::ZT_InetAddress_ipScope(self.as_capi_ptr())).unwrap_or(IpScope::None) + } + } } impl ToString for InetAddress { fn to_string(&self) -> String { let mut buf: MaybeUninit<[c_char; 128]> = MaybeUninit::uninit(); unsafe { - return cstr_to_string(ztcore::ZT_InetAddress_toString(self.as_ptr(), (*buf.as_mut_ptr()).as_mut_ptr(), 128), 128); + return cstr_to_string(ztcore::ZT_InetAddress_toString(self.as_capi_ptr(), (*buf.as_mut_ptr()).as_mut_ptr(), 128), 128); } } } @@ -129,7 +148,7 @@ impl<'de> serde::Deserialize<'de> for InetAddress { #[cfg(test)] mod tests { - use std::mem::{size_of, zeroed}; + use std::mem::size_of; use crate::*; diff --git a/rust-zerotier-core/src/lib.rs b/rust-zerotier-core/src/lib.rs index 78a48c5b5..b283daffa 100644 --- a/rust-zerotier-core/src/lib.rs +++ b/rust-zerotier-core/src/lib.rs @@ -170,9 +170,9 @@ pub fn version() -> (i32, i32, i32, i32) { } /// Convenience function to get the number of milliseconds since the Unix epoch. -#[inline] +#[inline(always)] pub fn now() -> i64 { - (std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() & 0x7fffffffffffffff) as i64 + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() as i64 } /// The CStr stuff is cumbersome, so this is an easier to use function to turn a C string into a String. diff --git a/rust-zerotier-core/src/mac.rs b/rust-zerotier-core/src/mac.rs index 9b2f510f3..9be780adf 100644 --- a/rust-zerotier-core/src/mac.rs +++ b/rust-zerotier-core/src/mac.rs @@ -1,14 +1,6 @@ pub struct MAC(pub u64); -impl MAC { - #[inline] - pub fn new_from_string(s: &str) -> MAC { - return MAC(u64::from_str_radix(s.replace(":","").as_str(), 16).unwrap_or(0)); - } -} - impl ToString for MAC { - #[inline] fn to_string(&self) -> String { let x = self.0; format!("{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}:{:0>2x}", @@ -21,6 +13,12 @@ impl ToString for MAC { } } +impl From<&str> for MAC { + fn from(s: &str) -> MAC { + MAC(u64::from_str_radix(s.replace(":","").as_str(), 16).unwrap_or(0)) + } +} + impl serde::Serialize for MAC { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { serializer.serialize_str(self.to_string().as_str()) @@ -33,11 +31,11 @@ impl<'de> serde::de::Visitor<'de> for AddressVisitor { type Value = MAC; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("Ethernet MAC address in string format") + formatter.write_str("Ethernet MAC address in string format (with or without : separators)") } fn visit_str(self, s: &str) -> Result where E: serde::de::Error { - Ok(MAC::new_from_string(s)) + Ok(MAC::from(s)) } } diff --git a/rust-zerotier-core/src/node.rs b/rust-zerotier-core/src/node.rs index 12402bd7f..244d88aab 100644 --- a/rust-zerotier-core/src/node.rs +++ b/rust-zerotier-core/src/node.rs @@ -197,8 +197,7 @@ impl Node { Ok(n) } - /// This is called periodically from internal background thread. - /// Don't call directly. + /// This is called periodically from the background service thread. #[inline(always)] fn process_background_tasks(&self) -> i64 { let current_time = now(); @@ -249,21 +248,21 @@ impl Node { } #[inline(always)] - pub fn process_wire_packet(&self, local_socket: i64, remote_address: &InetAddress, data: &mut Buffer) -> ResultCode { + pub fn process_wire_packet(&self, local_socket: i64, remote_address: &InetAddress, data: Buffer) -> ResultCode { let current_time = self.now.get(); let mut next_task_deadline: i64 = current_time; - unsafe { - return ResultCode::from_u32(ztcore::ZT_Node_processWirePacket(self.capi.get(), null_mut(), current_time, local_socket, remote_address.as_ptr() as *const ztcore::ZT_InetAddress, data.zt_core_buf as *const c_void, data.data_size as u32, 1, &mut next_task_deadline as *mut i64) as u32).unwrap_or(ResultCode::ErrorInternalNonFatal); - } + let rc = unsafe { ResultCode::from_u32(ztcore::ZT_Node_processWirePacket(self.capi.get(), null_mut(), current_time, local_socket, remote_address.as_capi_ptr(), data.zt_core_buf as *const c_void, data.data_size as u32, 1, &mut next_task_deadline as *mut i64) as u32).unwrap_or(ResultCode::ErrorInternalNonFatal) }; + std::mem::forget(data); // prevent Buffer from being returned to ZT core twice + rc } #[inline(always)] - pub fn process_virtual_network_frame(&self, nwid: &NetworkId, source_mac: &MAC, dest_mac: &MAC, ethertype: u16, vlan_id: u16, data: &mut Buffer) -> ResultCode { + pub fn process_virtual_network_frame(&self, nwid: &NetworkId, source_mac: &MAC, dest_mac: &MAC, ethertype: u16, vlan_id: u16, data: Buffer) -> ResultCode { let current_time = self.now.get(); let mut next_tick_deadline: i64 = current_time; - unsafe { - return ResultCode::from_u32(ztcore::ZT_Node_processVirtualNetworkFrame(self.capi.get(), null_mut(), current_time, nwid.0, source_mac.0, dest_mac.0, ethertype as c_uint, vlan_id as c_uint, data.zt_core_buf as *const c_void, data.data_size as u32, 1, &mut next_tick_deadline as *mut i64) as u32).unwrap_or(ResultCode::ErrorInternalNonFatal); - } + let rc = unsafe { ResultCode::from_u32(ztcore::ZT_Node_processVirtualNetworkFrame(self.capi.get(), null_mut(), current_time, nwid.0, source_mac.0, dest_mac.0, ethertype as c_uint, vlan_id as c_uint, data.zt_core_buf as *const c_void, data.data_size as u32, 1, &mut next_tick_deadline as *mut i64) as u32).unwrap_or(ResultCode::ErrorInternalNonFatal) }; + std::mem::forget(data); // prevent Buffer from being returned to ZT core twice + rc } pub fn multicast_subscribe(&self, nwid: &NetworkId, multicast_group: &MAC, multicast_adi: u32) -> ResultCode {