Simplify root API

This commit is contained in:
Adam Ierymenko 2019-09-26 13:35:56 -07:00
parent 7061f13b24
commit 3b3e6d2bfc
No known key found for this signature in database
GPG Key ID: C8877CF2D7A5D7F3
8 changed files with 149 additions and 299 deletions

View File

@ -355,6 +355,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
if req.Method == http.MethodPost || req.Method == http.MethodPut {
if queriedID == 0 {
apiSendObj(out, req, http.StatusBadRequest, nil)
} else {
}
} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
roots := node.Roots()

View File

@ -624,12 +624,18 @@ func (n *Node) Peers() []*Peer {
p2.Version = [3]int{int(p.versionMajor), int(p.versionMinor), int(p.versionRev)}
p2.Latency = int(p.latency)
p2.Role = int(p.role)
p2.Paths = make([]Path, 0, int(p.pathCount))
usingAllocation := false
for j := uintptr(0); j < uintptr(p.pathCount); j++ {
pt := &p.paths[j]
if pt.alive != 0 {
a := sockaddrStorageToUDPAddr(&pt.address)
if a != nil {
alloc := float32(pt.allocation)
if alloc > 0.0 {
usingAllocation = true
}
p2.Paths = append(p2.Paths, Path{
IP: a.IP,
Port: a.Port,
@ -644,18 +650,44 @@ func (n *Node) Peers() []*Peer {
Stability: float32(pt.stability),
Throughput: uint64(pt.throughput),
MaxThroughput: uint64(pt.maxThroughput),
Allocation: float32(pt.allocation),
Allocation: alloc,
})
}
}
}
sort.Slice(p2.Paths, func(a, b int) bool { return p2.Paths[a].LastReceive < p2.Paths[b].LastReceive })
if !usingAllocation { // if all allocations are zero fall back to single path mode that uses the preferred flag
for i, j := 0, uintptr(0); j < uintptr(p.pathCount); j++ {
pt := &p.paths[j]
if pt.alive != 0 {
if pt.preferred == 0 {
p2.Paths[i].Allocation = 0.0
} else {
p2.Paths[i].Allocation = 1.0
}
i++
}
}
}
sort.Slice(p2.Paths, func(a, b int) bool {
pa := &p2.Paths[a]
pb := &p2.Paths[b]
if pb.Allocation < pa.Allocation { // invert order, put highest allocation paths first
return true
}
if pa.Allocation == pb.Allocation {
return pa.LastReceive < pb.LastReceive // then sort by most recent activity
}
return false
})
p2.Clock = TimeMs()
peers = append(peers, p2)
}
C.ZT_Node_freeQueryResult(unsafe.Pointer(n.zn), unsafe.Pointer(pl))
}
sort.Slice(peers, func(a, b int) bool { return peers[a].Address < peers[b].Address })
sort.Slice(peers, func(a, b int) bool {
return peers[a].Address < peers[b].Address
})
return peers
}

View File

@ -18,9 +18,13 @@ type Root struct {
DNSName string
Identity *Identity
Addresses []InetAddress
Locator []byte
Preferred bool
Online bool
}
// Static returns true if this is a static root
func (r *Root) Static() bool { return len(r.DNSName) == 0 }
// Dynamic returns true if this is a dynamic root
func (r *Root) Dynamic() bool { return len(r.DNSName) > 0 }

View File

@ -1887,47 +1887,27 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_
ZT_SDK_API ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now);
/**
* Set a static root
*
* @param node Node instance
* @param identity Public identity of static root
* @param addresses Physical address(es) of root
* @param addressCount Number of physical addresses
* @return OK (0) or error code
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_setStaticRoot(ZT_Node *node,const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount);
/**
* Set a dynamic root
* Add or update a root
*
* The node will begin trying to resolve the DNS TXT record for
* this root and possibly obtain it from other peers.
*
* @param node Node instance
* @param dnsName DNS name whose TXT record(s) contain the latest Locator for this root
* @param defaultLocator Binary-serialized default locator of NULL if none (used if TXT records are not retrievable)
* @param defaultLocatorSize Size of default locator or 0 if none
* @param name DNS name or simply the address in hex form for static roots
* @param locator Binary-serialized locator of NULL if none
* @param locatorSize Size of locator or 0 if none
* @return OK (0) or error code
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_setDynamicRoot(ZT_Node *node,const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize);
/**
* Remove a static root
*
* @param node Node instance
* @param identity Public identity of this root
* @return OK (0) or error code
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeStaticRoot(ZT_Node *node,const char *identity);
ZT_SDK_API enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize);
/**
* Remove a dynamic root
*
* @param node Node instance
* @param dnsName DNS name of this dynamic root
* @param name DNS name of this dynamic root or the address in hex form for static roots
* @return OK (0) or error code
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeDynamicRoot(ZT_Node *node,const char *dnsName);
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name);
/**
* Get this node's 40-bit ZeroTier address

View File

@ -26,6 +26,7 @@
#include <algorithm>
#include <vector>
// These are absolute maximums -- real locators are never this big
#define ZT_LOCATOR_MAX_PHYSICAL_ADDRESSES 255
#define ZT_LOCATOR_MAX_VIRTUAL_ADDRESSES 255
@ -38,19 +39,15 @@ namespace ZeroTier {
* may be found. It can contain static physical addresses or virtual ZeroTier
* addresses of nodes that can forward to the target node. Locator records
* can be stored in signed DNS TXT record sets, in LF by roots, in caches,
* etc. Version 2.x nodes can sign their own locators. Roots can create
* signed locators using their own signature for version 1.x nodes. Locators
* signed by the node whose location they describe always take precedence
* over locators signed by other nodes.
* etc.
*/
class Locator
{
public:
ZT_ALWAYS_INLINE Locator() : _ts(0),_signatureLength(0) {}
ZT_ALWAYS_INLINE const Identity &id() const { return _id; }
ZT_ALWAYS_INLINE const Identity &signer() const { return ((_signedBy) ? _signedBy : _id); }
ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
ZT_ALWAYS_INLINE const Identity &id() const { return _id; }
ZT_ALWAYS_INLINE const std::vector<InetAddress> &phy() const { return _physical; }
ZT_ALWAYS_INLINE const std::vector<Identity> &virt() const { return _virtual; }
@ -76,11 +73,11 @@ public:
/**
* Method to be called after add() is called for each address or forwarding node
*
* This sets timestamp and ID information and sorts and deduplicates target
* lists but does not sign the locator. The sign() method should be used after
* finish().
* @param id Identity that this locator describes (must contain private key)
* @param ts Current time
* @return True if completion and signature were successful
*/
ZT_ALWAYS_INLINE void finish(const Identity &id,const int64_t ts)
ZT_ALWAYS_INLINE bool finish(const Identity &id,const int64_t ts)
{
_ts = ts;
_id = id;
@ -88,24 +85,10 @@ public:
_physical.erase(std::unique(_physical.begin(),_physical.end()),_physical.end());
std::sort(_virtual.begin(),_virtual.end());
_virtual.erase(std::unique(_virtual.begin(),_virtual.end()),_virtual.end());
}
/**
* Sign this locator (must be called after finish())
*/
ZT_ALWAYS_INLINE bool sign(const Identity &signingId)
{
if (!signingId.hasPrivate())
return false;
if (signingId == _id) {
_signedBy.zero();
} else {
_signedBy = signingId;
}
try {
ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
serialize(*tmp,true);
_signatureLength = signingId.sign(tmp->data(),tmp->size(),_signature,ZT_SIGNATURE_BUFFER_SIZE);
_signatureLength = id.sign(tmp->data(),tmp->size(),_signature,ZT_SIGNATURE_BUFFER_SIZE);
return (_signatureLength > 0);
} catch ( ... ) {
return false;
@ -122,8 +105,7 @@ public:
try {
ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
serialize(*tmp,true);
const bool ok = (_signedBy) ? _signedBy.verify(tmp->data(),tmp->size(),_signature,_signatureLength) : _id.verify(tmp->data(),tmp->size(),_signature,_signatureLength);
return ok;
return _id.verify(tmp->data(),tmp->size(),_signature,_signatureLength);
} catch ( ... ) {
return false;
}
@ -155,6 +137,8 @@ public:
}
/**
* This searches for an extracts a public key from a DNS name, if one is present.
*
* @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])
@ -210,8 +194,9 @@ public:
ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
serialize(*tmp,false);
SHA384(s384,tmp->data(),tmp->size());
ECC384ECDSASign(p384SigningKeyPrivate,s384,((uint8_t *)tmp->unsafeData()) + tmp->size());
const unsigned int sigLocation = tmp->size();
tmp->addSize(ZT_ECC384_SIGNATURE_SIZE);
ECC384ECDSASign(p384SigningKeyPrivate,s384,((uint8_t *)tmp->unsafeData()) + sigLocation);
// Blob must be broken into multiple TXT records that must remain sortable so they are prefixed by a hex value.
// 186-byte chunks yield 248-byte base64 chunks which leaves some margin below the limit of 255.
@ -292,12 +277,6 @@ public:
b.append((uint8_t)0); // version/flags, currently 0
b.append((uint64_t)_ts);
_id.serialize(b,false);
if (_signedBy) {
b.append((uint8_t)1); // number of signers, current max is 1
_signedBy.serialize(b,false); // be sure not to include private key!
} else {
b.append((uint8_t)0); // signer is _id
}
b.append((uint8_t)_physical.size());
for(std::vector<InetAddress>::const_iterator i(_physical.begin());i!=_physical.end();++i)
i->serialize(b);
@ -354,16 +333,25 @@ public:
ZT_ALWAYS_INLINE bool addressesEqual(const Locator &l) const { return ((_physical == l._physical)&&(_virtual == l._virtual)); }
ZT_ALWAYS_INLINE bool operator==(const Locator &l) const { return ((_ts == l._ts)&&(_id == l._id)&&(_signedBy == l._signedBy)&&(_physical == l._physical)&&(_virtual == l._virtual)&&(_signatureLength == l._signatureLength)&&(memcmp(_signature,l._signature,_signatureLength) == 0)); }
ZT_ALWAYS_INLINE bool operator==(const Locator &l) const
{
return (
(_ts == l._ts)&&
(_id == l._id)&&
(_physical == l._physical)&&
(_virtual == l._virtual)&&
(_signatureLength == l._signatureLength)&&
(memcmp(_signature,l._signature,_signatureLength) == 0));
}
ZT_ALWAYS_INLINE bool operator!=(const Locator &l) const { return (!(*this == l)); }
ZT_ALWAYS_INLINE bool operator<(const Locator &l) const
{
if (_id < l._id) return true;
if (_ts < l._ts) return true;
if (_signedBy < l._signedBy) return true;
if (_physical < l._physical) return true;
if (_virtual < l._virtual) return true;
return false;
if (_ts < l._ts) return true; else if (_ts > l._ts) return false;
if (_id < l._id) return true; else if (_id > l._id) return false;
if (_physical < l._physical) return true; else if (_physical > l._physical) return false;
if (_virtual < l._virtual) return true; else if (_virtual > l._virtual) return false;
if (_signatureLength < l._signatureLength) return true;
return (_signatureLength == l._signatureLength) ? (memcmp(_signature,l._signature,_signatureLength) < 0) : false;
}
ZT_ALWAYS_INLINE bool operator>(const Locator &l) const { return (l < *this); }
ZT_ALWAYS_INLINE bool operator<=(const Locator &l) const { return (!(l < *this)); }
@ -374,7 +362,6 @@ public:
private:
int64_t _ts;
Identity _id;
Identity _signedBy; // signed by _id if nil/zero
std::vector<InetAddress> _physical;
std::vector<Identity> _virtual;
unsigned int _signatureLength;

View File

@ -170,7 +170,9 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
if (nw) {
RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength);
return ZT_RESULT_OK;
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
} else {
return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
}
// This is passed as the argument to the DNS request handler and
@ -184,7 +186,7 @@ struct _processBackgroundTasks_dnsResultAccumulator
static const ZT_DNSRecordType s_txtRecordType[1] = { ZT_DNS_RECORD_TXT };
struct _processBackgroundTasks_check_dynamicRoots
struct _processBackgroundTasks_eachRootName
{
ZT_Node_Callbacks *cb;
Node *n;
@ -194,7 +196,7 @@ struct _processBackgroundTasks_check_dynamicRoots
ZT_ALWAYS_INLINE bool operator()(const Str &dnsName,const Locator &loc)
{
if ((updateAll)||(!loc)) {
if ((strchr(dnsName.c_str(),'.'))&&((updateAll)||(!loc))) {
_processBackgroundTasks_dnsResultAccumulator *dnsReq = new _processBackgroundTasks_dnsResultAccumulator(dnsName);
cb->dnsResolver(reinterpret_cast<ZT_Node *>(n),uPtr,tPtr,s_txtRecordType,1,dnsName.c_str(),(uintptr_t)dnsReq);
}
@ -258,7 +260,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
try {
// Periodically refresh locators for dynamic roots from their DNS names.
if (_cb.dnsResolver) {
_processBackgroundTasks_check_dynamicRoots cr;
_processBackgroundTasks_eachRootName cr;
cr.cb = &_cb;
cr.n = this;
cr.uPtr = _uPtr;
@ -269,7 +271,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
} else {
cr.updateAll = false;
}
RR->topology->eachDynamicRoot(cr);
RR->topology->eachRootName(cr);
}
// Ping each root explicitly no matter what
@ -363,7 +365,7 @@ void Node::processDNSResult(
} else if (recordType == ZT_DNS_RECORD__END_OF_RESULTS) {
Locator loc;
if (loc.decodeTxtRecords(acc->dnsName,acc->txtRecords.begin(),acc->txtRecords.end())) {
RR->topology->setDynamicRoot(acc->dnsName,loc);
RR->topology->setRoot(acc->dnsName,loc);
delete acc;
}
}
@ -434,59 +436,38 @@ ZT_RootList *Node::listRoots(int64_t now)
return RR->topology->apiRoots(now);
}
enum ZT_ResultCode Node::setStaticRoot(const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount)
enum ZT_ResultCode Node::setRoot(const char *name,const void *locator,unsigned int locatorSize)
{
if (!identity)
return ZT_RESULT_ERROR_BAD_PARAMETER;
Identity id;
if (id.fromString(identity)) {
if (id) {
std::vector<InetAddress> addrs;
for(unsigned int i=0;i<addressCount;++i)
addrs.push_back(InetAddress(addresses[i]));
RR->topology->setStaticRoot(identity,addrs);
return ZT_RESULT_OK;
}
}
return ZT_RESULT_ERROR_BAD_PARAMETER;
}
enum ZT_ResultCode Node::setDynamicRoot(const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize)
{
if (!dnsName)
return ZT_RESULT_ERROR_BAD_PARAMETER;
if (strlen(dnsName) >= 256)
return ZT_RESULT_ERROR_BAD_PARAMETER;
try {
Locator loc;
if ((defaultLocator)&&(defaultLocatorSize > 0)&&(defaultLocatorSize < 65535)) {
if ((locator)&&(locatorSize > 0)&&(locatorSize < 65535)) {
ScopedPtr< Buffer<65536> > locbuf(new Buffer<65536>());
locbuf->append(defaultLocator,defaultLocatorSize);
locbuf->append(locator,locatorSize);
loc.deserialize(*locbuf,0);
if (!loc.verify())
loc = Locator();
return ZT_RESULT_ERROR_BAD_PARAMETER;
}
return RR->topology->setDynamicRoot(Str(dnsName),loc) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED;
Str n;
if ((!name)||(strlen(name) == 0)) {
if (!loc)
return ZT_RESULT_ERROR_BAD_PARAMETER; /* no name and no locator */
char tmp[16];
loc.id().address().toString(tmp);
n = tmp;
} else {
n = name;
}
return RR->topology->setRoot(n,loc) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED;
} catch ( ... ) {
return ZT_RESULT_ERROR_BAD_PARAMETER;
}
}
enum ZT_ResultCode Node::removeStaticRoot(const char *identity)
{
if (identity) {
Identity id;
if (id.fromString(identity))
RR->topology->removeStaticRoot(id);
}
return ZT_RESULT_OK;
}
enum ZT_ResultCode Node::removeDynamicRoot(const char *dnsName)
enum ZT_ResultCode Node::removeRoot(const char *name)
{
try {
if (dnsName)
RR->topology->removeDynamicRoot(Str(dnsName));
if (name)
RR->topology->removeRoot(Str(name));
} catch ( ... ) {}
return ZT_RESULT_OK;
}
@ -937,10 +918,10 @@ ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now)
}
}
enum ZT_ResultCode ZT_Node_setStaticRoot(ZT_Node *node,const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount)
enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->setStaticRoot(identity,addresses,addressCount);
return reinterpret_cast<ZeroTier::Node *>(node)->setRoot(name,locator,locatorSize);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
@ -948,32 +929,10 @@ enum ZT_ResultCode ZT_Node_setStaticRoot(ZT_Node *node,const char *identity,cons
}
}
enum ZT_ResultCode ZT_Node_setDynamicRoot(ZT_Node *node,const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize)
enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->setDynamicRoot(dnsName,defaultLocator,defaultLocatorSize);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_removeStaticRoot(ZT_Node *node,const char *identity)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->removeStaticRoot(identity);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_removeDynamicRoot(ZT_Node *node,const char *dnsName)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->removeDynamicRoot(dnsName);
return reinterpret_cast<ZeroTier::Node *>(node)->removeRoot(name);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {

View File

@ -93,10 +93,8 @@ public:
ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_RootList *listRoots(int64_t now);
enum ZT_ResultCode setStaticRoot(const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount);
enum ZT_ResultCode setDynamicRoot(const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize);
enum ZT_ResultCode removeStaticRoot(const char *identity);
enum ZT_ResultCode removeDynamicRoot(const char *dnsName);
enum ZT_ResultCode setRoot(const char *name,const void *locator,unsigned int locatorSize);
enum ZT_ResultCode removeRoot(const char *name);
uint64_t address() const;
void status(ZT_NodeStatus *status) const;
ZT_PeerList *peers() const;

View File

@ -66,14 +66,14 @@ private:
ZT_ALWAYS_INLINE void _updateDynamicRootIdentities()
{
// assumes _dynamicRoots_l is locked
_dynamicRootIdentities.clear();
Hashtable< Str,Locator >::Iterator i(_dynamicRoots);
// assumes _roots_l is locked
_rootIdentities.clear();
Hashtable< Str,Locator >::Iterator i(_roots);
Str *k = (Str *)0;
Locator *v = (Locator *)0;
while (i.next(k,v)) {
if (*v)
_dynamicRootIdentities.set(v->id(),true);
_rootIdentities.set(v->id(),true);
}
}
@ -81,6 +81,10 @@ public:
ZT_ALWAYS_INLINE Topology(const RuntimeEnvironment *renv,const Identity &myId) :
RR(renv),
_myIdentity(myId),
_peers(64),
_paths(128),
_roots(8),
_rootIdentities(8),
_numConfiguredPhysicalPaths(0),
_lastUpdatedBestRoot(0) {}
ZT_ALWAYS_INLINE ~Topology() {}
@ -166,17 +170,8 @@ public:
*/
ZT_ALWAYS_INLINE bool isRoot(const Identity &id) const
{
{
Mutex::Lock l(_dynamicRoots_l);
if (_dynamicRootIdentities.contains(id))
return true;
}
{
Mutex::Lock l(_staticRoots_l);
if (_staticRoots.contains(id))
return true;
}
return false;
Mutex::Lock l(_roots_l);
return _rootIdentities.contains(id);
}
/**
@ -260,57 +255,28 @@ public:
template<typename F>
ZT_ALWAYS_INLINE void eachRoot(F f)
{
{
Mutex::Lock l(_dynamicRoots_l);
Hashtable< Str,Locator >::Iterator i(_dynamicRoots);
Str *k = (Str *)0;
Locator *v = (Locator *)0;
while (i.next(k,v)) {
if (*v) {
for(std::vector<Identity>::const_iterator id(v->virt().begin());id!=v->virt().end();++id) {
const SharedPtr<Peer> *ap;
{
Mutex::Lock l2(_peers_l);
ap = _peers.get(id->address());
}
if (ap) {
if (!f(*ap,v->phy()))
return;
} else {
SharedPtr<Peer> p(new Peer(RR,_myIdentity,*id));
{
Mutex::Lock l2(_peers_l);
_peers.set(id->address(),p);
}
if (!f(p,v->phy()))
return;
}
}
}
}
}
{
Mutex::Lock l(_staticRoots_l);
Hashtable< Identity,std::vector<InetAddress> >::Iterator i(_staticRoots);
Identity *k = (Identity *)0;
std::vector<InetAddress> *v = (std::vector<InetAddress> *)0;
while (i.next(k,v)) {
if (!v->empty()) {
Mutex::Lock l(_roots_l);
Hashtable< Str,Locator >::Iterator i(_roots);
Str *k = (Str *)0;
Locator *v = (Locator *)0;
while (i.next(k,v)) {
if (*v) {
for(std::vector<Identity>::const_iterator id(v->virt().begin());id!=v->virt().end();++id) {
const SharedPtr<Peer> *ap;
{
Mutex::Lock l2(_peers_l);
ap = _peers.get(k->address());
ap = _peers.get(id->address());
}
if (ap) {
if (!f(*ap,*v))
if (!f(*ap,v->phy()))
return;
} else {
SharedPtr<Peer> p(new Peer(RR,_myIdentity,*k));
SharedPtr<Peer> p(new Peer(RR,_myIdentity,*id));
{
Mutex::Lock l2(_peers_l);
_peers.set(k->address(),p);
_peers.set(id->address(),p);
}
if (!f(p,*v))
if (!f(p,v->phy()))
return;
}
}
@ -335,49 +301,17 @@ public:
}
/**
* Set or update a static root entry
*
* @param id Static root's identity
* @param addrs Static root's IP address(es)
*/
inline void setStaticRoot(const Identity &id,const std::vector<InetAddress> &addrs)
{
Mutex::Lock l(_staticRoots_l);
_staticRoots[id] = addrs;
}
/**
* Remove a static root
*
* @param id Identity to remove
*/
inline void removeStaticRoot(const Identity &id)
{
Mutex::Lock l(_staticRoots_l);
_staticRoots.erase(id);
}
/**
* Clear all static roots
*/
inline void removeStaticRoot()
{
Mutex::Lock l(_staticRoots_l);
_staticRoots.clear();
}
/**
* Iterate through all dynamic roots
* Iterate through all root names
*
* @param f Function of (Str,Locator)
*/
template<typename F>
ZT_ALWAYS_INLINE void eachDynamicRoot(F f) const
ZT_ALWAYS_INLINE void eachRootName(F f) const
{
Mutex::Lock l(_dynamicRoots_l);
Mutex::Lock l(_roots_l);
Str *k = (Str *)0;
Locator *v = (Locator *)0;
Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_dynamicRoots);
Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_roots);
while (i.next(k,v)) {
if (!f(*k,*v))
break;
@ -389,22 +323,22 @@ public:
*
* This does not check signatures or internal validity of the locator.
*
* @param dnsName DNS name used to retrive root
* @param name DNS name used to retrive root or simply the address for static roots
* @param latestLocator Latest locator
* @return True if locator is newer or if a new entry was created
*/
inline bool setDynamicRoot(const Str &dnsName,const Locator &latestLocator)
inline bool setRoot(const Str &name,const Locator &latestLocator)
{
Mutex::Lock l(_dynamicRoots_l);
Mutex::Lock l(_roots_l);
if (latestLocator) {
Locator &ll = _dynamicRoots[dnsName];
Locator &ll = _roots[name];
if (ll.timestamp() < latestLocator.timestamp()) {
ll = latestLocator;
_updateDynamicRootIdentities();
return true;
}
} else if (!_dynamicRoots.contains(dnsName)) {
_dynamicRoots[dnsName];
} else if (!_roots.contains(name)) {
_roots[name];
return true;
}
return false;
@ -412,39 +346,26 @@ public:
/**
* Remove a dynamic root entry
*
* @param dnsName DNS name to remove
*/
inline void removeDynamicRoot(const Str &dnsName)
inline void removeRoot(const Str &name)
{
Mutex::Lock l(_dynamicRoots_l);
_dynamicRoots.erase(dnsName);
Mutex::Lock l(_roots_l);
_roots.erase(name);
_updateDynamicRootIdentities();
}
/**
* Remove all dynamic roots
*/
inline void clearDynamicRoots()
{
Mutex::Lock l(_dynamicRoots_l);
_dynamicRoots.clear();
_dynamicRootIdentities.clear();
}
/**
* @param Current time
* @return ZT_RootList as returned by the external CAPI
*/
inline ZT_RootList *apiRoots(const int64_t now) const
{
Mutex::Lock l1(_staticRoots_l);
Mutex::Lock l2(_dynamicRoots_l);
Mutex::Lock l2(_roots_l);
// The memory allocated here has room for all roots plus the maximum size
// of their DNS names, identities, and up to 16 physical addresses. Most
// roots will have two: one V4 and one V6.
const unsigned int totalRoots = _staticRoots.size() + _dynamicRoots.size();
const unsigned int totalRoots = _roots.size();
ZT_RootList *rl = reinterpret_cast<ZT_RootList *>(malloc(sizeof(ZT_RootList) + (sizeof(ZT_Root) * totalRoots) + ((sizeof(struct sockaddr_storage) * ZT_MAX_PEER_NETWORK_PATHS) * totalRoots) + ((ZT_IDENTITY_STRING_BUFFER_LENGTH + 1024) * totalRoots)));
if (!rl) {
return nullptr;
@ -462,7 +383,7 @@ public:
{
Str *k = (Str *)0;
Locator *v = (Locator *)0;
Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_dynamicRoots);
Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_roots);
while (i.next(k,v)) {
rl->roots[c].dnsName = nameBufPtr;
const char *p = k->c_str();
@ -494,35 +415,6 @@ public:
}
}
{
Hashtable< Identity,std::vector<InetAddress> >::Iterator i(const_cast<Topology *>(this)->_staticRoots);
Identity *k = (Identity *)0;
std::vector<InetAddress> *v = (std::vector<InetAddress> *)0;
while (i.next(k,v)) {
rl->roots[c].dnsName = nullptr;
rl->roots[c].identity = nameBufPtr;
k->toString(false,nameBufPtr);
nameBufPtr += strlen(nameBufPtr) + 1;
rl->roots[c].addresses = addrBuf;
unsigned int ac = 0;
for(unsigned int j=(unsigned int)v->size();(ac<j)&&(ac<16);++ac)
*(addrBuf++) = (*v)[ac];
rl->roots[c].addressCount = ac;
_peers_l.lock();
const SharedPtr<Peer> *psptr = _peers.get(k->address());
if (psptr) {
rl->roots[c].preferred = (psptr->ptr() == bestRootPtr) ? 1 : 0;
rl->roots[c].online = (*psptr)->alive(now) ? 1 : 0;
}
_peers_l.unlock();
++c;
}
}
rl->count = c;
return rl;
@ -668,18 +560,15 @@ private:
Hashtable< Address,SharedPtr<Peer> > _peers;
Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
Hashtable< Str,Locator > _dynamicRoots;
Hashtable< Identity,bool > _dynamicRootIdentities;
Hashtable< Identity,std::vector<InetAddress> > _staticRoots;
Hashtable< Str,Locator > _roots;
Hashtable< Identity,bool > _rootIdentities;
int64_t _lastUpdatedBestRoot;
SharedPtr<Peer> _bestRoot;
Mutex _peers_l;
Mutex _paths_l;
Mutex _dynamicRoots_l;
Mutex _staticRoots_l;
Mutex _roots_l;
Mutex _bestRoot_l;
};