More threading improvements in root, more DNS TXT and multicast work (in progress)

This commit is contained in:
Adam Ierymenko 2019-09-16 10:33:59 -07:00
parent 9f9032ae36
commit e08fc81397
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
10 changed files with 317 additions and 95 deletions

View file

@ -129,6 +129,67 @@ public:
}
}
/**
* Make a DNS name contiaining a public key that can sign DNS entries
*
* This generates the initial fields of a DNS name that contains an
* encoded public key. Users may append any domain suffix to this name.
*
* @return First field(s) of DNS name
*/
static inline Str makeSecureDnsName(const uint8_t p384SigningKeyPublic[ZT_ECC384_PUBLIC_KEY_SIZE])
{
uint8_t tmp[ZT_ECC384_PUBLIC_KEY_SIZE+2];
memcpy(tmp,p384SigningKeyPublic,ZT_ECC384_PUBLIC_KEY_SIZE);
const uint16_t crc = Utils::crc16(tmp,ZT_ECC384_PUBLIC_KEY_SIZE);
tmp[ZT_ECC384_PUBLIC_KEY_SIZE-2] = (uint8_t)(crc >> 8);
tmp[ZT_ECC384_PUBLIC_KEY_SIZE-1] = (uint8_t)(crc);
Str name;
char b32[128];
Utils::b32e(tmp,35,b32,sizeof(b32));
name << b32;
Utils::b32e(tmp + 35,(ZT_ECC384_PUBLIC_KEY_SIZE+2) - 35,b32,sizeof(b32));
name << '.';
name << b32;
return name;
}
/**
* @return True if a key was found and successfully decoded
*/
static inline bool decodeSecureDnsName(const char *name,uint8_t p384SigningKeyPublic[ZT_ECC384_PUBLIC_KEY_SIZE])
{
uint8_t b32[128];
unsigned int b32ptr = 0;
char tmp[1024];
Utils::scopy(tmp,sizeof(tmp),name);
bool ok = false;
for(char *saveptr=(char *)0,*p=Utils::stok(tmp,".",&saveptr);p;p=Utils::stok((char *)0,".",&saveptr)) {
if (b32ptr >= sizeof(b32))
break;
int s = Utils::b32d(p,b32 + b32ptr,sizeof(b32) - b32ptr);
if (s > 0) {
b32ptr += (unsigned int)s;
if (b32ptr > 2) {
const uint16_t crc = Utils::crc16(b32,b32ptr);
if ((b32[b32ptr-2] == (uint8_t)(crc >> 8))&&(b32[b32ptr-1] == (uint8_t)(crc & 0xff))) {
ok = true;
break;
}
}
} else break;
}
if (ok) {
if (b32ptr == (ZT_ECC384_PUBLIC_KEY_SIZE + 2)) {
memcpy(p384SigningKeyPublic,b32,ZT_ECC384_PUBLIC_KEY_SIZE);
return true;
}
}
return false;
}
/**
* Make DNS TXT records for this locator
*
@ -184,7 +245,7 @@ public:
* now contains the contents of the supplied TXT records.
*/
template<typename I>
inline bool decodeTxtRecords(I start,I end,const uint8_t p384SigningKeyPublic[ZT_ECC384_PUBLIC_KEY_SIZE])
inline bool decodeTxtRecords(const Str &dnsName,I start,I end)
{
uint8_t dec[256],s384[48];
try {
@ -204,12 +265,13 @@ public:
for(std::vector<Str>::const_iterator i(txtRecords.begin());i!=txtRecords.end();++i)
tmp->append(dec,Utils::b64d(i->c_str() + 2,dec,sizeof(dec)));
if (tmp->size() <= ZT_ECC384_SIGNATURE_SIZE) {
return false;
}
SHA384(s384,tmp->data(),tmp->size() - ZT_ECC384_SIGNATURE_SIZE);
if (!ECC384ECDSAVerify(p384SigningKeyPublic,s384,((const uint8_t *)tmp->data()) + (tmp->size() - ZT_ECC384_SIGNATURE_SIZE))) {
return false;
uint8_t p384SigningKeyPublic[ZT_ECC384_PUBLIC_KEY_SIZE];
if (decodeSecureDnsName(dnsName.c_str(),p384SigningKeyPublic)) {
if (tmp->size() <= ZT_ECC384_SIGNATURE_SIZE)
return false;
SHA384(s384,tmp->data(),tmp->size() - ZT_ECC384_SIGNATURE_SIZE);
if (!ECC384ECDSAVerify(p384SigningKeyPublic,s384,((const uint8_t *)tmp->data()) + (tmp->size() - ZT_ECC384_SIGNATURE_SIZE)))
return false;
}
deserialize(*tmp,0);

View file

@ -33,6 +33,7 @@
#include "Network.hpp"
#include "Trace.hpp"
#include "ScopedPtr.hpp"
#include "Locator.hpp"
namespace ZeroTier {
@ -172,6 +173,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
#if 0
struct _processBackgroundTasks_ping_eachRoot
{
Hashtable< void *,bool > roots;
@ -179,7 +181,7 @@ struct _processBackgroundTasks_ping_eachRoot
void *tPtr;
bool online;
inline void operator()(const Root &root,const SharedPtr<Peer> &peer)
ZT_ALWAYS_INLINE void operator()(const Root &root,const SharedPtr<Peer> &peer)
{
unsigned int v4SendCount = 0,v6SendCount = 0;
peer->ping(tPtr,now,v4SendCount,v6SendCount);
@ -204,6 +206,7 @@ struct _processBackgroundTasks_ping_eachRoot
roots.set((void *)peer.ptr(),true);
}
};
#endif
struct _processBackgroundTasks_ping_eachPeer
{
@ -211,7 +214,7 @@ struct _processBackgroundTasks_ping_eachPeer
void *tPtr;
Hashtable< void *,bool > *roots;
inline void operator()(const SharedPtr<Peer> &peer)
ZT_ALWAYS_INLINE void operator()(const SharedPtr<Peer> &peer)
{
if (!roots->contains((void *)peer.ptr())) {
unsigned int v4SendCount = 0,v6SendCount = 0;
@ -234,22 +237,24 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
if ((now - _lastPing) >= ZT_PEER_PING_PERIOD) {
_lastPing = now;
try {
#if 0
_processBackgroundTasks_ping_eachRoot rf;
rf.now = now;
rf.tPtr = tptr;
rf.online = false;
RR->topology->eachRoot(rf);
#endif
_processBackgroundTasks_ping_eachPeer pf;
pf.now = now;
pf.tPtr = tptr;
pf.roots = &rf.roots;
//pf.roots = &rf.roots;
RR->topology->eachPeer(pf);
if (rf.online != _online) {
_online = rf.online;
postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
}
//if (rf.online != _online) {
// _online = rf.online;
// postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
//}
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}

View file

@ -1,182 +0,0 @@
/*
* Copyright (c)2019 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: 2023-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.
*/
/****/
#ifndef ZT_ROOT_HPP
#define ZT_ROOT_HPP
#include "Constants.hpp"
#include "Str.hpp"
#include "ECC384.hpp"
#include "Locator.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
#include "Identity.hpp"
#include "Mutex.hpp"
namespace ZeroTier {
/**
* A root entry pointing to a node capable of global identity lookup and indirect transit
*
* Root entries point to DNS records that contain TXT entries that decode to Locator objects
* pointing to actual root nodes. A default root identity and static addresses can also be
* provided as fallback if DNS is not available.
*
* Note that root identities can change if DNS returns a different result, but that DNS entries
* are authenticated using their own signature scheme. This allows a root DNS name to serve
* up different roots based on factors like location or relative load of different roots.
*
* It's also possible to create a root with no DNS and no DNS validator public key. This root
* will be a static entry pointing to a single root identity and set of physical addresses.
*/
class Root
{
public:
ZT_ALWAYS_INLINE Root() : _dnsPublicKeySize(0) {}
/**
* Create a new root entry
*
* @param dn DNS name
* @param dnspk DNS public key for record validation
* @param dnspksize Size of DNS public key (currently always the size of a NIST P-384 point compressed public key)
* @param dflId Default identity if DNS is not available
* @param dflAddrs Default IP addresses if DNS is not available
*/
template<typename S>
ZT_ALWAYS_INLINE Root(S dn,const uint8_t *const dnspk,const unsigned int dnspksize,const Identity &dflId,const std::vector<InetAddress> &dflAddrs) :
_defaultIdentity(dflId),
_defaultAddresses(dflAddrs),
_dnsName(dn),
_dnsPublicKeySize(dnspksize)
{
if (dnspksize != 0) {
if (dnspksize > sizeof(_dnsPublicKey))
throw ZT_EXCEPTION_INVALID_ARGUMENT;
memcpy(_dnsPublicKey,dnspk,dnspksize);
}
}
/**
* @return Current identity (either default or latest locator)
*/
ZT_ALWAYS_INLINE const Identity id() const
{
if (_lastFetchedLocator.id())
return _lastFetchedLocator.id();
return _defaultIdentity;
}
/**
* @param id Identity to check
* @return True if identity equals this root's current identity
*/
ZT_ALWAYS_INLINE bool is(const Identity &id) const
{
return ((_lastFetchedLocator.id()) ? (id == _lastFetchedLocator.id()) : (id == _defaultIdentity));
}
/**
* @return Current ZeroTier address (either default or latest locator)
*/
ZT_ALWAYS_INLINE const Address address() const
{
if (_lastFetchedLocator.id())
return _lastFetchedLocator.id().address();
return _defaultIdentity.address();
}
/**
* @return DNS name for this root or empty string if static entry with no DNS
*/
ZT_ALWAYS_INLINE const Str dnsName() const { return _dnsName; }
/**
* @return Latest locator or NIL locator object if none
*/
ZT_ALWAYS_INLINE Locator locator() const { return _lastFetchedLocator; }
/**
* @return Timestamp of latest retrieved locator or 0 if none
*/
ZT_ALWAYS_INLINE int64_t locatorTimestamp() const { return _lastFetchedLocator.timestamp(); }
/**
* Update locator, returning true if new locator is valid and newer than existing
*/
ZT_ALWAYS_INLINE bool updateLocator(const Locator &loc)
{
if (!loc.verify())
return false;
if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) {
_lastFetchedLocator = loc;
return true;
}
return false;
}
/**
* Update this root's locator from a series of TXT records
*/
template<typename I>
ZT_ALWAYS_INLINE bool updateLocatorFromTxt(I start,I end)
{
try {
if (_dnsPublicKeySize != ZT_ECC384_PUBLIC_KEY_SIZE)
return false;
Locator loc;
if (!loc.decodeTxtRecords(start,end,_dnsPublicKey)) // also does verify()
return false;
if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) {
_lastFetchedLocator = loc;
return true;
}
return false;
} catch ( ... ) {}
return false;
}
/**
* Pick a random physical IP for this root with the given address family
*
* @param addressFamily AF_INET or AF_INET6
* @return Address or InetAddress::NIL if no addresses exist for the given family
*/
ZT_ALWAYS_INLINE const InetAddress &pickPhysical(const int addressFamily) const
{
std::vector<const InetAddress *> pickList;
const std::vector<InetAddress> *const av = (_lastFetchedLocator) ? &(_lastFetchedLocator.phy()) : &_defaultAddresses;
for(std::vector<InetAddress>::const_iterator i(av->begin());i!=av->end();++i) {
if (addressFamily == (int)i->ss_family) {
pickList.push_back(&(*i));
}
}
if (pickList.size() == 1)
return *pickList[0];
else if (pickList.size() > 1)
return *pickList[(unsigned long)Utils::random() % (unsigned long)pickList.size()];
return InetAddress::NIL;
}
private:
Identity _defaultIdentity;
std::vector<InetAddress> _defaultAddresses;
Str _dnsName;
Locator _lastFetchedLocator;
unsigned int _dnsPublicKeySize;
uint8_t _dnsPublicKey[ZT_ECC384_PUBLIC_KEY_SIZE];
};
} // namespace ZeroTier
#endif

View file

@ -151,14 +151,35 @@ public:
return ((*this) << a.toString(tmp));
}
ZT_ALWAYS_INLINE Str &append(const char *s,const unsigned int max)
{
if (likely(s != (const char *)0)) {
unsigned long l = _l;
unsigned int c = 0;
while (*s) {
if (c++ >= max) break;
if (unlikely(l >= ZT_STR_CAPACITY)) {
_s[ZT_STR_CAPACITY] = 0;
_l = ZT_STR_CAPACITY;
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
_s[l++] = *s;
++s;
}
_s[l] = 0;
_l = (uint8_t)l;
}
return *this;
}
ZT_ALWAYS_INLINE operator bool() const { return (_l != 0); }
ZT_ALWAYS_INLINE bool operator==(const Str &s) const { return ((_l == s._l)&&(strcmp(_s,s._s) == 0)); }
ZT_ALWAYS_INLINE bool operator!=(const Str &s) const { return ((_l != s._l)||(strcmp(_s,s._s) != 0)); }
ZT_ALWAYS_INLINE bool operator<(const Str &s) const { return ((_l < s._l)&&(strcmp(_s,s._s) < 0)); }
ZT_ALWAYS_INLINE bool operator>(const Str &s) const { return ((_l > s._l)&&(strcmp(_s,s._s) > 0)); }
ZT_ALWAYS_INLINE bool operator<=(const Str &s) const { return ((_l <= s._l)&&(strcmp(_s,s._s) <= 0)); }
ZT_ALWAYS_INLINE bool operator>=(const Str &s) const { return ((_l >= s._l)&&(strcmp(_s,s._s) >= 0)); }
ZT_ALWAYS_INLINE bool operator==(const Str &s) const { return ((_l == s._l)&&(memcmp(_s,s._s,_l) == 0)); }
ZT_ALWAYS_INLINE bool operator!=(const Str &s) const { return ((_l != s._l)||(memcmp(_s,s._s,_l) != 0)); }
ZT_ALWAYS_INLINE bool operator<(const Str &s) const { return ( (_l < s._l) ? true : ((_l == s._l) ? (memcmp(_s,s._s,_l) < 0) : false) ); }
ZT_ALWAYS_INLINE bool operator>(const Str &s) const { return (s < *this); }
ZT_ALWAYS_INLINE bool operator<=(const Str &s) const { return !(s < *this); }
ZT_ALWAYS_INLINE bool operator>=(const Str &s) const { return !(*this < s); }
ZT_ALWAYS_INLINE bool operator==(const char *s) const { return (strcmp(_s,s) == 0); }
ZT_ALWAYS_INLINE bool operator!=(const char *s) const { return (strcmp(_s,s) != 0); }
@ -167,6 +188,16 @@ public:
ZT_ALWAYS_INLINE bool operator<=(const char *s) const { return (strcmp(_s,s) <= 0); }
ZT_ALWAYS_INLINE bool operator>=(const char *s) const { return (strcmp(_s,s) >= 0); }
ZT_ALWAYS_INLINE unsigned long hashCode() const
{
const char *p = _s;
unsigned long h = 0;
char c;
while ((c = *(p++)))
h = (31 * h) + (unsigned long)c;
return h;
}
private:
uint8_t _l;
char _s[ZT_STR_CAPACITY+1];

View file

@ -21,6 +21,7 @@
#include <stdexcept>
#include <algorithm>
#include <utility>
#include <set>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
@ -32,8 +33,9 @@
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "Root.hpp"
#include "Locator.hpp"
#include "SharedPtr.hpp"
#include "ScopedPtr.hpp"
namespace ZeroTier {
@ -65,7 +67,7 @@ public:
{
SharedPtr<Peer> np;
{
Mutex::Lock _l(_peers_m);
Mutex::Lock _l(_peers_l);
SharedPtr<Peer> &hp = _peers[peer->address()];
if (!hp)
hp = peer;
@ -86,11 +88,12 @@ public:
if (zta == _myIdentity.address())
return SharedPtr<Peer>();
Mutex::Lock l1(_peers_m);
Mutex::Lock l1(_peers_l);
const SharedPtr<Peer> *const ap = _peers.get(zta);
if (ap)
return *ap;
#if 0
Mutex::Lock l2(_roots_m);
for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) {
if (r->address() == zta) {
@ -101,6 +104,7 @@ public:
} catch ( ... ) {}
}
}
#endif
return SharedPtr<Peer>();
}
@ -115,7 +119,7 @@ public:
if (zta == _myIdentity.address()) {
return _myIdentity;
} else {
Mutex::Lock _l(_peers_m);
Mutex::Lock _l(_peers_l);
const SharedPtr<Peer> *const ap = _peers.get(zta);
if (ap)
return (*ap)->identity();
@ -132,7 +136,7 @@ public:
*/
ZT_ALWAYS_INLINE SharedPtr<Path> getPath(const int64_t l,const InetAddress &r)
{
Mutex::Lock _l(_paths_m);
Mutex::Lock _l(_paths_l);
SharedPtr<Path> &p = _paths[Path::HashKey(l,r)];
if (!p)
p.set(new Path(l,r));
@ -145,11 +149,13 @@ public:
*/
ZT_ALWAYS_INLINE bool isRoot(const Identity &id) const
{
#if 0
Mutex::Lock l(_roots_m);
for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) {
if (r->is(id))
return true;
}
#endif
return false;
}
@ -159,7 +165,7 @@ public:
ZT_ALWAYS_INLINE void doPeriodicTasks(int64_t now)
{
{
Mutex::Lock _l1(_peers_m);
Mutex::Lock _l1(_peers_l);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
@ -170,7 +176,7 @@ public:
}
}
{
Mutex::Lock _l(_paths_m);
Mutex::Lock _l(_paths_l);
Hashtable< Path::HashKey,SharedPtr<Path> >::Iterator i(_paths);
Path::HashKey *k = (Path::HashKey *)0;
SharedPtr<Path> *p = (SharedPtr<Path> *)0;
@ -188,7 +194,7 @@ public:
ZT_ALWAYS_INLINE unsigned long countActive(int64_t now) const
{
unsigned long cnt = 0;
Mutex::Lock _l(_peers_m);
Mutex::Lock _l(_peers_l);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
@ -212,7 +218,7 @@ public:
template<typename F>
ZT_ALWAYS_INLINE void eachPeer(F f)
{
Mutex::Lock l(_peers_m);
Mutex::Lock l(_peers_l);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
@ -221,6 +227,7 @@ public:
}
}
#if 0
/**
* Apply a function or function object to all roots
*
@ -237,7 +244,7 @@ public:
SharedPtr<Peer> rp;
for(std::vector<Root>::const_iterator i(_roots.begin());i!=_roots.end();++i) {
{
Mutex::Lock l2(_peers_m);
Mutex::Lock l2(_peers_l);
const SharedPtr<Peer> *const ap = _peers.get(i->address());
if (ap) {
rp = *ap;
@ -256,7 +263,7 @@ public:
* @param now Current time
* @return Best/fastest currently connected root or NULL if none
*/
ZT_ALWAYS_INLINE SharedPtr<Peer> root(const int64_t now)
inline SharedPtr<Peer> root(const int64_t now)
{
Mutex::Lock l(_bestRoot_m);
if ((!_bestRoot)||((now - _lastRankedBestRoot) >= ZT_FIND_BEST_ROOT_PERIOD)) {
@ -266,7 +273,7 @@ public:
long bestQuality = 2147483647;
for(std::vector<Root>::const_iterator i(_roots.begin());i!=_roots.end();++i) {
{
Mutex::Lock l2(_peers_m);
Mutex::Lock l2(_peers_l);
const SharedPtr<Peer> *const ap = _peers.get(i->address());
if (ap) {
rp = *ap;
@ -287,6 +294,54 @@ public:
}
return _bestRoot;
}
#endif
ZT_ALWAYS_INLINE SharedPtr<Peer> root(const int64_t now)
{
return SharedPtr<Peer>();
}
/**
* @return Names of dynamic roots currently known by the system
*/
ZT_ALWAYS_INLINE std::vector<Str> dynamicRootNames() const
{
Mutex::Lock l(_dynamicRoots_l);
return _dynamicRoots.keys();
}
/**
* Set or update a static root entry
*
* @param id Static root's identity
* @param addrs Static root's IP address(es)
*/
ZT_ALWAYS_INLINE void setStaticRoot(const Identity &id,const std::vector<InetAddress> &addrs)
{
Mutex::Lock l(_staticRoots_l);
_staticRoots[id] = addrs;
}
/**
* Set or update dynamic root if new locator is newer and valid
*
* This checks internal validity of the new locator including its internal self-signature.
* It does not check any DNS signatures.
*
* @param dnsName DNS name used to retrive root
* @param latestLocator Latest locator
* @return True if latest locator is internally valid and newer
*/
ZT_ALWAYS_INLINE bool setDynamicRoot(const Str &dnsName,const Locator &latestLocator)
{
Mutex::Lock l(_dynamicRoots_l);
Locator &ll = _dynamicRoots[dnsName];
if (ll.timestamp() < latestLocator.timestamp()) {
ll = latestLocator;
return true;
}
return false;
}
/**
* Get the best relay to a given address, which may or may not be a root
@ -298,15 +353,15 @@ public:
ZT_ALWAYS_INLINE SharedPtr<Peer> findRelayTo(const int64_t now,const Address &toAddr)
{
// TODO: in the future this will check 'mesh-like' relays and if enabled consult LF for other roots (for if this is a root)
return root(now);
//return root(now);
}
/**
* @param allPeers vector to fill with all current peers
*/
ZT_ALWAYS_INLINE void getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const
inline void getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const
{
Mutex::Lock l(_peers_m);
Mutex::Lock l(_peers_l);
allPeers.clear();
allPeers.reserve(_peers.size());
Hashtable< Address,SharedPtr<Peer> >::Iterator i(*(const_cast<Hashtable< Address,SharedPtr<Peer> > *>(&_peers)));
@ -385,7 +440,7 @@ public:
/**
* Set or clear physical path configuration (called via Node::setPhysicalPathConfiguration)
*/
ZT_ALWAYS_INLINE void setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig)
inline void setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig)
{
if (!pathNetwork) {
_numConfiguredPhysicalPaths = 0;
@ -422,17 +477,26 @@ public:
private:
const RuntimeEnvironment *const RR;
const Identity _myIdentity;
std::pair<InetAddress,ZT_PhysicalPathConfiguration> _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
unsigned int _numConfiguredPhysicalPaths;
std::vector<Root> _roots;
SharedPtr<Peer> _bestRoot;
int64_t _lastRankedBestRoot;
Hashtable< Address,SharedPtr<Peer> > _peers;
Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
Mutex _roots_m;
Mutex _bestRoot_m;
Mutex _peers_m;
Mutex _paths_m;
Hashtable< Identity,std::vector<InetAddress> > _staticRoots;
Hashtable< Str,Locator > _dynamicRoots;
//std::vector<Root> _roots;
//SharedPtr<Peer> _bestRoot;
//int64_t _lastRankedBestRoot;
//Mutex _roots_m;
//Mutex _bestRoot_m;
Mutex _peers_l;
Mutex _paths_l;
Mutex _staticRoots_l;
Mutex _dynamicRoots_l;
};
} // namespace ZeroTier

View file

@ -95,6 +95,49 @@ char *Utils::decimal(unsigned long n,char s[24])
return s;
}
unsigned short Utils::crc16(const void *buf,unsigned int len)
{
static const uint16_t crc16tab[256]= {
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
uint16_t crc = 0;
const uint8_t *p = (const uint8_t *)buf;
for(unsigned int i=0;i<len;++i)
crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ *(p++)) & 0x00ff];
return crc;
}
unsigned int Utils::unhex(const char *h,void *buf,unsigned int buflen)
{
unsigned int l = 0;

View file

@ -68,6 +68,11 @@ public:
*/
static char *decimal(unsigned long n,char s[24]);
/**
* Compute CRC16-CCITT
*/
static uint16_t crc16(const void *buf,unsigned int len);
/**
* Convert an unsigned integer into hex
*