Browse Source

Simplify root API

Adam Ierymenko 5 years ago
parent
commit
3b3e6d2bfc
8 changed files with 149 additions and 299 deletions
  1. 1 0
      go/pkg/zerotier/api.go
  2. 35 3
      go/pkg/zerotier/node.go
  3. 4 0
      go/pkg/zerotier/root.go
  4. 7 27
      include/ZeroTierCore.h
  5. 29 42
      node/Locator.hpp
  6. 30 71
      node/Node.cpp
  7. 2 4
      node/Node.hpp
  8. 41 152
      node/Topology.hpp

+ 1 - 0
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 req.Method == http.MethodPost || req.Method == http.MethodPut {
 			if queriedID == 0 {
 			if queriedID == 0 {
 				apiSendObj(out, req, http.StatusBadRequest, nil)
 				apiSendObj(out, req, http.StatusBadRequest, nil)
+			} else {
 			}
 			}
 		} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
 		} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
 			roots := node.Roots()
 			roots := node.Roots()

+ 35 - 3
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.Version = [3]int{int(p.versionMajor), int(p.versionMinor), int(p.versionRev)}
 			p2.Latency = int(p.latency)
 			p2.Latency = int(p.latency)
 			p2.Role = int(p.role)
 			p2.Role = int(p.role)
+
 			p2.Paths = make([]Path, 0, int(p.pathCount))
 			p2.Paths = make([]Path, 0, int(p.pathCount))
+			usingAllocation := false
 			for j := uintptr(0); j < uintptr(p.pathCount); j++ {
 			for j := uintptr(0); j < uintptr(p.pathCount); j++ {
 				pt := &p.paths[j]
 				pt := &p.paths[j]
 				if pt.alive != 0 {
 				if pt.alive != 0 {
 					a := sockaddrStorageToUDPAddr(&pt.address)
 					a := sockaddrStorageToUDPAddr(&pt.address)
 					if a != nil {
 					if a != nil {
+						alloc := float32(pt.allocation)
+						if alloc > 0.0 {
+							usingAllocation = true
+						}
 						p2.Paths = append(p2.Paths, Path{
 						p2.Paths = append(p2.Paths, Path{
 							IP:                     a.IP,
 							IP:                     a.IP,
 							Port:                   a.Port,
 							Port:                   a.Port,
@@ -644,18 +650,44 @@ func (n *Node) Peers() []*Peer {
 							Stability:              float32(pt.stability),
 							Stability:              float32(pt.stability),
 							Throughput:             uint64(pt.throughput),
 							Throughput:             uint64(pt.throughput),
 							MaxThroughput:          uint64(pt.maxThroughput),
 							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()
 			p2.Clock = TimeMs()
 			peers = append(peers, p2)
 			peers = append(peers, p2)
 		}
 		}
 		C.ZT_Node_freeQueryResult(unsafe.Pointer(n.zn), unsafe.Pointer(pl))
 		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
 	return peers
 }
 }
 
 

+ 4 - 0
go/pkg/zerotier/root.go

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

+ 7 - 27
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);
 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
  * The node will begin trying to resolve the DNS TXT record for
  * this root and possibly obtain it from other peers.
  * this root and possibly obtain it from other peers.
  *
  *
  * @param node Node instance
  * @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
- * @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
+ * @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
  * @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
  * Remove a dynamic root
  *
  *
  * @param node Node instance
  * @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
  * @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
  * Get this node's 40-bit ZeroTier address

+ 29 - 42
node/Locator.hpp

@@ -26,6 +26,7 @@
 #include <algorithm>
 #include <algorithm>
 #include <vector>
 #include <vector>
 
 
+// These are absolute maximums -- real locators are never this big
 #define ZT_LOCATOR_MAX_PHYSICAL_ADDRESSES 255
 #define ZT_LOCATOR_MAX_PHYSICAL_ADDRESSES 255
 #define ZT_LOCATOR_MAX_VIRTUAL_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
  * may be found. It can contain static physical addresses or virtual ZeroTier
  * addresses of nodes that can forward to the target node. Locator records
  * 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,
  * 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
 class Locator
 {
 {
 public:
 public:
 	ZT_ALWAYS_INLINE Locator() : _ts(0),_signatureLength(0) {}
 	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 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<InetAddress> &phy() const { return _physical; }
 	ZT_ALWAYS_INLINE const std::vector<Identity> &virt() const { return _virtual; }
 	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
 	 * 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;
 		_ts = ts;
 		_id = id;
 		_id = id;
@@ -88,24 +85,10 @@ public:
 		_physical.erase(std::unique(_physical.begin(),_physical.end()),_physical.end());
 		_physical.erase(std::unique(_physical.begin(),_physical.end()),_physical.end());
 		std::sort(_virtual.begin(),_virtual.end());
 		std::sort(_virtual.begin(),_virtual.end());
 		_virtual.erase(std::unique(_virtual.begin(),_virtual.end()),_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 {
 		try {
 			ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
 			ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
 			serialize(*tmp,true);
 			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);
 			return (_signatureLength > 0);
 		} catch ( ... ) {
 		} catch ( ... ) {
 			return false;
 			return false;
@@ -122,8 +105,7 @@ public:
 		try {
 		try {
 			ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
 			ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
 			serialize(*tmp,true);
 			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 ( ... ) {
 		} catch ( ... ) {
 			return false;
 			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
 	 * @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])
 	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>());
 		ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
 		serialize(*tmp,false);
 		serialize(*tmp,false);
 		SHA384(s384,tmp->data(),tmp->size());
 		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);
 		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.
 		// 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.
 		// 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((uint8_t)0); // version/flags, currently 0
 		b.append((uint64_t)_ts);
 		b.append((uint64_t)_ts);
 		_id.serialize(b,false);
 		_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());
 		b.append((uint8_t)_physical.size());
 		for(std::vector<InetAddress>::const_iterator i(_physical.begin());i!=_physical.end();++i)
 		for(std::vector<InetAddress>::const_iterator i(_physical.begin());i!=_physical.end();++i)
 			i->serialize(b);
 			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 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 { return (!(*this == l)); }
 	ZT_ALWAYS_INLINE bool operator<(const Locator &l) const
 	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); }
 	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:
 private:
 	int64_t _ts;
 	int64_t _ts;
 	Identity _id;
 	Identity _id;
-	Identity _signedBy; // signed by _id if nil/zero
 	std::vector<InetAddress> _physical;
 	std::vector<InetAddress> _physical;
 	std::vector<Identity> _virtual;
 	std::vector<Identity> _virtual;
 	unsigned int _signatureLength;
 	unsigned int _signatureLength;

+ 30 - 71
node/Node.cpp

@@ -170,7 +170,9 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
 	if (nw) {
 	if (nw) {
 		RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength);
 		RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength);
 		return ZT_RESULT_OK;
 		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
 // 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 };
 static const ZT_DNSRecordType s_txtRecordType[1] = { ZT_DNS_RECORD_TXT };
 
 
-struct _processBackgroundTasks_check_dynamicRoots
+struct _processBackgroundTasks_eachRootName
 {
 {
 	ZT_Node_Callbacks *cb;
 	ZT_Node_Callbacks *cb;
 	Node *n;
 	Node *n;
@@ -194,7 +196,7 @@ struct _processBackgroundTasks_check_dynamicRoots
 
 
 	ZT_ALWAYS_INLINE bool operator()(const Str &dnsName,const Locator &loc)
 	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);
 			_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);
 			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 {
 		try {
 			// Periodically refresh locators for dynamic roots from their DNS names.
 			// Periodically refresh locators for dynamic roots from their DNS names.
 			if (_cb.dnsResolver) {
 			if (_cb.dnsResolver) {
-				_processBackgroundTasks_check_dynamicRoots cr;
+				_processBackgroundTasks_eachRootName cr;
 				cr.cb = &_cb;
 				cr.cb = &_cb;
 				cr.n = this;
 				cr.n = this;
 				cr.uPtr = _uPtr;
 				cr.uPtr = _uPtr;
@@ -269,7 +271,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
 				} else {
 				} else {
 					cr.updateAll = false;
 					cr.updateAll = false;
 				}
 				}
-				RR->topology->eachDynamicRoot(cr);
+				RR->topology->eachRootName(cr);
 			}
 			}
 
 
 			// Ping each root explicitly no matter what
 			// Ping each root explicitly no matter what
@@ -363,7 +365,7 @@ void Node::processDNSResult(
 		} else if (recordType == ZT_DNS_RECORD__END_OF_RESULTS) {
 		} else if (recordType == ZT_DNS_RECORD__END_OF_RESULTS) {
 			Locator loc;
 			Locator loc;
 			if (loc.decodeTxtRecords(acc->dnsName,acc->txtRecords.begin(),acc->txtRecords.end())) {
 			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;
 				delete acc;
 			}
 			}
 		}
 		}
@@ -434,59 +436,38 @@ ZT_RootList *Node::listRoots(int64_t now)
 	return RR->topology->apiRoots(now);
 	return RR->topology->apiRoots(now);
 }
 }
 
 
-enum ZT_ResultCode Node::setStaticRoot(const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount)
-{
-	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)
+enum ZT_ResultCode Node::setRoot(const char *name,const void *locator,unsigned int locatorSize)
 {
 {
-	if (!dnsName)
-		return ZT_RESULT_ERROR_BAD_PARAMETER;
-	if (strlen(dnsName) >= 256)
-		return ZT_RESULT_ERROR_BAD_PARAMETER;
 	try {
 	try {
 		Locator loc;
 		Locator loc;
-		if ((defaultLocator)&&(defaultLocatorSize > 0)&&(defaultLocatorSize < 65535)) {
+		if ((locator)&&(locatorSize > 0)&&(locatorSize < 65535)) {
 			ScopedPtr< Buffer<65536> > locbuf(new Buffer<65536>());
 			ScopedPtr< Buffer<65536> > locbuf(new Buffer<65536>());
-			locbuf->append(defaultLocator,defaultLocatorSize);
+			locbuf->append(locator,locatorSize);
 			loc.deserialize(*locbuf,0);
 			loc.deserialize(*locbuf,0);
 			if (!loc.verify())
 			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 ( ... ) {
 	} catch ( ... ) {
 		return ZT_RESULT_ERROR_BAD_PARAMETER;
 		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 {
 	try {
-		if (dnsName)
-			RR->topology->removeDynamicRoot(Str(dnsName));
+		if (name)
+			RR->topology->removeRoot(Str(name));
 	} catch ( ... ) {}
 	} catch ( ... ) {}
 	return ZT_RESULT_OK;
 	return ZT_RESULT_OK;
 }
 }
@@ -937,32 +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)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->setStaticRoot(identity,addresses,addressCount);
-	} 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_setDynamicRoot(ZT_Node *node,const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize)
-{
-	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)
+enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize)
 {
 {
 	try {
 	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->removeStaticRoot(identity);
+		return reinterpret_cast<ZeroTier::Node *>(node)->setRoot(name,locator,locatorSize);
 	} catch (std::bad_alloc &exc) {
 	} catch (std::bad_alloc &exc) {
 		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
 		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
 	} catch ( ... ) {
 	} catch ( ... ) {
@@ -970,10 +929,10 @@ enum ZT_ResultCode ZT_Node_removeStaticRoot(ZT_Node *node,const char *identity)
 	}
 	}
 }
 }
 
 
-enum ZT_ResultCode ZT_Node_removeDynamicRoot(ZT_Node *node,const char *dnsName)
+enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name)
 {
 {
 	try {
 	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->removeDynamicRoot(dnsName);
+		return reinterpret_cast<ZeroTier::Node *>(node)->removeRoot(name);
 	} catch (std::bad_alloc &exc) {
 	} catch (std::bad_alloc &exc) {
 		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
 		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
 	} catch ( ... ) {
 	} catch ( ... ) {

+ 2 - 4
node/Node.hpp

@@ -93,10 +93,8 @@ public:
 	ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
 	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_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
 	ZT_RootList *listRoots(int64_t now);
 	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;
 	uint64_t address() const;
 	void status(ZT_NodeStatus *status) const;
 	void status(ZT_NodeStatus *status) const;
 	ZT_PeerList *peers() const;
 	ZT_PeerList *peers() const;

+ 41 - 152
node/Topology.hpp

@@ -66,14 +66,14 @@ private:
 
 
 	ZT_ALWAYS_INLINE void _updateDynamicRootIdentities()
 	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;
 		Str *k = (Str *)0;
 		Locator *v = (Locator *)0;
 		Locator *v = (Locator *)0;
 		while (i.next(k,v)) {
 		while (i.next(k,v)) {
 			if (*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) :
 	ZT_ALWAYS_INLINE Topology(const RuntimeEnvironment *renv,const Identity &myId) :
 		RR(renv),
 		RR(renv),
 		_myIdentity(myId),
 		_myIdentity(myId),
+		_peers(64),
+		_paths(128),
+		_roots(8),
+		_rootIdentities(8),
 		_numConfiguredPhysicalPaths(0),
 		_numConfiguredPhysicalPaths(0),
 		_lastUpdatedBestRoot(0) {}
 		_lastUpdatedBestRoot(0) {}
 	ZT_ALWAYS_INLINE ~Topology() {}
 	ZT_ALWAYS_INLINE ~Topology() {}
@@ -166,17 +170,8 @@ public:
 	 */
 	 */
 	ZT_ALWAYS_INLINE bool isRoot(const Identity &id) const
 	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>
 	template<typename F>
 	ZT_ALWAYS_INLINE void eachRoot(F 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;
 					const SharedPtr<Peer> *ap;
 					{
 					{
 						Mutex::Lock l2(_peers_l);
 						Mutex::Lock l2(_peers_l);
-						ap = _peers.get(k->address());
+						ap = _peers.get(id->address());
 					}
 					}
 					if (ap) {
 					if (ap) {
-						if (!f(*ap,*v))
+						if (!f(*ap,v->phy()))
 							return;
 							return;
 					} else {
 					} else {
-						SharedPtr<Peer> p(new Peer(RR,_myIdentity,*k));
+						SharedPtr<Peer> p(new Peer(RR,_myIdentity,*id));
 						{
 						{
 							Mutex::Lock l2(_peers_l);
 							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;
 							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)
 	 * @param f Function of (Str,Locator)
 	 */
 	 */
 	template<typename F>
 	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;
 		Str *k = (Str *)0;
 		Locator *v = (Locator *)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)) {
 		while (i.next(k,v)) {
 			if (!f(*k,*v))
 			if (!f(*k,*v))
 				break;
 				break;
@@ -389,22 +323,22 @@ public:
 	 *
 	 *
 	 * This does not check signatures or internal validity of the locator.
 	 * 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
 	 * @param latestLocator Latest locator
 	 * @return True if locator is newer or if a new entry was created
 	 * @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) {
 		if (latestLocator) {
-			Locator &ll = _dynamicRoots[dnsName];
+			Locator &ll = _roots[name];
 			if (ll.timestamp() < latestLocator.timestamp()) {
 			if (ll.timestamp() < latestLocator.timestamp()) {
 				ll = latestLocator;
 				ll = latestLocator;
 				_updateDynamicRootIdentities();
 				_updateDynamicRootIdentities();
 				return true;
 				return true;
 			}
 			}
-		} else if (!_dynamicRoots.contains(dnsName)) {
-			_dynamicRoots[dnsName];
+		} else if (!_roots.contains(name)) {
+			_roots[name];
 			return true;
 			return true;
 		}
 		}
 		return false;
 		return false;
@@ -412,39 +346,26 @@ public:
 
 
 	/**
 	/**
 	 * Remove a dynamic root entry
 	 * 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();
 		_updateDynamicRootIdentities();
 	}
 	}
 
 
-	/**
-	 * Remove all dynamic roots
-	 */
-	inline void clearDynamicRoots()
-	{
-		Mutex::Lock l(_dynamicRoots_l);
-		_dynamicRoots.clear();
-		_dynamicRootIdentities.clear();
-	}
-
 	/**
 	/**
 	 * @param Current time
 	 * @param Current time
 	 * @return ZT_RootList as returned by the external CAPI
 	 * @return ZT_RootList as returned by the external CAPI
 	 */
 	 */
 	inline ZT_RootList *apiRoots(const int64_t now) const
 	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
 		// 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
 		// of their DNS names, identities, and up to 16 physical addresses. Most
 		// roots will have two: one V4 and one V6.
 		// 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)));
 		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) {
 		if (!rl) {
 			return nullptr;
 			return nullptr;
@@ -462,7 +383,7 @@ public:
 		{
 		{
 			Str *k = (Str *)0;
 			Str *k = (Str *)0;
 			Locator *v = (Locator *)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)) {
 			while (i.next(k,v)) {
 				rl->roots[c].dnsName = nameBufPtr;
 				rl->roots[c].dnsName = nameBufPtr;
 				const char *p = k->c_str();
 				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;
 		rl->count = c;
 
 
 		return rl;
 		return rl;
@@ -668,18 +560,15 @@ private:
 
 
 	Hashtable< Address,SharedPtr<Peer> > _peers;
 	Hashtable< Address,SharedPtr<Peer> > _peers;
 	Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
 	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;
 	int64_t _lastUpdatedBestRoot;
 	SharedPtr<Peer> _bestRoot;
 	SharedPtr<Peer> _bestRoot;
 
 
 	Mutex _peers_l;
 	Mutex _peers_l;
 	Mutex _paths_l;
 	Mutex _paths_l;
-	Mutex _dynamicRoots_l;
-	Mutex _staticRoots_l;
+	Mutex _roots_l;
 	Mutex _bestRoot_l;
 	Mutex _bestRoot_l;
 };
 };