Browse Source

Work in progress...

Adam Ierymenko 6 years ago
parent
commit
b66431bc29
15 changed files with 355 additions and 389 deletions
  1. 134 28
      LICENSE.txt
  2. 0 5
      node/Constants.hpp
  3. 3 0
      node/Hashtable.hpp
  4. 3 0
      node/Membership.cpp
  5. 24 31
      node/Network.cpp
  6. 17 38
      node/Network.hpp
  7. 90 84
      node/Node.cpp
  8. 13 13
      node/Node.hpp
  9. 1 11
      node/Peer.hpp
  10. 3 3
      node/SHA512.cpp
  11. 4 0
      node/SHA512.hpp
  12. 1 1
      node/SelfAwareness.cpp
  13. 3 6
      node/Topology.hpp
  14. 58 156
      node/Trace.cpp
  15. 1 13
      node/Trace.hpp

+ 134 - 28
LICENSE.txt

@@ -1,37 +1,143 @@
-ZeroTier One - Network Virtualization Everywhere
-Copyright (C) 2011-2019  ZeroTier, Inc.  https://www.zerotier.com/
+Business Source License 1.1
 
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
+"Business Source License" is a trademark of MariaDB Corporation Ab.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+-----------------------------------------------------------------------------
 
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
+Parameters
 
-See LICENSE.GPL-3 for the full GNU GPL v3 license.
+Licensor:             ZeroTier, Inc.
+Licensed Work:        ZeroTier Network Virtualization Engine 2.0
+                      The Licensed Work is (c)2019 ZeroTier, Inc.
+Additional Use Grant: You may make use of the Licensed Work, provided you
+                      do not use it in any of the following ways:
 
---
+                      * Sell hosted ZeroTier services as a "SaaS" Product
 
-You can be released from the requirements of the license by purchasing
-a commercial license. Buying such a license is mandatory as soon as you
-develop commercial closed-source software that incorporates or links
-directly against ZeroTier software without disclosing the source code
-of your own application.
+                      (1) Operate or sell access to ZeroTier root servers,
+                      network controllers, or authorization key or certificate
+                      generation components of the Licensed Work as a
+                      for-profit service, regardless of whether the use of
+                      these components is sold alone or is bundled with other
+                      services.
 
---
+                      * Create Non-Open-Source Commercial Derviative Works
 
-The above license does not apply to third party code included with or
-linked against by ZeroTier software. See the third party code section
-of the AUTHORS.md for an index of third party software included in
-this software repository.
+                      (2) Link or directly include the Licensed Work in a
+                      commercial or for-profit application or other product
+                      not distributed under an Open Source Initiative (OSI)
+                      compliant license. See: https://opensource.org/licenses
 
-Licenses for third party code are all relatively permissive: MIT,
-BSD, and public domain. The only exception is the tap-windows driver
-which is under the GPLv2, but this is only needed to produce the
-binary tap device driver used by the ZeroTier service on Windows.
+                      (3) Remove the name, logo, copyright, or other branding
+                      material from the Licensed Work to create a "rebranded"
+                      or "white labeled" version to distribute as part of
+                      any commercial or for-profit product or service.
+
+                      * Certain Government Uses
+
+                      (4) Use or deploy the Licensed Work in a government
+                      setting in support of any active government function
+                      or operation with the exception of the following:
+                      physical or mental health care, family and social
+                      services, social welfare, senior care, child care, and
+                      the care of persons with disabilities.
+
+Change Date:          2023-01-01
+
+Change License:       Apache License version 2.0 as published by the Apache
+                      Software Foundation
+											https://www.apache.org/licenses/
+
+Alternative Licensing
+
+If you would like to use the Licensed Work in any way that conflicts with
+the stipulations of the Additional Use Grant, contact ZeroTier, Inc. to
+obtain an alternative commercial license.
+
+Visit us on the web at: https://www.zerotier.com/
+
+Notice
+
+The Business Source License (this document, or the "License") is not an Open
+Source license. However, the Licensed Work will eventually be made available
+under an Open Source License, as stated in this License.
+
+For more information on the use of the Business Source License for ZeroTier
+products, please visit the ZeroTier Business Source License FAQ at
+https://zerotier.com/bsl-license.
+
+For more information on the use of the Business Source License generally,
+please visit the Adopting and Developing Business Source License FAQ at
+https://mariadb.com/bsl-faq-adopting.
+
+-----------------------------------------------------------------------------
+
+Business Source License 1.1
+
+Terms
+
+The Licensor hereby grants you the right to copy, modify, create derivative
+works, redistribute, and make non-production use of the Licensed Work. The
+Licensor may make an Additional Use Grant, above, permitting limited
+production use.
+
+Effective on the Change Date, or the fourth anniversary of the first publicly
+available distribution of a specific version of the Licensed Work under this
+License, whichever comes first, the Licensor hereby grants you rights under
+the terms of the Change License, and the rights granted in the paragraph
+above terminate.
+
+If your use of the Licensed Work does not comply with the requirements
+currently in effect as described in this License, you must purchase a
+commercial license from the Licensor, its affiliated entities, or authorized
+resellers, or you must refrain from using the Licensed Work.
+
+All copies of the original and modified Licensed Work, and derivative works
+of the Licensed Work, are subject to this License. This License applies
+separately for each version of the Licensed Work and the Change Date may vary
+for each version of the Licensed Work released by Licensor.
+
+You must conspicuously display this License on each original or modified copy
+of the Licensed Work. If you receive the Licensed Work in original or
+modified form from a third party, the terms and conditions set forth in this
+License apply to your use of that work.
+
+Any use of the Licensed Work in violation of this License will automatically
+terminate your rights under this License for the current and all other
+versions of the Licensed Work.
+
+This License does not grant you any right in any trademark or logo of
+Licensor or its affiliates (provided that you may use a trademark or logo of
+Licensor as expressly required by this License).
+
+TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
+AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
+EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
+TITLE.
+
+MariaDB hereby grants you permission to use this License’s text to license
+your works, and to refer to it using the trademark "Business Source License",
+as long as you comply with the Covenants of Licensor below.
+
+Covenants of Licensor
+
+In consideration of the right to use this License’s text and the "Business
+Source License" name and trademark, Licensor covenants to MariaDB, and to all
+other recipients of the licensed work to be provided by Licensor:
+
+1. To specify as the Change License the GPL Version 2.0 or any later version,
+   or a license that is compatible with GPL Version 2.0 or a later version,
+   where "compatible" means that software provided under the Change License can
+   be included in a program with software provided under GPL Version 2.0 or a
+   later version. Licensor may specify additional Change Licenses without
+   limitation.
+
+2. To either: (a) specify an additional grant of rights to use that does not
+   impose any additional restriction on the right granted in this License, as
+   the Additional Use Grant; or (b) insert the text "None".
+
+3. To specify a Change Date.
+
+4. Not to modify this License in any other way.

+ 0 - 5
node/Constants.hpp

@@ -270,11 +270,6 @@
  */
 #define ZT_MULTICAST_TRANSMIT_TIMEOUT 5000
 
-/**
- * Delay between checks of peer pings, etc., and also related housekeeping tasks
- */
-#define ZT_PING_CHECK_INVERVAL 5000
-
 /**
  * How frequently to check for changes to the system's network interfaces. When
  * the service decides to use this constant it's because we want to react more

+ 3 - 0
node/Hashtable.hpp

@@ -384,10 +384,13 @@ public:
 private:
 	template<typename O>
 	static inline unsigned long _hc(const O &obj) { return (unsigned long)obj.hashCode(); }
+
 	static inline unsigned long _hc(const uint64_t i) { return (unsigned long)(i ^ (i >> 32)); }
 	static inline unsigned long _hc(const uint32_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
 	static inline unsigned long _hc(const uint16_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
 	static inline unsigned long _hc(const int i) { return ((unsigned long)i * (unsigned long)0x9e3379b1); }
+	static inline unsigned long _hc(void *p) { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
+	static inline unsigned long _hc(const void *p) { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
 
 	inline void _grow()
 	{

+ 3 - 0
node/Membership.cpp

@@ -132,6 +132,9 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
 		return ADD_ACCEPTED_REDUNDANT;
 
 	switch(com.verify(RR,tPtr)) {
+		default:
+			RR->t->credentialRejected(tPtr,com,"invalid");
+			return Membership::ADD_REJECTED;
 		case Credential::VERIFY_OK:
 			_com = com;
 			return ADD_ACCEPTED_NEW;

+ 24 - 31
node/Network.cpp

@@ -556,7 +556,6 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u
 	RR(renv),
 	_uPtr(uptr),
 	_id(nwid),
-	_lastAnnouncedMulticastGroupsUpstream(0),
 	_mac(renv->identity.address(),nwid),
 	_portInitialized(false),
 	_lastConfigUpdate(0),
@@ -1006,7 +1005,7 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
 		ZT_VirtualNetworkConfig ctmp;
 		bool oldPortInitialized;
 		{	// do things that require lock here, but unlock before calling callbacks
-			Mutex::Lock _l(_config_l);
+			Mutex::Lock l1(_config_l);
 
 			_config = nconf;
 			_lastConfigUpdate = RR->node->now();
@@ -1237,30 +1236,14 @@ bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer)
 	return false;
 }
 
-bool Network::recentlyAssociatedWith(const Address &addr)
-{
-	Mutex::Lock _l(_memberships_l);
-	const Membership *m = _memberships.get(addr);
-	return ((m)&&(m->recentlyAssociated(RR->node->now())));
-}
-
-void Network::clean()
+void Network::doPeriodicTasks(void *tPtr)
 {
 	const int64_t now = RR->node->now();
-	Mutex::Lock _l(_memberships_l);
+	Mutex::Lock l1(_memberships_l);
 
 	if (_destroyed)
 		return;
 
-	{
-		Hashtable< MulticastGroup,uint64_t >::Iterator i(_multicastGroupsBehindMe);
-		MulticastGroup *mg = (MulticastGroup *)0;
-		uint64_t *ts = (uint64_t *)0;
-		while (i.next(mg,ts)) {
-			if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2))
-				_multicastGroupsBehindMe.erase(*mg);
-		}
-	}
 	{
 		Address *a = (Address *)0;
 		Membership *m = (Membership *)0;
@@ -1269,14 +1252,20 @@ void Network::clean()
 			m->clean(now,_config);
 		}
 	}
-}
 
-Membership::AddCredentialResult Network::addCredential(void *tPtr,const CertificateOfMembership &com)
-{
-	if (com.networkId() != _id)
-		return Membership::ADD_REJECTED;
-	Mutex::Lock _l(_memberships_l);
-	return _memberships[com.issuedTo()].addCredential(RR,tPtr,_config,com);
+	{
+		Mutex::Lock l2(_myMulticastGroups_l);
+
+		Hashtable< MulticastGroup,uint64_t >::Iterator i(_multicastGroupsBehindMe);
+		MulticastGroup *mg = (MulticastGroup *)0;
+		uint64_t *ts = (uint64_t *)0;
+		while (i.next(mg,ts)) {
+			if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2))
+				_multicastGroupsBehindMe.erase(*mg);
+		}
+
+		_announceMulticastGroups(tPtr,false);
+	}
 }
 
 Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev)
@@ -1284,7 +1273,7 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address
 	if (rev.networkId() != _id)
 		return Membership::ADD_REJECTED;
 
-	Mutex::Lock _l(_memberships_l);
+	Mutex::Lock l1(_memberships_l);
 	Membership &m = _memberships[rev.target()];
 
 	const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,rev);
@@ -1371,9 +1360,10 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
 	}
 }
 
-void Network::_announceMulticastGroups(void *tPtr)
+void Network::_announceMulticastGroups(void *tPtr,bool force)
 {
 	// Assumes _myMulticastGroups_l and _memberships_l are locked
+	const int64_t now = RR->node->now();
 	const std::vector<MulticastGroup> groups(_allMulticastGroups());
 	_announceMulticastGroupsTo(tPtr,controller(),groups);
 	{
@@ -1381,7 +1371,10 @@ void Network::_announceMulticastGroups(void *tPtr)
 		Membership *m = (Membership *)0;
 		Hashtable<Address,Membership>::Iterator i(_memberships);
 		while (i.next(a,m)) {
-			if (m->isAllowedOnNetwork(_config))
+			bool announce = m->multicastLikeGate(now); // force this to be called even if 'force' is true since it updates last push time
+			if ((!announce)&&(force))
+				announce = true;
+			if ((announce)&&(m->isAllowedOnNetwork(_config)))
 				_announceMulticastGroupsTo(tPtr,*a,groups);
 		}
 	}
@@ -1415,7 +1408,7 @@ void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const st
 
 std::vector<MulticastGroup> Network::_allMulticastGroups() const
 {
-	// Assumes _lock is locked
+	// Assumes _myMulticastGroups_l is locked
 	std::vector<MulticastGroup> mgs;
 	mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1);
 	mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end());

+ 17 - 38
node/Network.hpp

@@ -172,9 +172,9 @@ public:
 	 * @param includeBridgedGroups If true, also check groups we've learned via bridging
 	 * @return True if this network endpoint / peer is a member
 	 */
-	inline bool subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const
+	inline bool subscribedToMulticastGroup(const MulticastGroup &mg,const bool includeBridgedGroups) const
 	{
-		Mutex::Lock _l(_myMulticastGroups_l);
+		Mutex::Lock l(_myMulticastGroups_l);
 		if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
 			return true;
 		else if (includeBridgedGroups)
@@ -190,11 +190,11 @@ public:
 	 */
 	inline void multicastSubscribe(void *tPtr,const MulticastGroup &mg)
 	{
-		Mutex::Lock _l(_myMulticastGroups_l);
+		Mutex::Lock l(_myMulticastGroups_l);
 		if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
 			_myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg);
 			Mutex::Lock l2(_memberships_l);
-			_announceMulticastGroups(tPtr);
+			_announceMulticastGroups(tPtr,true);
 		}
 	}
 
@@ -205,7 +205,7 @@ public:
 	 */
 	inline void multicastUnsubscribe(const MulticastGroup &mg)
 	{
-		Mutex::Lock _l(_myMulticastGroups_l);
+		Mutex::Lock l(_myMulticastGroups_l);
 		std::vector<MulticastGroup>::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg));
 		if ( (i != _myMulticastGroups.end()) && (*i == mg) )
 			_myMulticastGroups.erase(i);
@@ -262,35 +262,10 @@ public:
 	 */
 	bool gate(void *tPtr,const SharedPtr<Peer> &peer);
 
-	/**
-	 * Check whether a given peer has recently had an association with this network
-	 *
-	 * This checks whether a peer has communicated with us recently about this
-	 * network and has possessed a valid certificate of membership. This may return
-	 * true even if the peer has been offline for a while or no longer has a valid
-	 * certificate of membership but had one recently.
-	 *
-	 * @param addr Peer address
-	 * @return True if peer has recently associated
-	 */
-	bool recentlyAssociatedWith(const Address &addr);
-
 	/**
 	 * Do periodic cleanup and housekeeping tasks
 	 */
-	void clean();
-
-	/**
-	 * Push state to members such as multicast group memberships and latest COM (if needed)
-	 *
-	 * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
-	 */
-	inline void sendUpdatesToMembers(void *tPtr)
-	{
-		Mutex::Lock _l(_myMulticastGroups_l);
-		Mutex::Lock _l2(_memberships_l);
-		_announceMulticastGroups(tPtr);
-	}
+	void doPeriodicTasks(void *tPtr);
 
 	/**
 	 * Find the node on this network that has this MAC behind it (if any)
@@ -362,14 +337,20 @@ public:
 	 */
 	inline void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now)
 	{
-		Mutex::Lock _l(_multicastGroupsBehindMe_l);
+		Mutex::Lock l(_myMulticastGroups_l);
 		_multicastGroupsBehindMe.set(mg,now);
 	}
 
 	/**
 	 * Validate a credential and learn it if it passes certificate and other checks
 	 */
-	Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com);
+	Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com)
+	{
+		if (com.networkId() != _id)
+			return Membership::ADD_REJECTED;
+		Mutex::Lock _l(_memberships_l);
+		return _memberships[com.issuedTo()].addCredential(RR,tPtr,_config,com);
+	}
 
 	/**
 	 * Validate a credential and learn it if it passes certificate and other checks
@@ -423,7 +404,7 @@ public:
 	}
 
 	/**
-	 * Push credentials if we haven't done so in a very long time
+	 * Push credentials if we haven't done so in a long time
 	 *
 	 * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
 	 * @param to Destination peer address
@@ -473,14 +454,13 @@ private:
 	ZT_VirtualNetworkStatus _status() const;
 	void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
 	bool _gate(const SharedPtr<Peer> &peer);
-	void _announceMulticastGroups(void *tPtr);
+	void _announceMulticastGroups(void *tPtr,bool force);
 	void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
 	std::vector<MulticastGroup> _allMulticastGroups() const;
 
 	const RuntimeEnvironment *const RR;
 	void *_uPtr;
 	const uint64_t _id;
-	uint64_t _lastAnnouncedMulticastGroupsUpstream;
 	MAC _mac; // local MAC address
 	bool _portInitialized;
 
@@ -493,7 +473,7 @@ private:
 
 	struct _IncomingConfigChunk
 	{
-		_IncomingConfigChunk() { memset(this,0,sizeof(_IncomingConfigChunk)); }
+		_IncomingConfigChunk() : ts(0),updateId(0),haveChunks(0),haveBytes(0),data() {}
 		uint64_t ts;
 		uint64_t updateId;
 		uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS];
@@ -516,7 +496,6 @@ private:
 	Hashtable<Address,Membership> _memberships;
 
 	Mutex _myMulticastGroups_l;
-	Mutex _multicastGroupsBehindMe_l;
 	Mutex _remoteBridgeRoutes_l;
 	Mutex _config_l;
 	Mutex _memberships_l;

+ 90 - 84
node/Node.cpp

@@ -58,7 +58,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
 	_uPtr(uptr),
 	_networks(8),
 	_now(now),
-	_lastPingCheck(0),
+	_lastPing(0),
 	_lastHousekeepingRun(0),
 	_lastMemoizedTraceSettings(0)
 {
@@ -184,101 +184,91 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
 	} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
 }
 
-/*
-// Function object used to traverse the peer list, check peer status, and ping
-// those that need pinging.
-struct _PingPeersThatNeedPing
-{
-	inline _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector<InetAddress> > &alwaysContact,int64_t now) :
-		RR(renv),
-		_tPtr(tPtr),
-		_alwaysContact(alwaysContact),
-		_now(now),
-		_bestCurrentUpstream(RR->topology->getUpstreamPeer()),
-		online(false)
-	{
-	}
+struct _processBackgroundTasks_ping_eachRoot
+{
+	Hashtable< void *,bool > roots;
+	int64_t now;
+	void *tPtr;
+	bool online;
 
-	inline void operator()(Topology &t,const SharedPtr<Peer> &p)
+	inline void operator()(const Root &root,const SharedPtr<Peer> &peer)
 	{
-		const std::vector<InetAddress> *const alwaysContactEndpoints = _alwaysContact.get(p->address());
-		if (alwaysContactEndpoints) {
-			online |= p->isAlive(_now);
-			const unsigned int sent = p->doPingAndKeepalive(_tPtr,_now);
-			bool contacted = (sent != 0);
-
-			if ((sent & 0x1) == 0) { // bit 0x1 == IPv4 sent
-				for(unsigned long k=0,ptr=(unsigned long)Utils::random();k<(unsigned long)alwaysContactEndpoints->size();++k) {
-					const InetAddress &addr = (*alwaysContactEndpoints)[ptr++ % alwaysContactEndpoints->size()];
-					if (addr.ss_family == AF_INET) {
-						p->sendHELLO(_tPtr,-1,addr,_now);
-						contacted = true;
-						break;
-					}
-				}
-			}
+		unsigned int v4SendCount = 0,v6SendCount = 0;
+		peer->ping(tPtr,now,v4SendCount,v6SendCount);
+
+		const InetAddress *contactAddrs[2];
+		unsigned int contactAddrCount = 0;
+		if (v4SendCount == 0) {
+			if (*(contactAddrs[contactAddrCount] = &(root.pickPhysical(AF_INET))))
+				++contactAddrCount;
+		}
+		if (v6SendCount == 0) {
+			if (*(contactAddrs[contactAddrCount] = &(root.pickPhysical(AF_INET6))))
+				++contactAddrCount;
+		}
 
-			if ((sent & 0x2) == 0) { // bit 0x2 == IPv6 sent
-				for(unsigned long k=0,ptr=(unsigned long)Utils::random();k<(unsigned long)alwaysContactEndpoints->size();++k) {
-					const InetAddress &addr = (*alwaysContactEndpoints)[ptr++ % alwaysContactEndpoints->size()];
-					if (addr.ss_family == AF_INET6) {
-						p->sendHELLO(_tPtr,-1,addr,_now);
-						contacted = true;
-						break;
-					}
-				}
-			}
+		for(unsigned int i=0;i<contactAddrCount;++i)
+			peer->sendHELLO(tPtr,-1,*contactAddrs[i],now);
 
-			if ((!contacted)&&(_bestCurrentUpstream)) {
-				const SharedPtr<Path> up(_bestCurrentUpstream->getAppropriatePath(_now,true));
-				if (up)
-					p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now);
-			}
+		if (!online)
+			online = ((now - peer->lastReceive()) <= ((ZT_PEER_PING_PERIOD * 2) + 5000));
 
-			_alwaysContact.erase(p->address()); // after this we'll WHOIS all upstreams that remain
-		} else if (p->isActive(_now)) {
-			p->doPingAndKeepalive(_tPtr,_now);
-		}
+		roots.set((void *)peer.ptr(),true);
 	}
+};
 
-	const RuntimeEnvironment *RR;
-	void *_tPtr;
-	Hashtable< Address,std::vector<InetAddress> > &_alwaysContact;
-	const int64_t _now;
-	const SharedPtr<Peer> _bestCurrentUpstream;
+struct _processBackgroundTasks_ping_eachPeer
+{
+	int64_t now;
+	void *tPtr;
+	Hashtable< void *,bool > *roots;
 
-	bool online;
+	inline void operator()(const SharedPtr<Peer> &peer)
+	{
+		if (!roots->contains((void *)peer.ptr())) {
+			unsigned int v4SendCount = 0,v6SendCount = 0;
+			peer->ping(tPtr,now,v4SendCount,v6SendCount);
+		}
+	}
 };
-*/
 
 ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
 {
 	_now = now;
 	Mutex::Lock bl(_backgroundTasksLock);
 
-	unsigned long timeUntilNextPingCheck = ZT_PING_CHECK_INVERVAL;
-	const int64_t timeSinceLastPingCheck = now - _lastPingCheck;
+	unsigned long timeUntilNextPing = ZT_PEER_PING_PERIOD;
+	const int64_t timeSinceLastPing = now - _lastPing;
+
+	if (timeSinceLastPing >= ZT_PEER_PING_PERIOD) {
+		_lastPing = now;
+		try {
+			_processBackgroundTasks_ping_eachRoot rf;
+			rf.now = now;
+			rf.tPtr = tptr;
+			rf.online = false;
+			RR->topology->eachRoot(rf);
+
+			_processBackgroundTasks_ping_eachPeer pf;
+			pf.now = now;
+			pf.tPtr = tptr;
+			pf.roots = &rf.roots;
+			RR->topology->eachPeer(pf);
+
+			if (rf.online != _online) {
+				_online = rf.online;
+				postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
+			}
+		} catch ( ... ) {
+			return ZT_RESULT_FATAL_ERROR_INTERNAL;
+		}
+	}
+
+	/*
 	if (timeSinceLastPingCheck >= ZT_PING_CHECK_INVERVAL) {
 		try {
 			_lastPingCheck = now;
 
-			// Clean up any old local controller auth memoizations. This is an
-			// optimization for network controllers to know whether to accept
-			// or trust nodes without doing an extra cert check.
-			{
-				_localControllerAuthorizations_m.lock();
-				Hashtable< _LocalControllerAuth,int64_t >::Iterator i(_localControllerAuthorizations);
-				_LocalControllerAuth *k = (_LocalControllerAuth *)0;
-				int64_t *v = (int64_t *)0;
-				while (i.next(k,v)) {
-					if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3)) {
-						_localControllerAuthorizations.erase(*k);
-					}
-				}
-				_localControllerAuthorizations_m.unlock();
-			}
-
-/*
 			// (1) Get peers we should remain connected to and (2) get networks that need config.
 			Hashtable< Address,std::vector<InetAddress> > alwaysContact;
 			RR->topology->getAlwaysContact(alwaysContact);
@@ -319,13 +309,13 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
 			_online = pfunc.online;
 			if (oldOnline != _online)
 				postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
-*/
 		} catch ( ... ) {
 			return ZT_RESULT_FATAL_ERROR_INTERNAL;
 		}
 	} else {
 		timeUntilNextPingCheck -= (unsigned long)timeSinceLastPingCheck;
 	}
+*/
 
 	if ((now - _lastMemoizedTraceSettings) >= (ZT_HOUSEKEEPING_PERIOD / 4)) {
 		_lastMemoizedTraceSettings = now;
@@ -335,6 +325,22 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
 	if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) {
 		_lastHousekeepingRun = now;
 		try {
+			// Clean up any old local controller auth memoizations. This is an
+			// optimization for network controllers to know whether to accept
+			// or trust nodes without doing an extra cert check.
+			{
+				_localControllerAuthorizations_m.lock();
+				Hashtable< _LocalControllerAuth,int64_t >::Iterator i(_localControllerAuthorizations);
+				_LocalControllerAuth *k = (_LocalControllerAuth *)0;
+				int64_t *v = (int64_t *)0;
+				while (i.next(k,v)) {
+					if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3)) {
+						_localControllerAuthorizations.erase(*k);
+					}
+				}
+				_localControllerAuthorizations_m.unlock();
+			}
+
 			RR->topology->doPeriodicTasks(now);
 			RR->sa->clean(now);
 			RR->mc->clean(now);
@@ -344,7 +350,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
 	}
 
 	try {
-		*nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY);
+		*nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min(timeUntilNextPing,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY);
 	} catch ( ... ) {
 		return ZT_RESULT_FATAL_ERROR_INTERNAL;
 	}
@@ -527,9 +533,9 @@ void Node::freeQueryResult(void *qr)
 int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr)
 {
 	if (Path::isAddressValidForPath(*(reinterpret_cast<const InetAddress *>(addr)))) {
-		Mutex::Lock _l(_directPaths_m);
-		if (std::find(_directPaths.begin(),_directPaths.end(),*(reinterpret_cast<const InetAddress *>(addr))) == _directPaths.end()) {
-			_directPaths.push_back(*(reinterpret_cast<const InetAddress *>(addr)));
+		Mutex::Lock _l(_localInterfaceAddresses_m);
+		if (std::find(_localInterfaceAddresses.begin(),_localInterfaceAddresses.end(),*(reinterpret_cast<const InetAddress *>(addr))) == _localInterfaceAddresses.end()) {
+			_localInterfaceAddresses.push_back(*(reinterpret_cast<const InetAddress *>(addr)));
 			return 1;
 		}
 	}
@@ -538,8 +544,8 @@ int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr)
 
 void Node::clearLocalInterfaceAddresses()
 {
-	Mutex::Lock _l(_directPaths_m);
-	_directPaths.clear();
+	Mutex::Lock _l(_localInterfaceAddresses_m);
+	_localInterfaceAddresses.clear();
 }
 
 int Node::sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len)

+ 13 - 13
node/Node.hpp

@@ -170,8 +170,8 @@ public:
 
 	inline std::vector<InetAddress> directPaths() const
 	{
-		Mutex::Lock _l(_directPaths_m);
-		return _directPaths;
+		Mutex::Lock _l(_localInterfaceAddresses_m);
+		return _localInterfaceAddresses;
 	}
 
 	inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ev,md); }
@@ -249,9 +249,6 @@ public:
 	virtual void ncSendRevocation(const Address &destination,const Revocation &rev);
 	virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode);
 
-	inline const Address &remoteTraceTarget() const { return _remoteTraceTarget; }
-	inline Trace::Level remoteTraceLevel() const { return _remoteTraceLevel; }
-
 	inline void setMultipathMode(uint8_t mode) { _multipathMode = mode; }
 	inline uint8_t getMultipathMode() { return _multipathMode; }
 
@@ -278,8 +275,11 @@ private:
 	// Time of last identity verification indexed by InetAddress.rateGateHash() -- used in IncomingPacket::_doHELLO() via rateGateIdentityVerification()
 	int64_t _lastIdentityVerification[16384];
 
-	// Map that remembers if we have recently sent a network config to someone
-	// querying us as a controller.
+	/* Map that remembers if we have recently sent a network config to someone
+	 * querying us as a controller. This is an optimization to allow network
+	 * controllers to know whether to treat things like multicast queries the
+	 * way authorized members would be treated without requiring an extra cert
+	 * validation. */
 	struct _LocalControllerAuth
 	{
 		uint64_t nwid,address;
@@ -291,21 +291,21 @@ private:
 	Hashtable< _LocalControllerAuth,int64_t > _localControllerAuthorizations;
 	Mutex _localControllerAuthorizations_m;
 
+	// Curreently joined networks
 	Hashtable< uint64_t,SharedPtr<Network> > _networks;
 	Mutex _networks_m;
 
-	std::vector<InetAddress> _directPaths;
-	Mutex _directPaths_m;
+	// Local interface addresses as reported by the code harnessing this Node
+	std::vector<InetAddress> _localInterfaceAddresses;
+	Mutex _localInterfaceAddresses_m;
 
+	// Lock to ensure processBackgroundTasks never gets run concurrently
 	Mutex _backgroundTasksLock;
 
-	Address _remoteTraceTarget;
-	enum Trace::Level _remoteTraceLevel;
-
 	uint8_t _multipathMode;
 
 	volatile int64_t _now;
-	int64_t _lastPingCheck;
+	int64_t _lastPing;
 	int64_t _lastHousekeepingRun;
 	int64_t _lastMemoizedTraceSettings;
 	bool _online;

+ 1 - 11
node/Peer.hpp

@@ -256,16 +256,6 @@ public:
 	 */
 	void ping(void *tPtr,int64_t now,unsigned int &v4SendCount,unsigned int &v6SendCount);
 
-	/**
-	 * Clear paths whose localSocket(s) are in a CLOSED state or have an otherwise INVALID state.
-	 * This should be called frequently so that we can detect and remove unproductive or invalid paths.
-	 *
-	 * Under the hood this is done periodically based on ZT_CLOSED_PATH_PRUNING_INTERVAL.
-	 *
-	 * @return Number of paths that were pruned this round
-	 */
-	unsigned int prunePaths();
-
 	/**
 	 * Reset paths within a given IP scope and address family
 	 *
@@ -304,7 +294,7 @@ public:
 	/**
 	 * @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT
 	 */
-	inline bool isAlive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
+	inline bool alive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
 
 	/**
 	 * @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths

+ 3 - 3
node/SHA512.cpp

@@ -49,7 +49,7 @@ typedef struct sha512_ctx_tag {
 	uint64_t len[2];
 	uint64_t val[8];
 	uint8_t *payload_addr;
-	uint64_t payload_len;
+	unsigned long payload_len;
 } sha512_ctx_t;
 
 #define LSR(x,n) (x >> n)
@@ -103,7 +103,7 @@ static inline void sha512_memclr(uint8_t *dst, uint32_t size)
 	for (;i < size;i++) { *dst++ = 0; }
 }
 
-static inline void sha512_init_512(sha512_ctx_t *sha512_ctx, uint8_t *payload_addr, uint64_t payload_len)
+static inline void sha512_init_512(sha512_ctx_t *sha512_ctx, uint8_t *payload_addr, unsigned long payload_len)
 {
 	sha512_memclr((uint8_t *)sha512_ctx,sizeof(sha512_ctx_t));
 	sha512_ctx->val[0] = 0x6A09E667F3BCC908ULL;
@@ -121,7 +121,7 @@ static inline void sha512_init_512(sha512_ctx_t *sha512_ctx, uint8_t *payload_ad
 	sha512_ctx->len[1] = payload_len >> 61;
 }
 
-static inline void sha512_init_384(sha512_ctx_t *sha512_ctx, uint8_t *payload_addr, uint64_t payload_len)
+static inline void sha512_init_384(sha512_ctx_t *sha512_ctx, uint8_t *payload_addr, unsigned long payload_len)
 {
 	sha512_memclr((uint8_t *)sha512_ctx,sizeof(sha512_ctx_t));
 	sha512_ctx->val[0] = 0xCBBB9D5DC1059ED8ULL;

+ 4 - 0
node/SHA512.hpp

@@ -42,6 +42,8 @@
 
 namespace ZeroTier {
 
+#if 0
+
 #ifdef __APPLE__
 #define ZT_HAVE_NATIVE_SHA512 1
 static inline void SHA512(void *digest,const void *data,unsigned int len)
@@ -78,6 +80,8 @@ static inline void SHA384(void *digest,const void *data,unsigned int len)
 }
 #endif
 
+#endif
+
 #ifndef ZT_HAVE_NATIVE_SHA512
 void SHA512(void *digest,const void *data,unsigned int len);
 void SHA384(void *digest,const void *data,unsigned int len);

+ 1 - 1
node/SelfAwareness.cpp

@@ -55,7 +55,7 @@ public:
 		_family(inetAddressFamily),
 		_scope(scope) {}
 
-	inline void operator()(Topology &t,const SharedPtr<Peer> &p) { p->resetWithinScope(_tPtr,_scope,_family,_now); }
+	inline void operator()(const SharedPtr<Peer> &p) { p->resetWithinScope(_tPtr,_scope,_family,_now); }
 
 private:
 	uint64_t _now;

+ 3 - 6
node/Topology.hpp

@@ -177,7 +177,7 @@ public:
 			Address *a = (Address *)0;
 			SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
 			while (i.next(a,p)) {
-				if (!(*p)->isAlive(now)) {
+				if (!(*p)->alive(now)) {
 					_peers.erase(*a);
 				}
 			}
@@ -230,16 +230,13 @@ public:
 		Address *a = (Address *)0;
 		SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
 		while (i.next(a,p)) {
-			f(*this,*((const SharedPtr<Peer> *)p));
+			f(*((const SharedPtr<Peer> *)p));
 		}
 	}
 
 	/**
 	 * Apply a function or function object to all roots
 	 *
-	 * Arguments to the function are this topology object, the root in
-	 * question, and a pointer to the peer corresponding to it.
-	 *
 	 * This locks the root list during execution but other operations
 	 * are fine.
 	 *
@@ -262,7 +259,7 @@ public:
 					_peers.set(rp->address(),rp);
 				}
 			}
-			f(*this,*i,rp);
+			f(*i,rp);
 		}
 	}
 

+ 58 - 156
node/Trace.cpp

@@ -47,7 +47,7 @@ namespace ZeroTier {
 #ifdef ZT_TRACE
 static void ZT_LOCAL_TRACE(void *const tPtr,const RuntimeEnvironment *const RR,const char *const fmt,...)
 {
-	char traceMsgBuf[1024];
+	char traceMsgBuf[2048];
 	va_list ap;
 	va_start(ap,fmt);
 	vsnprintf(traceMsgBuf,sizeof(traceMsgBuf),fmt,ap);
@@ -61,20 +61,10 @@ static void ZT_LOCAL_TRACE(void *const tPtr,const RuntimeEnvironment *const RR,c
 
 void Trace::resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope)
 {
+#ifdef ZT_TRACE
 	char tmp[128];
-
 	ZT_LOCAL_TRACE(tPtr,RR,"RESET and revalidate paths in scope %d; new phy address %s reported by trusted peer %.10llx",(int)scope,myPhysicalAddress.toIpString(tmp),reporter.toInt());
-
-	Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
-	d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S);
-	d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,reporter);
-	d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,reporterPhysicalAddress.toString(tmp));
-	d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR,myPhysicalAddress.toString(tmp));
-	d.add(ZT_REMOTE_TRACE_FIELD__IP_SCOPE,(uint64_t)scope);
-
-	if (_globalTarget)
-		_send(tPtr,d,_globalTarget);
-	_spamToAllNetworks(tPtr,d,Trace::LEVEL_NORMAL);
+#endif
 }
 
 void Trace::peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &path,const uint64_t packetId,const Packet::Verb verb)
@@ -87,7 +77,7 @@ void Trace::peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,
 	std::pair<Address,Trace::Level> byn;
 	if (networkId) { Mutex::Lock l(_byNet_m); _byNet.get(networkId,byn); }
 
-	if ((_globalTarget)||(byn.first)) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_NORMAL)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
@@ -99,11 +89,7 @@ void Trace::peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,
 			d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
 			d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
 		}
-
-		if (_globalTarget)
-			_send(tPtr,d,_globalTarget);
-		if (byn.first)
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -137,7 +123,7 @@ void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &p
 	std::pair<Address,Trace::Level> byn;
 	if (networkId) { Mutex::Lock l(_byNet_m); _byNet.get(networkId,byn); }
 
-	if ((_globalTarget)||(byn.first)) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_NORMAL)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
@@ -146,37 +132,7 @@ void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &p
 		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address());
 		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp));
 		d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket());
-
-		if (_globalTarget)
-			_send(tPtr,d,_globalTarget);
-		if (byn.first)
-			_send(tPtr,d,byn.first);
-	}
-}
-
-void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath)
-{
-	char tmp[128];
-	if (!newPath) return; // sanity check
-
-	ZT_LOCAL_TRACE(tPtr,RR,"explicit redirect from %.10llx to path %s",peer.address().toInt(),newPath->address().toString(tmp));
-
-	std::pair<Address,Trace::Level> byn;
-	if (networkId) { Mutex::Lock l(_byNet_m); _byNet.get(networkId,byn); }
-
-	if ((_globalTarget)||(byn.first)) {
-		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
-		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S);
-		if (networkId)
-			d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId);
-		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address());
-		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp));
-		d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket());
-
-		if (_globalTarget)
-			_send(tPtr,d,_globalTarget);
-		if (byn.first)
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -192,7 +148,7 @@ void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network
 	std::pair<Address,Trace::Level> byn;
 	{ Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); }
 
-	if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) ) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id());
@@ -203,11 +159,7 @@ void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network
 		d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen);
 		if (reason)
 			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE))
-			_send(tPtr,d,_globalTarget);
-		if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE))
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -221,7 +173,7 @@ void Trace::incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network
 	std::pair<Address,Trace::Level> byn;
 	{ Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); }
 
-	if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) ) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_NORMAL)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
@@ -232,11 +184,7 @@ void Trace::incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network
 			d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
 		}
 		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id());
-
-		if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE))
-			_send(tPtr,d,_globalTarget);
-		if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE))
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -250,7 +198,7 @@ void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network
 	std::pair<Address,Trace::Level> byn;
 	{ Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); }
 
-	if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) ) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
@@ -265,11 +213,7 @@ void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network
 		d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt());
 		if (reason)
 			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE))
-			_send(tPtr,d,_globalTarget);
-		if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE))
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -279,21 +223,18 @@ void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const Sh
 
 	ZT_LOCAL_TRACE(tPtr,RR,"MAC failed for packet %.16llx from %.10llx(%s)",packetId,source.toInt(),(path) ? path->address().toString(tmp) : "???");
 
-	if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) {
-		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
-		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S);
-		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
-		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops);
-		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source);
-		if (path) {
-			d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
-			d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
-		}
-		if (reason)
-			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		_send(tPtr,d,_globalTarget);
+	Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
+	d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S);
+	d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
+	d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops);
+	d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source);
+	if (path) {
+		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
+		d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
 	}
+	if (reason)
+		d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
+	_spamToAllNetworks(tPtr,d,Trace::LEVEL_DEBUG);
 }
 
 void Trace::incomingPacketInvalid(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason)
@@ -302,22 +243,19 @@ void Trace::incomingPacketInvalid(void *const tPtr,const SharedPtr<Path> &path,c
 
 	ZT_LOCAL_TRACE(tPtr,RR,"INVALID packet %.16llx from %.10llx(%s) (%s)",packetId,source.toInt(),(path) ? path->address().toString(tmp) : "???",(reason) ? reason : "unknown reason");
 
-	if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) {
-		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
-		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S);
-		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
-		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb);
-		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source);
-		if (path) {
-			d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
-			d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
-		}
-		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops);
-		if (reason)
-			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		_send(tPtr,d,_globalTarget);
+	Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
+	d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S);
+	d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
+	d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb);
+	d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source);
+	if (path) {
+		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
+		d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
 	}
+	d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops);
+	if (reason)
+		d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
+	_spamToAllNetworks(tPtr,d,Trace::LEVEL_DEBUG);
 }
 
 void Trace::incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const char *reason)
@@ -326,32 +264,22 @@ void Trace::incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr<Path> &p
 
 	ZT_LOCAL_TRACE(tPtr,RR,"DROPPED HELLO from %.10llx(%s) (%s)",source.toInt(),(path) ? path->address().toString(tmp) : "???",(reason) ? reason : "???");
 
-	if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) {
-		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
-		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S);
-		d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
-		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source);
-		if (path) {
-			d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
-			d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
-		}
-		if (reason)
-			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		_send(tPtr,d,_globalTarget);
+	Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
+	d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S);
+	d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
+	d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source);
+	if (path) {
+		d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
+		d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
 	}
+	if (reason)
+		d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
+	_spamToAllNetworks(tPtr,d,Trace::LEVEL_DEBUG);
 }
 
 void Trace::networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller)
 {
 	ZT_LOCAL_TRACE(tPtr,RR,"requesting configuration for network %.16llx",network.id());
-	if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) {
-		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
-		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S);
-		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id());
-		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID,controller);
-		_send(tPtr,d,_globalTarget);
-	}
 }
 
 void Trace::networkFilter(
@@ -375,7 +303,7 @@ void Trace::networkFilter(
 	std::pair<Address,Trace::Level> byn;
 	{ Mutex::Lock l(_byNet_m); _byNet.get(network.id(),byn); }
 
-	if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_RULES)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_RULES)) ) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_RULES)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id());
@@ -396,11 +324,7 @@ void Trace::networkFilter(
 		d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen);
 		if (frameLen > 0)
 			d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA,(const char *)frameData,(frameLen > 256) ? (int)256 : (int)frameLen);
-
-		if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_RULES))
-			_send(tPtr,d,_globalTarget);
-		if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_RULES))
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -409,7 +333,7 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c
 	std::pair<Address,Trace::Level> byn;
 	if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
 
-	if ((_globalTarget)||(byn.first)) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId());
@@ -419,11 +343,7 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c
 		d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
 		if (reason)
 			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		if (_globalTarget)
-			_send(tPtr,d,_globalTarget);
-		if (byn.first)
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -432,7 +352,7 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,
 	std::pair<Address,Trace::Level> byn;
 	if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
 
-	if ((_globalTarget)||(byn.first)) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId());
@@ -442,11 +362,7 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,
 		d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
 		if (reason)
 			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		if (_globalTarget)
-			_send(tPtr,d,_globalTarget);
-		if (byn.first)
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -455,7 +371,7 @@ void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *
 	std::pair<Address,Trace::Level> byn;
 	if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
 
-	if ((_globalTarget)||(byn.first)) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId());
@@ -465,11 +381,7 @@ void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *
 		d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
 		if (reason)
 			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		if (_globalTarget)
-			_send(tPtr,d,_globalTarget);
-		if (byn.first)
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -478,7 +390,7 @@ void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason)
 	std::pair<Address,Trace::Level> byn;
 	if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
 
-	if ((_globalTarget)||(byn.first)) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId());
@@ -489,11 +401,7 @@ void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason)
 		d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value());
 		if (reason)
 			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		if (_globalTarget)
-			_send(tPtr,d,_globalTarget);
-		if (byn.first)
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
@@ -502,7 +410,7 @@ void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *
 	std::pair<Address,Trace::Level> byn;
 	if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
 
-	if ((_globalTarget)||(byn.first)) {
+	if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
 		Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
 		d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
 		d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId());
@@ -511,18 +419,12 @@ void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *
 		d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target());
 		if (reason)
 			d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
-
-		if (_globalTarget)
-			_send(tPtr,d,_globalTarget);
-		if (byn.first)
-			_send(tPtr,d,byn.first);
+		_send(tPtr,d,byn.first);
 	}
 }
 
 void Trace::updateMemoizedSettings()
 {
-	_globalTarget = RR->node->remoteTraceTarget();
-	_globalLevel = RR->node->remoteTraceLevel();
 	const std::vector< SharedPtr<Network> > nws(RR->node->allNetworks());
 	{
 		Mutex::Lock l(_byNet_m);

+ 1 - 13
node/Trace.hpp

@@ -73,8 +73,7 @@ public:
 		LEVEL_NORMAL = 0,
 		LEVEL_VERBOSE = 10,
 		LEVEL_RULES = 15,
-		LEVEL_DEBUG = 20,
-		LEVEL_INSANE = 30
+		LEVEL_DEBUG = 20
 	};
 
 	/**
@@ -119,25 +118,17 @@ public:
 	}
 
 	void resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope);
-
 	void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &path,const uint64_t packetId,const Packet::Verb verb);
-
 	void peerLinkNowRedundant(void *const tPtr,Peer &peer);
 	void peerLinkNoLongerRedundant(void *const tPtr,Peer &peer);
-
 	void peerLinkAggregateStatistics(void *const tPtr,Peer &peer);
-
 	void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath,const uint64_t packetId);
-	void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath);
-
 	void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason);
 	void incomingPacketInvalid(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason);
 	void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const char *reason);
-
 	void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason);
 	void incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested);
 	void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason);
-
 	void networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller);
 	void networkFilter(
 		void *const tPtr,
@@ -156,7 +147,6 @@ public:
 		const bool noTee,
 		const bool inbound,
 		const int accept);
-
 	void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason);
 	void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason);
 	void credentialRejected(void *const tPtr,const Capability &c,const char *reason);
@@ -171,8 +161,6 @@ private:
 	void _send(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> &d,const Address &dest);
 	void _spamToAllNetworks(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> &d,const Level level);
 
-	Address _globalTarget;
-	Trace::Level _globalLevel;
 	Hashtable< uint64_t,std::pair< Address,Trace::Level > > _byNet;
 	Mutex _byNet_m;
 };