Comments, fix to Rust bindgen, cleanup, warning removal, etc.

This commit is contained in:
Adam Ierymenko 2021-01-08 14:59:05 -05:00
parent 36f9dd54d9
commit 20b6f347c8
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
25 changed files with 543 additions and 122 deletions

View file

@ -33,6 +33,6 @@ distclean: FORCE
rust-zerotier-core-bindgen: FORCE
cargo install bindgen
rm -f rust-zerotier-core/src/bindings/capi.rs
bindgen --no-doc-comments core/zerotier.h >rust-zerotier-core/src/bindings/capi.rs
bindgen --no-doc-comments --no-layout-tests --no-derive-debug core/zerotier.h >rust-zerotier-core/src/bindings/capi.rs
FORCE:

View file

@ -464,4 +464,7 @@ InetAddress InetAddress::makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress)
return r;
}
const int ZT_AF_INET = (int)AF_INET;
const int ZT_AF_INET6 = (int)AF_INET6;
} // namespace ZeroTier

View file

@ -83,7 +83,7 @@ Node::Node(
uint64_t idtmp[2];
idtmp[0] = 0;
idtmp[1] = 0;
Vector< uint8_t > data(stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp));
Vector< uint8_t > data(stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, 0));
bool haveIdentity = false;
if (!data.empty()) {
data.push_back(0); // zero-terminate string
@ -102,15 +102,16 @@ Node::Node(
RR->identity.toString(true, RR->secretIdentityStr);
idtmp[0] = RR->identity.address();
idtmp[1] = 0;
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, RR->secretIdentityStr, (unsigned int)strlen(RR->secretIdentityStr));
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, 1, RR->secretIdentityStr, (unsigned int)strlen(RR->secretIdentityStr));
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, 1, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
ZT_SPEW("no pre-existing identity found, created %s", RR->identity.toString().c_str());
} else {
idtmp[0] = RR->identity.address();
idtmp[1] = 0;
data = stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp);
if ((data.empty()) || (memcmp(data.data(), RR->publicIdentityStr, strlen(RR->publicIdentityStr)) != 0))
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
data = stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, 1);
if ((data.empty()) || (memcmp(data.data(), RR->publicIdentityStr, strlen(RR->publicIdentityStr)) != 0)) {
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, 1, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
}
}
// Create a secret key for encrypting local data at rest.
@ -329,7 +330,7 @@ ZT_ResultCode Node::leave(
uint64_t tmp[2];
tmp[0] = nwid;
tmp[1] = 0;
RR->node->stateObjectDelete(tptr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp);
RR->node->stateObjectDelete(tptr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, 1);
return ZT_RESULT_OK;
}
@ -661,7 +662,7 @@ void Node::setController(void *networkControllerInstance)
// Methods used only within the core ----------------------------------------------------------------------------------
Vector< uint8_t > Node::stateObjectGet(void *const tPtr, ZT_StateObjectType type, const uint64_t *id)
Vector< uint8_t > Node::stateObjectGet(void *const tPtr, ZT_StateObjectType type, const uint64_t *id, const unsigned int idSize)
{
Vector< uint8_t > r;
if (m_cb.stateGetFunction) {
@ -673,6 +674,7 @@ Vector< uint8_t > Node::stateObjectGet(void *const tPtr, ZT_StateObjectType type
tPtr,
type,
id,
idSize,
&data,
&freeFunc);
if ((l > 0) && (data) && (freeFunc)) {

View file

@ -241,9 +241,10 @@ public:
* @param tPtr Thread pointer
* @param ev Event object
* @param md Event data or NULL if none
* @param mdSize Size of event data
*/
ZT_INLINE void postEvent(void *tPtr, ZT_Event ev, const void *md = nullptr) noexcept
{ m_cb.eventCallback(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, ev, md); }
ZT_INLINE void postEvent(void *tPtr, ZT_Event ev, const void *md = nullptr, const unsigned int mdSize = 0) noexcept
{ m_cb.eventCallback(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, ev, md, mdSize); }
/**
* Post network port configuration via external callback
@ -271,7 +272,7 @@ public:
* @param id Object ID or NULL if this type does not use one
* @return Vector containing data or empty vector if not found or empty
*/
Vector< uint8_t > stateObjectGet(void *tPtr, ZT_StateObjectType type, const uint64_t *id);
Vector< uint8_t > stateObjectGet(void *tPtr, ZT_StateObjectType type, const uint64_t *id, unsigned int idSize);
/**
* Store a state object
@ -282,10 +283,10 @@ public:
* @param data Data to store
* @param len Length of data
*/
ZT_INLINE void stateObjectPut(void *const tPtr, ZT_StateObjectType type, const uint64_t id[2], const void *const data, const unsigned int len) noexcept
ZT_INLINE void stateObjectPut(void *const tPtr, ZT_StateObjectType type, const uint64_t *const id, const unsigned int idSize, const void *const data, const unsigned int len) noexcept
{
if (m_cb.statePutFunction)
m_cb.statePutFunction(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, type, id, data, (int)len);
m_cb.statePutFunction(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, type, id, idSize, data, (int)len);
}
/**
@ -295,10 +296,10 @@ public:
* @param type Object type to delete
* @param id Object ID
*/
ZT_INLINE void stateObjectDelete(void *const tPtr, ZT_StateObjectType type, const uint64_t id[2]) noexcept
ZT_INLINE void stateObjectDelete(void *const tPtr, ZT_StateObjectType type, const uint64_t *const id, const unsigned int idSize) noexcept
{
if (m_cb.statePutFunction)
m_cb.statePutFunction(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, type, id, nullptr, -1);
m_cb.statePutFunction(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, type, id, idSize, nullptr, -1);
}
/**

View file

@ -508,7 +508,7 @@ void Peer::save(void *tPtr) const
uint64_t id[2];
id[0] = m_id.address().toInt();
id[1] = 0;
RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_PEER, id, buf, (unsigned int)len + 8);
RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_PEER, id, 1, buf, (unsigned int)len + 8);
}
}

View file

@ -23,7 +23,7 @@ Topology::Topology(const RuntimeEnvironment *renv, void *tPtr, const int64_t now
char tmp[32];
Dictionary d;
Vector< uint8_t > trustData(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_TRUST_STORE, Utils::ZERO256));
Vector< uint8_t > trustData(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_TRUST_STORE, Utils::ZERO256, 0));
if (trustData.empty() || (!d.decode(trustData.data(), (unsigned int)trustData.size()))) {
if (!d.decode(Defaults::CERTIFICATES, Defaults::CERTIFICATES_BYTES))
d.clear();
@ -37,7 +37,7 @@ Topology::Topology(const RuntimeEnvironment *renv, void *tPtr, const int64_t now
if (serialNo.size() == ZT_SHA384_DIGEST_SIZE) {
Utils::copy< 48 >(id, serialNo.data());
Certificate cert;
Vector< uint8_t > enc(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_CERT, id));
Vector< uint8_t > enc(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_CERT, id, 6));
if (cert.decode(enc.data(), (unsigned int)enc.size()))
addCertificate(tPtr, cert, now, (unsigned int)d.getUI(Dictionary::arraySubscript(tmp, sizeof(tmp), "c$.lt", idx)), false, false, false);
}
@ -236,7 +236,7 @@ ZT_CertificateError Topology::addCertificate(void *tPtr, const Certificate &cert
Vector< uint8_t > certData(cert.encode());
uint64_t id[6];
Utils::copy< 48 >(id, cert.serialNo);
RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_CERT, id, certData.data(), (unsigned int)certData.size());
RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_CERT, id, 6, certData.data(), (unsigned int)certData.size());
}
return ZT_CERTIFICATE_ERROR_NONE;
@ -330,7 +330,7 @@ void Topology::m_eraseCertificate(void *tPtr, const SharedPtr< const Certificate
}
}
RR->node->stateObjectDelete(tPtr, ZT_STATE_OBJECT_CERT, serialNo.data);
RR->node->stateObjectDelete(tPtr, ZT_STATE_OBJECT_CERT, serialNo.data, 6);
}
bool Topology::m_cleanCertificates(void *tPtr, int64_t now)
@ -427,7 +427,7 @@ void Topology::m_loadCached(void *tPtr, const Address &zta, SharedPtr< Peer > &p
uint64_t id[2];
id[0] = zta.toInt();
id[1] = 0;
Vector< uint8_t > data(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PEER, id));
Vector< uint8_t > data(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PEER, id, 1));
if (data.size() > 8) {
const uint8_t *d = data.data();
int dl = (int)data.size();
@ -521,7 +521,7 @@ void Topology::m_writeTrustStore(void *tPtr)
Vector< uint8_t > trustStore;
d.encode(trustStore);
RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_TRUST_STORE, Utils::ZERO256, trustStore.data(), (unsigned int)trustStore.size());
RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_TRUST_STORE, Utils::ZERO256, 0, trustStore.data(), (unsigned int)trustStore.size());
}
} // namespace ZeroTier

View file

@ -1838,7 +1838,8 @@ typedef void (*ZT_EventCallback)(
void *, /* User ptr */
void *, /* Thread ptr */
enum ZT_Event, /* Event type */
const void *); /* Event payload (if applicable) */
const void *, /* Event payload (if applicable) */
unsigned int); /* Size of event payload */
/**
* Callback for storing and/or publishing state information
@ -1846,10 +1847,6 @@ typedef void (*ZT_EventCallback)(
* See ZT_StateObjectType docs for information about each state object type
* and when and if it needs to be persisted.
*
* The state object ID's size depends on the object type, and is always
* in the form of one or more 64-bit unsigned integers. Some object types
* do not use this field, and for these it may be NULL.
*
* An object of length -1 is sent to indicate that an object should be
* deleted.
*/
@ -1859,6 +1856,7 @@ typedef void (*ZT_StatePutFunction)(
void *, /* Thread ptr */
enum ZT_StateObjectType, /* State object type */
const uint64_t *, /* State object ID (if applicable) */
unsigned int, /* Length of state object ID in quads */
const void *, /* State object data */
int); /* Length of data or -1 to delete */
@ -1877,6 +1875,7 @@ typedef int (*ZT_StateGetFunction)(
void *, /* Thread ptr */
enum ZT_StateObjectType, /* State object type */
const uint64_t *, /* State object ID (if applicable) */
unsigned int, /* Length of object ID in quads */
void **, /* Result parameter: data */
void (**)(void *)); /* Result parameter: data free function */
@ -3019,6 +3018,9 @@ ZT_SDK_API int ZT_InetAddress_isV6(const ZT_InetAddress *ia);
*/
ZT_SDK_API enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddress *ia);
/* These mirror the values of AF_INET and AF_INET6 for use by Rust and other things that need it. */
ZT_SDK_API const int ZT_AF_INET,ZT_AF_INET6;
/* ---------------------------------------------------------------------------------------------------------------- */

View file

@ -6,8 +6,8 @@ edition = "2018"
build = "build.rs"
[dependencies]
num-traits = "0.2.14"
num-derive = "0.3.3"
num-traits = "0.2"
num-derive = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
hex = "0.4.2"
hex = "0.4"

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
pub struct Address(pub u64);
impl ToString for Address {

View file

@ -1,2 +1,15 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#[allow(non_snake_case,non_upper_case_globals,non_camel_case_types,dead_code,improper_ctypes)]
pub mod capi;

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::os::raw::c_void;
use std::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut};

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::cell::Cell;
use std::ffi::CString;
use std::hash::{Hash, Hasher};
@ -199,8 +212,6 @@ impl CertificateSubjectUniqueIdSecret {
}
}
implement_to_from_json!(CertificateSubjectUniqueIdSecret);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Reasons a certificate may be rejected.
@ -370,8 +381,6 @@ impl CertificateName {
}
}
implement_to_from_json!(CertificateName);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Serialize, Deserialize)]
@ -402,8 +411,6 @@ impl CertificateNetwork {
}
}
implement_to_from_json!(CertificateNetwork);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Serialize, Deserialize)]
@ -431,8 +438,6 @@ impl CertificateIdentity {
}
}
implement_to_from_json!(CertificateIdentity);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Serialize, Deserialize)]
@ -607,8 +612,6 @@ impl CertificateSubject {
}
}
implement_to_from_json!(CertificateSubject);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Serialize, Deserialize)]
@ -742,8 +745,6 @@ impl Certificate {
}
}
implement_to_from_json!(Certificate);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#[cfg(test)]

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::os::raw::{c_char, c_int, c_void};

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::os::raw::{c_char, c_int};

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::os::raw::*;

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::ffi::CString;
use std::mem::{MaybeUninit, transmute, size_of};
@ -7,6 +20,14 @@ use num_traits::FromPrimitive;
use crate::*;
use crate::bindings::capi as ztcore;
use std::os::raw::{c_void, c_uint};
// WARNING: here be dragons! This defines an opaque blob in Rust that shadows
// and is of the exact size as an opaque blob in C that shadows and is the
// exact size of struct sockaddr_storage. This Rust code makes use of a good
// deal of transmute() magic to save copying and allow these identically sized
// blobs to be freely cast to one another. That the sizes are correct is
// checked statically in the C++ code and in the tests in the Rust code.
#[derive(FromPrimitive,ToPrimitive)]
pub enum IpScope {
@ -20,6 +41,12 @@ pub enum IpScope {
Private = ztcore::ZT_InetAddress_IpScope_ZT_IP_SCOPE_PRIVATE as isize
}
pub enum InetAddressFamily {
Nil,
IPv4,
IPv6
}
/// 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
@ -28,13 +55,28 @@ pub struct InetAddress {
}
impl InetAddress {
#[inline(always)]
/// Create a new empty and "nil" InetAddress.
pub fn new() -> InetAddress {
InetAddress {
bits: [0; (ztcore::ZT_SOCKADDR_STORAGE_SIZE / 8) as usize]
}
}
/// Create from a 4-byte IPv4 IP or a 16-byte IPv6 IP.
/// Returns None if ip is not 4 or 16 bytes.
pub fn new_from_ip_bytes(ip: &[u8], port: u16) -> Option<InetAddress> {
if ip.len() != 4 && ip.len() != 16 {
return None;
}
let mut a = InetAddress::new();
unsafe {
ztcore::ZT_InetAddress_setIpBytes(a.as_capi_mut_ptr(), ip.as_ptr() as *const c_void, ip.len() as c_uint, port as c_uint);
}
Some(a)
}
/// Create from an InetAddress in string form.
/// Returns None if the string is not valid.
pub fn new_from_string(s: &str) -> Option<InetAddress> {
let mut a = InetAddress::new();
let cs = CString::new(s);
@ -66,12 +108,14 @@ impl InetAddress {
}
}
/// Clear and set to the "nil" value.
pub fn clear(&mut self) {
for i in self.bits.iter_mut() {
*i = 0;
}
}
/// Returns true if this InetAddress holds nothing.
#[inline(always)]
pub fn is_nil(&self) -> bool {
self.bits[0] == 0 // if ss_family != 0, this will not be zero
@ -91,11 +135,27 @@ impl InetAddress {
}
}
/// Get the network scope of the IP in this object.
pub fn ip_scope(&self) -> IpScope {
unsafe {
IpScope::from_u32(ztcore::ZT_InetAddress_ipScope(self.as_capi_ptr()) as u32).unwrap_or(IpScope::None)
}
}
/// Get the address family of this InetAddress.
pub fn family(&self) -> InetAddressFamily {
if !self.is_nil() {
unsafe {
if ztcore::ZT_InetAddress_isV4(self.as_capi_ptr()) != 0 {
return InetAddressFamily::IPv6;
}
if ztcore::ZT_InetAddress_isV6(self.as_capi_ptr()) != 0 {
return InetAddressFamily::IPv6;
}
}
}
InetAddressFamily::Nil
}
}
impl ToString for InetAddress {

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::os::raw::{c_char, c_int};
use num_derive::{FromPrimitive, ToPrimitive};
@ -134,27 +147,6 @@ pub enum ResultCode {
ErrorInternalNonFatal = ztcore::ZT_ResultCode_ZT_RESULT_ERROR_INTERNAL as isize,
}
#[derive(FromPrimitive,ToPrimitive)]
pub enum Event {
Up = ztcore::ZT_Event_ZT_EVENT_UP as isize,
Offline = ztcore::ZT_Event_ZT_EVENT_OFFLINE as isize,
Online = ztcore::ZT_Event_ZT_EVENT_ONLINE as isize,
Down = ztcore::ZT_Event_ZT_EVENT_DOWN as isize,
Trace = ztcore::ZT_Event_ZT_EVENT_TRACE as isize,
UserMessage = ztcore::ZT_Event_ZT_EVENT_USER_MESSAGE as isize,
}
#[derive(FromPrimitive,ToPrimitive)]
pub enum StateObjectType {
IdentityPublic = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_IDENTITY_PUBLIC as isize,
IdentitySecret = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_IDENTITY_SECRET as isize,
Locator = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_LOCATOR as isize,
Peer = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_PEER as isize,
NetworkConfig = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_NETWORK_CONFIG as isize,
TrustStore = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_TRUST_STORE as isize,
Certificate = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_CERT as isize
}
/// Returns a tuple of major, minor, revision, and build version numbers from the ZeroTier core.
pub fn version() -> (i32, i32, i32, i32) {
let mut major: c_int = 0;
@ -191,6 +183,7 @@ pub unsafe fn cstr_to_string(cstr: *const c_char, max_len: isize) -> String {
String::new()
}
/*
#[macro_export(crate)]
macro_rules! implement_to_from_json {
($struct_name:ident) => {
@ -213,3 +206,4 @@ macro_rules! implement_to_from_json {
}
};
}
*/

View file

@ -1,7 +1,21 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::ffi::CString;
use std::os::raw::{c_char, c_int, c_uint};
use crate::*;
use crate::bindings::capi as ztcore;
use std::os::raw::{c_char, c_int, c_uint};
use std::ffi::CString;
pub struct Locator {
pub(crate) capi: *const ztcore::ZT_Locator,

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
pub struct MAC(pub u64);
impl ToString for MAC {

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
pub struct NetworkId(pub u64);
impl NetworkId {

View file

@ -1,9 +1,25 @@
use std::cell::Cell;
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::collections::hash_map::HashMap;
use std::ffi::CStr;
use std::mem::MaybeUninit;
use std::mem::transmute;
use std::fs::copy;
use std::intrinsics::copy_nonoverlapping;
use std::mem::{MaybeUninit, transmute};
use std::os::raw::{c_int, c_uint, c_ulong, c_void};
use std::ptr::null_mut;
use std::ptr::{null, null_mut, slice_from_raw_parts};
use std::sync::*;
use std::sync::atomic::*;
use std::time::Duration;
@ -14,8 +30,45 @@ use serde::{Deserialize, Serialize};
use crate::*;
use crate::bindings::capi as ztcore;
/// Minimum delay between iterations of the background loop.
const NODE_BACKGROUND_MIN_DELAY: i64 = 250;
#[derive(FromPrimitive,ToPrimitive)]
pub enum Event {
Up = ztcore::ZT_Event_ZT_EVENT_UP as isize,
Offline = ztcore::ZT_Event_ZT_EVENT_OFFLINE as isize,
Online = ztcore::ZT_Event_ZT_EVENT_ONLINE as isize,
Down = ztcore::ZT_Event_ZT_EVENT_DOWN as isize,
Trace = ztcore::ZT_Event_ZT_EVENT_TRACE as isize,
UserMessage = ztcore::ZT_Event_ZT_EVENT_USER_MESSAGE as isize,
}
#[derive(FromPrimitive,ToPrimitive)]
pub enum StateObjectType {
IdentityPublic = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_IDENTITY_PUBLIC as isize,
IdentitySecret = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_IDENTITY_SECRET as isize,
Locator = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_LOCATOR as isize,
Peer = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_PEER as isize,
NetworkConfig = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_NETWORK_CONFIG as isize,
TrustStore = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_TRUST_STORE as isize,
Certificate = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_CERT as isize
}
impl StateObjectType {
pub fn to_file_ext(&self) -> &str {
match *self {
StateObjectType::IdentityPublic => "public",
StateObjectType::IdentitySecret => "secret",
StateObjectType::Locator => "locator",
StateObjectType::Peer => "peer",
StateObjectType::NetworkConfig => "network",
StateObjectType::TrustStore => "trust",
StateObjectType::Certificate => "cert"
}
}
}
/// The status of a ZeroTier node.
#[derive(Serialize, Deserialize)]
pub struct NodeStatus {
pub address: Address,
@ -27,29 +80,53 @@ pub struct NodeStatus {
pub online: bool,
}
/// An event handler that receives events, frames, and packets from the core.
/// Note that these handlers can be called concurrently from any thread and
/// must be thread safe.
pub trait NodeEventHandler {
fn virtual_network_config(&self);
fn virtual_network_frame(&self);
fn event(&self);
fn state_put(&self);
fn state_get(&self);
fn wire_packet_send(&self);
fn path_check(&self);
fn path_lookup(&self);
/// Called when a configuration change or update should be applied to a network.
fn virtual_network_config(&self, network_id: NetworkId, network_obj: &Arc<dyn Any>, config_op: VirtualNetworkConfigOperation, config: Option<&VirtualNetworkConfig>);
/// Called when a frame should be injected into the virtual network (physical -> virtual).
fn virtual_network_frame(&self, network_id: NetworkId, network_obj: &Arc<dyn Any>, source_mac: MAC, dest_mac: MAC, ethertype: u16, vlan_id: u16, data: &[u8]);
/// Called when a core ZeroTier event occurs.
fn event(&self, event: Event, event_data: &[u8]);
/// Called to store an object into the object store.
fn state_put(&self, obj_type: StateObjectType, obj_id: &[u64], obj_data: &[u8]);
/// Called to retrieve an object from the object store.
fn state_get(&self, obj_type: StateObjectType, obj_id: &[u64]) -> Box<[u8]>;
/// Called to send a packet over the physical network (virtual -> physical).
fn wire_packet_send(&self, local_socket: i64, sock_addr: &InetAddress, data: &[u8], packet_ttl: u32) -> i32;
/// Called to check and see if a physical address should be used for ZeroTier traffic.
fn path_check(&self, address: Address, id: &Identity, local_socket: i64, sock_addr: &InetAddress) -> bool;
/// Called to look up a path to a known node, allowing out of band lookup methods for physical paths to nodes.
fn path_lookup(&self, address: Address, id: &Identity, desired_family: InetAddressFamily) -> Option<InetAddress>;
}
/// An instance of the ZeroTier core.
/// This is templated on the actual implementation of NodeEventHandler for performance reasons,
/// as it avoids an extra indirect function call.
pub struct Node<T: NodeEventHandler + 'static> {
event_handler: Arc<T>,
capi: Cell<*mut ztcore::ZT_Node>,
background_thread: Cell<Option<std::thread::JoinHandle<()>>>,
background_thread_run: Arc<AtomicBool>,
now: PortableAtomicI64,
networks_by_id: Mutex<HashMap<u64, *mut Arc<dyn Any>>> // pointer to an Arc<> is a raw value created from Box<Arc<N>>
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
macro_rules! node_from_raw_ptr {
($uptr:ident) => {
unsafe {
let ntmp: *const Node<T> = transmute($uptr);
let ntmp: *const Node<T> = $uptr.cast::<Node<T>>();
let ntmp: &Node<T> = &*ntmp;
ntmp
}
@ -57,22 +134,32 @@ macro_rules! node_from_raw_ptr {
}
extern "C" fn zt_virtual_network_config_function<T: NodeEventHandler + 'static>(
capi: *mut ztcore::ZT_Node,
_: *mut ztcore::ZT_Node,
uptr: *mut c_void,
tptr: *mut c_void,
_: *mut c_void,
nwid: u64,
nptr: *mut *mut c_void,
op: ztcore::ZT_VirtualNetworkConfigOperation,
conf: *const ztcore::ZT_VirtualNetworkConfig,
) {
let n = node_from_raw_ptr!(uptr);
n.event_handler.virtual_network_config();
let op2 = VirtualNetworkConfigOperation::from_u32(op as u32);
if op2.is_some() {
let op2 = op2.unwrap();
let n = node_from_raw_ptr!(uptr);
let network_obj: &Arc<dyn Any> = unsafe { &*((*nptr).cast::<Arc<dyn Any>>()) };
if conf.is_null() {
n.event_handler.virtual_network_config(NetworkId(nwid), network_obj, op2, None);
} else {
let conf2 = unsafe { VirtualNetworkConfig::new_from_capi(&*conf) };
n.event_handler.virtual_network_config(NetworkId(nwid), network_obj, op2, Some(&conf2));
}
}
}
extern "C" fn zt_virtual_network_frame_function<T: NodeEventHandler + 'static>(
capi: *mut ztcore::ZT_Node,
_: *mut ztcore::ZT_Node,
uptr: *mut c_void,
tptr: *mut c_void,
_: *mut c_void,
nwid: u64,
nptr: *mut *mut c_void,
source_mac: u64,
@ -82,87 +169,162 @@ extern "C" fn zt_virtual_network_frame_function<T: NodeEventHandler + 'static>(
data: *const c_void,
data_size: c_uint,
) {
let n = node_from_raw_ptr!(uptr);
n.event_handler.virtual_network_frame();
if !nptr.is_null() {
let n = node_from_raw_ptr!(uptr);
let network_obj: &Arc<dyn Any> = unsafe { &*((*nptr).cast::<Arc<dyn Any>>()) };
let data_slice = unsafe { &*slice_from_raw_parts(data.cast::<u8>(), data_size as usize) };
n.event_handler.virtual_network_frame(NetworkId(nwid), network_obj, MAC(source_mac), MAC(dest_mac), ethertype as u16, vlan_id as u16, data_slice);
}
}
extern "C" fn zt_event_callback<T: NodeEventHandler + 'static>(
capi: *mut ztcore::ZT_Node,
_: *mut ztcore::ZT_Node,
uptr: *mut c_void,
tptr: *mut c_void,
_: *mut c_void,
ev: ztcore::ZT_Event,
data: *const c_void,
data_size: c_uint
) {
let n = node_from_raw_ptr!(uptr);
n.event_handler.event();
let ev2 = Event::from_u32(ev as u32);
if ev2.is_some() {
let ev2 = ev2.unwrap();
let n = node_from_raw_ptr!(uptr);
if data.is_null() {
n.event_handler.event(ev2, &[u8; 0]);
} else {
let data2 = unsafe { &*slice_from_raw_parts(data.cast::<u8>(), data_size as usize) };
n.event_handler.event(ev2, data2);
}
}
}
extern "C" fn zt_state_put_function<T: NodeEventHandler + 'static>(
capi: *mut ztcore::ZT_Node,
_: *mut ztcore::ZT_Node,
uptr: *mut c_void,
tptr: *mut c_void,
_: *mut c_void,
obj_type: ztcore::ZT_StateObjectType,
obj_id: *const u64,
obj_id_len: c_uint,
obj_data: *const c_void,
obj_data_len: c_int,
) {
let n = node_from_raw_ptr!(uptr);
n.event_handler.state_put();
let obj_type2 = StateObjectType::from_u32(obj_type as u32);
if obj_type2.is_some() {
let obj_type2 = obj_type2.unwrap();
let n = node_from_raw_ptr!(uptr);
let obj_id2 = unsafe { &*slice_from_raw_parts(obj_id, obj_id_len as usize) };
let obj_data2 = unsafe { &*slice_from_raw_parts(obj_data.cast::<u8>(), obj_data_len as usize) };
n.event_handler.state_put(obj_type2, obj_id2, obj_data2);
}
}
extern "C" fn zt_state_get_function<T: NodeEventHandler + 'static>(
capi: *mut ztcore::ZT_Node,
_: *mut ztcore::ZT_Node,
uptr: *mut c_void,
tptr: *mut c_void,
_: *mut c_void,
obj_type: ztcore::ZT_StateObjectType,
obj_id: *const u64,
obj_id_len: c_uint,
obj_data: *mut *mut c_void,
obj_data_free_function: *mut *mut c_void,
) {
let n = node_from_raw_ptr!(uptr);
n.event_handler.state_get();
) -> c_int {
if obj_data.is_null() || obj_data_free_function.is_null() {
return -1;
}
unsafe {
*obj_data = null_mut();
*obj_data_free_function = transmute(ztcore::free as *const ());
}
let obj_type2 = StateObjectType::from_u32(obj_type as u32);
if obj_type2.is_some() {
let obj_type2 = obj_type2.unwrap();
let n = node_from_raw_ptr!(uptr);
let obj_id2 = unsafe { &*slice_from_raw_parts(obj_id, obj_id_len as usize) };
let obj_data_result = n.event_handler.state_get(obj_type2, obj_id2);
if obj_data_result.len() > 0 {
unsafe {
let obj_data_len: c_int = obj_data_result.len() as c_int;
let obj_data_raw = ztcore::malloc(obj_data_len as c_ulong);
if !obj_data_raw.is_null() {
copy_nonoverlapping(obj_data_result.as_ptr(), obj_data_raw.cast::<u8>(), obj_data_len as usize);
*obj_data = obj_data_raw;
return obj_data_len;
}
}
}
}
return -1;
}
extern "C" fn zt_wire_packet_send_function<T: NodeEventHandler + 'static>(
capi: *mut ztcore::ZT_Node,
_: *mut ztcore::ZT_Node,
uptr: *mut c_void,
tptr: *mut c_void,
_: *mut c_void,
local_socket: i64,
sock_addr: *const ztcore::ZT_InetAddress,
data: *const c_void,
data_size: c_uint,
packet_ttl: c_uint,
) {
) -> c_int {
let n = node_from_raw_ptr!(uptr);
n.event_handler.wire_packet_send();
return n.event_handler.wire_packet_send(local_socket, InetAddress::transmute_capi(unsafe { &*sock_addr }), unsafe { &*slice_from_raw_parts(data.cast::<u8>(), data_size as usize) }, packet_ttl as u32) as c_int;
}
extern "C" fn zt_path_check_function<T: NodeEventHandler + 'static>(
capi: *mut ztcore::ZT_Node,
_: *mut ztcore::ZT_Node,
uptr: *mut c_void,
tptr: *mut c_void,
_: *mut c_void,
address: u64,
identity: *const ztcore::ZT_Identity,
local_socket: i64,
sock_addr: *const ztcore::ZT_InetAddress,
) {
) -> c_int {
let n = node_from_raw_ptr!(uptr);
n.event_handler.path_check();
let id = Identity::new_from_capi(identity, false);
if n.event_handler.path_check(Address(address), &id, local_socket, InetAddress::transmute_capi(unsafe{ &*sock_addr })) {
return 1;
}
return 0;
}
extern "C" fn zt_path_lookup_function<T: NodeEventHandler + 'static>(
capi: *mut ztcore::ZT_Node,
_: *mut ztcore::ZT_Node,
uptr: *mut c_void,
tptr: *mut c_void,
_: *mut c_void,
address: u64,
identity: *const ztcore::ZT_Identity,
sock_family: c_int,
sock_addr: *mut ztcore::ZT_InetAddress,
) {
) -> c_int {
if sock_addr.is_null() {
return 0;
}
let mut sock_family2: InetAddressFamily = InetAddressFamily::Nil;
unsafe {
match sock_family {
ztcore::ZT_AF_INET => InetAddressFamily::IPv4,
ztcore::ZT_AF_INET6 => InetAddressFamily::IPv6,
_ => { return 0; }
}
}
let n = node_from_raw_ptr!(uptr);
n.event_handler.path_lookup();
let id = Identity::new_from_capi(identity, false);
let result = n.event_handler.path_lookup(Address(address), &id, sock_family2);
if result.is_some() {
let result = result.unwrap();
let result_ptr = &result as *const InetAddress;
unsafe {
copy_nonoverlapping(result_ptr.cast::<ztcore::ZT_InetAddress>(), sock_addr, 1);
}
return 1;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
impl<T: NodeEventHandler + 'static> Node<T> {
/// Create a new Node with a given event handler.
pub fn new(event_handler: Arc<T>) -> Result<Arc<Node<T>>, ResultCode> {
@ -174,6 +336,7 @@ impl<T: NodeEventHandler + 'static> Node<T> {
background_thread: Cell::new(None),
background_thread_run: Arc::new(AtomicBool::new(true)),
now: PortableAtomicI64::new(now),
networks_by_id: Mutex::new(HashMap::new())
});
let mut capi: *mut ztcore::ZT_Node = null_mut();
@ -240,7 +403,7 @@ impl<T: NodeEventHandler + 'static> Node<T> {
next_delay
}
pub fn join(&self, nwid: NetworkId, controller_fingerprint: Option<Fingerprint>) -> ResultCode {
pub fn join(&self, nwid: NetworkId, controller_fingerprint: Option<Fingerprint>, network_obj: &Arc<dyn Any>) -> ResultCode {
let mut cfp: MaybeUninit<ztcore::ZT_Fingerprint> = MaybeUninit::uninit();
let mut cfpp: *mut ztcore::ZT_Fingerprint = null_mut();
if controller_fingerprint.is_some() {
@ -251,13 +414,27 @@ impl<T: NodeEventHandler + 'static> Node<T> {
(*cfpp).hash = cfp2.hash;
}
}
unsafe {
let rc = ztcore::ZT_Node_join(self.capi.get(), nwid.0, cfpp, null_mut(), null_mut());
return ResultCode::from_u32(rc as u32).unwrap();
let nptr = Box::into_raw(Box::new(network_obj.clone()));
self.networks_by_id.lock().as_deref_mut().unwrap().insert(nwid.0, nptr);
let rc = unsafe { ztcore::ZT_Node_join(self.capi.get(), nwid.0, cfpp, nptr.cast::<c_void>(), null_mut()) };
if rc != ztcore::ZT_ResultCode_ZT_RESULT_OK {
self.delete_network_uptr(nwid.0);
}
return ResultCode::from_u32(rc as u32).unwrap_or(ResultCode::ErrorInternalNonFatal);
}
fn delete_network_uptr(&self, nwid: u64) {
let nptr = self.networks_by_id.lock().as_deref_mut().unwrap().remove(&nwid).unwrap_or(null_mut());
if !nptr.is_null() {
unsafe {
Box::from_raw(nptr);
}
}
}
pub fn leave(&self, nwid: NetworkId) -> ResultCode {
self.delete_network_uptr(nwid.0);
unsafe {
return ResultCode::from_u32(ztcore::ZT_Node_leave(self.capi.get(), nwid.0, null_mut(), null_mut()) as u32).unwrap();
}
@ -306,8 +483,8 @@ impl<T: NodeEventHandler + 'static> Node<T> {
}
pub fn status(&self) -> NodeStatus {
let mut ns: MaybeUninit<ztcore::ZT_NodeStatus> = MaybeUninit::zeroed();
unsafe {
let mut ns: MaybeUninit<ztcore::ZT_NodeStatus> = MaybeUninit::zeroed();
ztcore::ZT_Node_status(self.capi.get(), ns.as_mut_ptr());
let ns = ns.assume_init();
if ns.identity.is_null() {
@ -386,6 +563,15 @@ impl<T: NodeEventHandler + 'static> Drop for Node<T> {
let _ = bt.join();
}
// Manually take care of the unboxed Boxes in networks_by_id
let mut nwids: Vec<u64> = Vec::new();
for n in self.networks_by_id.lock().unwrap().iter() {
nwids.push(*n.0);
}
for nwid in nwids.iter() {
self.delete_network_uptr(*nwid);
}
unsafe {
ztcore::ZT_Node_delete(self.capi.get(), null_mut());
}

View file

@ -1,6 +1,20 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use serde::{Deserialize, Serialize};
use crate::*;
use crate::bindings::capi as ztcore;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct Path {
@ -14,7 +28,7 @@ pub struct Path {
}
impl Path {
#[inline]
#[inline(always)]
pub(crate) fn new_from_capi(p: &ztcore::ZT_Path) -> Path {
Path{
endpoint: Endpoint::new_from_capi(&p.endpoint),

View file

@ -1,6 +1,20 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use serde::{Deserialize, Serialize};
use crate::*;
use crate::bindings::capi as ztcore;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct Peer {
@ -23,7 +37,7 @@ pub struct Peer {
}
impl Peer {
#[inline]
#[inline(always)]
pub(crate) fn new_from_capi(p: &ztcore::ZT_Peer) -> Peer {
unsafe {
let mut networks: Vec<NetworkId> = Vec::new();

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#[cfg(all(target_pointer_width = "32"))]
use std::sync::Mutex;

View file

@ -1,3 +1,16 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::mem::{size_of, transmute, zeroed};
use serde::{Deserialize, Serialize};