diff --git a/go/pkg/zerotier/api.go b/go/pkg/zerotier/api.go index 81b29a8d4..dbb884685 100644 --- a/go/pkg/zerotier/api.go +++ b/go/pkg/zerotier/api.go @@ -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() diff --git a/go/pkg/zerotier/node.go b/go/pkg/zerotier/node.go index bb060348d..eb30c8aad 100644 --- a/go/pkg/zerotier/node.go +++ b/go/pkg/zerotier/node.go @@ -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 } diff --git a/go/pkg/zerotier/root.go b/go/pkg/zerotier/root.go index fdd3a8efb..5c328693e 100644 --- a/go/pkg/zerotier/root.go +++ b/go/pkg/zerotier/root.go @@ -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 } diff --git a/include/ZeroTierCore.h b/include/ZeroTierCore.h index 59bb8d9f7..ddded6dc8 100644 --- a/include/ZeroTierCore.h +++ b/include/ZeroTierCore.h @@ -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 diff --git a/node/Locator.hpp b/node/Locator.hpp index 97b3150be..237ee47e6 100644 --- a/node/Locator.hpp +++ b/node/Locator.hpp @@ -26,6 +26,7 @@ #include #include +// 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 &phy() const { return _physical; } ZT_ALWAYS_INLINE const std::vector &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::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 _physical; std::vector _virtual; unsigned int _signatureLength; diff --git a/node/Node.cpp b/node/Node.cpp index 69db64569..02a763772 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -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(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 addrs; - for(unsigned int i=0;itopology->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(node)->setStaticRoot(identity,addresses,addressCount); + return reinterpret_cast(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(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(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(node)->removeDynamicRoot(dnsName); + return reinterpret_cast(node)->removeRoot(name); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { diff --git a/node/Node.hpp b/node/Node.hpp index 3302fa903..1b594ea9c 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -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; diff --git a/node/Topology.hpp b/node/Topology.hpp index 5bb3416c5..7b929214f 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -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 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::const_iterator id(v->virt().begin());id!=v->virt().end();++id) { - const SharedPtr *ap; - { - Mutex::Lock l2(_peers_l); - ap = _peers.get(id->address()); - } - if (ap) { - if (!f(*ap,v->phy())) - return; - } else { - SharedPtr 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 >::Iterator i(_staticRoots); - Identity *k = (Identity *)0; - std::vector *v = (std::vector *)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::const_iterator id(v->virt().begin());id!=v->virt().end();++id) { const SharedPtr *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 p(new Peer(RR,_myIdentity,*k)); + SharedPtr 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 &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 - 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(this)->_dynamicRoots); + Hashtable< Str,Locator >::Iterator i(const_cast(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(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(this)->_dynamicRoots); + Hashtable< Str,Locator >::Iterator i(const_cast(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 >::Iterator i(const_cast(this)->_staticRoots); - Identity *k = (Identity *)0; - std::vector *v = (std::vector *)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();(acroots[c].addressCount = ac; - - _peers_l.lock(); - const SharedPtr *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 > _peers; Hashtable< Path::HashKey,SharedPtr > _paths; - - Hashtable< Str,Locator > _dynamicRoots; - Hashtable< Identity,bool > _dynamicRootIdentities; - Hashtable< Identity,std::vector > _staticRoots; + Hashtable< Str,Locator > _roots; + Hashtable< Identity,bool > _rootIdentities; int64_t _lastUpdatedBestRoot; SharedPtr _bestRoot; Mutex _peers_l; Mutex _paths_l; - Mutex _dynamicRoots_l; - Mutex _staticRoots_l; + Mutex _roots_l; Mutex _bestRoot_l; };