Parcourir la source

The concept of link desperation (escalating to less desirable transports) simplifies a ton of stuff. Loads of spaghetti logic can die since we no longer have to make these decisions down in the core.

Adam Ierymenko il y a 10 ans
Parent
commit
a69e1876f1
11 fichiers modifiés avec 178 ajouts et 426 suppressions
  1. 8 10
      include/ZeroTierOne.h
  2. 2 2
      node/Constants.hpp
  3. 1 4
      node/Node.cpp
  4. 8 37
      node/Node.hpp
  5. 65 59
      node/Path.hpp
  6. 67 156
      node/Peer.cpp
  7. 20 62
      node/Peer.hpp
  8. 2 30
      node/Switch.cpp
  9. 0 25
      node/Switch.hpp
  10. 1 4
      node/Topology.cpp
  11. 4 37
      node/Topology.hpp

+ 8 - 10
include/ZeroTierOne.h

@@ -144,19 +144,17 @@ enum ZT1_ResultCode
 enum ZT1_NodeStatusCode
 enum ZT1_NodeStatusCode
 {
 {
 	/**
 	/**
-	 * Node is online
+	 * Node is offline -- nothing is reachable
 	 */
 	 */
-	ZT1_NODE_STATUS_ONLINE = 1,
+	ZT1_NODE_STATUS_OFFLINE = 0,
 
 
 	/**
 	/**
-	 * Node is offline -- nothing is reachable
+	 * Node is online -- at least one upstream is reachable
 	 */
 	 */
-	ZT1_NODE_STATUS_OFFLINE = 2,
+	ZT1_NODE_STATUS_ONLINE = 1,
 
 
 	/**
 	/**
-	 * The desperation level has changed
-	 *
-	 * 'extra' will point to an int containing the new level.
+	 * Link desperation level has changed
 	 */
 	 */
 	ZT1_NODE_STATUS_DESPERATION_CHANGE = 3
 	ZT1_NODE_STATUS_DESPERATION_CHANGE = 3
 };
 };
@@ -407,12 +405,12 @@ typedef struct
 } ZT1_PeerPhysicalPath;
 } ZT1_PeerPhysicalPath;
 
 
 /**
 /**
- * What trust hierarchy role does this device have?
+ * What trust hierarchy role does this peer have?
  */
  */
 enum ZT1_PeerRole {
 enum ZT1_PeerRole {
-	ZT1_PEER_ROLE_SUPERNODE = 0, // planetary supernode
+	ZT1_PEER_ROLE_NODE = 0       // ordinary node
 	ZT1_PEER_ROLE_HUB = 1,       // locally federated hub
 	ZT1_PEER_ROLE_HUB = 1,       // locally federated hub
-	ZT1_PEER_ROLE_NODE = 2       // ordinary node
+	ZT1_PEER_ROLE_SUPERNODE = 2, // planetary supernode
 };
 };
 
 
 /**
 /**

+ 2 - 2
node/Constants.hpp

@@ -287,9 +287,9 @@
 #define ZT_DESPERATION_INCREMENT (ZT_STARTUP_AGGRO * 2)
 #define ZT_DESPERATION_INCREMENT (ZT_STARTUP_AGGRO * 2)
 
 
 /**
 /**
- * "Spam" packets to lower desperation links every Nth packet
+ * Interval between "spams" if desperation > 0
  */
  */
-#define ZT_DESPERATION_SPAM_EVERY 10
+#define ZT_DESPERATION_SPAM_INTERVAL 60000
 
 
 /**
 /**
  * Maximum delay between runs of the main loop in Node.cpp
  * Maximum delay between runs of the main loop in Node.cpp

+ 1 - 4
node/Node.cpp

@@ -61,10 +61,7 @@ Node::Node(
 	_statusCallback(statusCallback),
 	_statusCallback(statusCallback),
 	_networks(),
 	_networks(),
 	_networks_m(),
 	_networks_m(),
-	_now(now),
-	_timeOfLastPacketReceived(0),
-	_timeOfLastPrivilegedPacket(0),
-	_spamCounter(0)
+	_now(now)
 {
 {
 	try {
 	try {
 		RR->prng = new CMWC4096();
 		RR->prng = new CMWC4096();

+ 8 - 37
node/Node.hpp

@@ -104,51 +104,25 @@ public:
 	 */
 	 */
 	inline uint64_t now() const throw() { return _now; }
 	inline uint64_t now() const throw() { return _now; }
 
 
-	/**
-	 * @return Current level of desperation
-	 */
-	inline int desperation() const throw() { return (int)((_now - _timeOfLastPrivilgedPacket) / ZT_DESPERATION_INCREMENT); }
-
-	/**
-	 * Called to update last packet receive time whenever a packet is received
-	 *
-	 * @param fromPrivilegedPeer If true, peer is a supernode or federated hub (a.k.a. an upstream link)
-	 */
-	inline void packetReceived(bool fromPrivilegedPeer)
-		throw()
-	{
-		const uint64_t n = _now;
-		_timeOfLastPacketReceived = n;
-		if (fromPrivilegedPeer)
-			_timeOfLastPrivilgedPacket = n;
-	}
-
-	/**
-	 * @return Most recent time of any packet receipt
-	 */
-	inline uint64_t timeOfLastPacketReceived() const throw() { return _timeOfLastPacketReceived; }
-
-	/**
-	 * @return Timestamp of last packet received from a supernode or hub (upstream link)
-	 */
-	inline uint64_t timeOfLastPrivilgedPacket() const throw() { return _timeOfLastPrivilgedPacket; }
-
 	/**
 	/**
 	 * Enqueue a ZeroTier message to be sent
 	 * Enqueue a ZeroTier message to be sent
 	 *
 	 *
 	 * @param addr Destination address
 	 * @param addr Destination address
 	 * @param data Packet data
 	 * @param data Packet data
 	 * @param len Packet length
 	 * @param len Packet length
+	 * @param desperation Link desperation for reaching this address
+	 * @param spam If true, flag this packet to be spammed to lower-desperation links
+	 * @return True if packet appears to have been sent
 	 */
 	 */
-	inline void putPacket(const InetAddress &addr,const void *data,unsigned int len)
+	inline bool putPacket(const InetAddress &addr,const void *data,unsigned int len,int desperation,bool spam)
 	{
 	{
-		_wirePacketSendFunction(
+		return (_wirePacketSendFunction(
 			reinterpret_cast<ZT1_Node *>(this),
 			reinterpret_cast<ZT1_Node *>(this),
 			reinterpret_cast<const struct sockaddr_storage *>(&addr),
 			reinterpret_cast<const struct sockaddr_storage *>(&addr),
-			this->desperation(),
-			(int)((++_spamCounter % ZT_DESPERATION_SPAM_EVERY) == 0),
+			desperation,
+			(int)spam,
 			data,
 			data,
-			len);
+			len) == 0);
 	}
 	}
 
 
 	/**
 	/**
@@ -216,9 +190,6 @@ private:
 	Mutex _networks_m;
 	Mutex _networks_m;
 
 
 	volatile uint64_t _now; // time of last run()
 	volatile uint64_t _now; // time of last run()
-	volatile uint64_t _timeOfLastPacketReceived;
-	volatile _timeOfLastPrivilgedPacket;
-	volatile unsigned int _spamCounter; // used to "spam" every Nth packet
 };
 };
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 65 - 59
node/Path.hpp

@@ -33,6 +33,7 @@
 
 
 #include <stdexcept>
 #include <stdexcept>
 #include <string>
 #include <string>
+#include <algorithm>
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "InetAddress.hpp"
 #include "InetAddress.hpp"
@@ -49,42 +50,28 @@ namespace ZeroTier {
 class Path
 class Path
 {
 {
 public:
 public:
-	enum Type
-	{
-		PATH_TYPE_NULL = 0,
-		PATH_TYPE_UDP = 1,
-		PATH_TYPE_TCP_OUT = 2,
-		PATH_TYPE_TCP_IN = 3
-	};
-
 	Path() :
 	Path() :
 		_lastSend(0),
 		_lastSend(0),
 		_lastReceived(0),
 		_lastReceived(0),
-		_lastPing(0),
 		_addr(),
 		_addr(),
-		_type(PATH_TYPE_NULL),
+		_lastReceiveDesperation(0),
 		_fixed(false) {}
 		_fixed(false) {}
 
 
-	Path(const Path &p)
-	{
-		memcpy(this,&p,sizeof(Path));
-	}
+	Path(const Path &p) throw() { memcpy(this,&p,sizeof(Path)); }
 
 
-	Path(const InetAddress &addr,Type t,bool fixed = false) :
+	Path(const InetAddress &addr,bool fixed) :
 		_lastSend(0),
 		_lastSend(0),
 		_lastReceived(0),
 		_lastReceived(0),
-		_lastPing(0),
 		_addr(addr),
 		_addr(addr),
-		_type(t),
+		_lastReceiveDesperation(0),
 		_fixed(fixed) {}
 		_fixed(fixed) {}
 
 
-	inline void init(const InetAddress &addr,Type t,bool fixed = false)
+	inline void init(const InetAddress &addr,bool fixed)
 	{
 	{
 		_lastSend = 0;
 		_lastSend = 0;
 		_lastReceived = 0;
 		_lastReceived = 0;
-		_lastPing = 0;
 		_addr = addr;
 		_addr = addr;
-		_type = t;
+		_lastReceiveDesperation = 0;
 		_fixed = fixed;
 		_fixed = fixed;
 	}
 	}
 
 
@@ -97,19 +84,54 @@ public:
 
 
 	inline const InetAddress &address() const throw() { return _addr; }
 	inline const InetAddress &address() const throw() { return _addr; }
 
 
-	inline Type type() const throw() { return _type; }
-	inline bool tcp() const throw() { return ((_type == PATH_TYPE_TCP_IN)||(_type == PATH_TYPE_TCP_OUT)); }
-
 	inline uint64_t lastSend() const throw() { return _lastSend; }
 	inline uint64_t lastSend() const throw() { return _lastSend; }
 	inline uint64_t lastReceived() const throw() { return _lastReceived; }
 	inline uint64_t lastReceived() const throw() { return _lastReceived; }
-	inline uint64_t lastPing() const throw() { return _lastPing; }
+	inline int lastReceiveDesperation() const throw() { return _lastReceiveDesperation; }
+
+	/**
+	 * Called when a packet is sent to this path
+	 *
+	 * @param t Time of send
+	 */
+	inline void sent(uint64_t t) throw() { _lastSend = t; }
 
 
+	/**
+	 * Called when a packet is received from this path
+	 *
+	 * @param t Time of receive
+	 * @param d Link desperation of receive
+	 */
+	inline void received(uint64_t t,int d) throw() { _lastReceived = t; _lastReceiveDesperation = d; }
+
+	/**
+	 * @return Is this a fixed path?
+	 */
 	inline bool fixed() const throw() { return _fixed; }
 	inline bool fixed() const throw() { return _fixed; }
+
+	/**
+	 * @param f New value of fixed path flag
+	 */
 	inline void setFixed(bool f) throw() { _fixed = f; }
 	inline void setFixed(bool f) throw() { _fixed = f; }
 
 
-	inline void sent(uint64_t t) throw() { _lastSend = t; }
-	inline void received(uint64_t t) throw() { _lastReceived = t; }
-	inline void pinged(uint64_t t) throw() { _lastPing = t; }
+	/**
+	 * Compute path desperation
+	 *
+	 * Path desperation affects escalation to less efficient fallback
+	 * transports such as TCP or HTTP relaying.
+	 *
+	 * Right now we only escalate desperation for fixed paths, which
+	 * are paths to supernodes. This causes our fallback tunneling
+	 * mechanisms to kick in.
+	 *
+	 * @param now Current time
+	 * @return Path desperation, starting at 0
+	 */
+	inline int desperation(uint64_t now) const
+	{
+		if ((_lastSend > _lastReceived)&&(_fixed))
+			return std::max(_lastReceiveDesperation,(int)((_lastSend - _lastReceived) / ZT_DESPERATION_INCREMENT));
+		return _lastReceiveDesperation;
+	}
 
 
 	/**
 	/**
 	 * @param now Current time
 	 * @param now Current time
@@ -118,53 +140,37 @@ public:
 	inline bool active(uint64_t now) const
 	inline bool active(uint64_t now) const
 		throw()
 		throw()
 	{
 	{
-		return ((_addr)&&((_fixed)||((now - _lastReceived) < ZT_PEER_PATH_ACTIVITY_TIMEOUT)));
+		return ( (_fixed) || ((now - _lastReceived) < ZT_PEER_PATH_ACTIVITY_TIMEOUT) );
 	}
 	}
 
 
 	/**
 	/**
-	 * @return Human-readable address and other information about this path, some computed as of current time
+	 * @param now Current time
+	 * @return Human-readable address and other information about this path
 	 */
 	 */
-	inline std::string toString() const
+	inline std::string toString(uint64_t now) const
 	{
 	{
-		uint64_t now = Utils::now();
 		char tmp[1024];
 		char tmp[1024];
-		const char *t = "";
-		switch(_type) {
-			case PATH_TYPE_NULL: t = "null"; break;
-			case PATH_TYPE_UDP: t = "udp"; break;
-			case PATH_TYPE_TCP_OUT: t = "tcp_out"; break;
-			case PATH_TYPE_TCP_IN: t = "tcp_in"; break;
-		}
-		Utils::snprintf(tmp,sizeof(tmp),"%s;%s;%lld;%lld;%lld;%s",
-			t,
+		Utils::snprintf(tmp,sizeof(tmp),"%s(%s)",
 			_addr.toString().c_str(),
 			_addr.toString().c_str(),
-			(long long)((_lastSend != 0) ? ((now - _lastSend) / 1000LL) : -1),
-			(long long)((_lastReceived != 0) ? ((now - _lastReceived) / 1000LL) : -1),
-			(long long)((_lastPing != 0) ? ((now - _lastPing) / 1000LL) : -1),
 			((_fixed) ? "fixed" : (active(now) ? "active" : "inactive"))
 			((_fixed) ? "fixed" : (active(now) ? "active" : "inactive"))
 		);
 		);
 		return std::string(tmp);
 		return std::string(tmp);
 	}
 	}
 
 
-	inline bool operator==(const Path &p) const throw() { return ((_addr == p._addr)&&(_type == p._type)); }
-	inline bool operator!=(const Path &p) const throw() { return ((_addr != p._addr)||(_type != p._type)); }
-	inline bool operator<(const Path &p) const
-		throw()
-	{
-		if (_addr == p._addr)
-			return ((int)_type < (int)p._type);
-		else return (_addr < p._addr);
-	}
-	inline bool operator>(const Path &p) const throw() { return (p < *this); }
-	inline bool operator<=(const Path &p) const throw() { return !(p < *this); }
-	inline bool operator>=(const Path &p) const throw() { return !(*this < p); }
+	inline operator bool() const throw() { return (_addr); }
+
+	inline bool operator==(const Path &p) const throw() { return (_addr == p._addr); }
+	inline bool operator!=(const Path &p) const throw() { return (_addr != p._addr); }
+	inline bool operator<(const Path &p) const throw() { return (_addr < p._addr); }
+	inline bool operator>(const Path &p) const throw() { return (_addr > p._addr); }
+	inline bool operator<=(const Path &p) const throw() { return (_addr <= p._addr); }
+	inline bool operator>=(const Path &p) const throw() { return (_addr >= p._addr); }
 
 
 private:
 private:
-	volatile uint64_t _lastSend;
-	volatile uint64_t _lastReceived;
-	volatile uint64_t _lastPing;
+	uint64_t _lastSend;
+	uint64_t _lastReceived;
 	InetAddress _addr;
 	InetAddress _addr;
-	Type _type;
+	int _lastReceiveDesperation;
 	bool _fixed;
 	bool _fixed;
 };
 };
 
 

+ 67 - 156
node/Peer.cpp

@@ -27,10 +27,9 @@
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Peer.hpp"
 #include "Peer.hpp"
+#include "Node.hpp"
 #include "Switch.hpp"
 #include "Switch.hpp"
-#include "Packet.hpp"
 #include "Network.hpp"
 #include "Network.hpp"
-#include "NodeConfig.hpp"
 #include "AntiRecursion.hpp"
 #include "AntiRecursion.hpp"
 
 
 #include <algorithm>
 #include <algorithm>
@@ -44,12 +43,13 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
 	_lastUnicastFrame(0),
 	_lastUnicastFrame(0),
 	_lastMulticastFrame(0),
 	_lastMulticastFrame(0),
 	_lastAnnouncedTo(0),
 	_lastAnnouncedTo(0),
+	_lastSpammed(0),
 	_vMajor(0),
 	_vMajor(0),
 	_vMinor(0),
 	_vMinor(0),
 	_vRevision(0),
 	_vRevision(0),
+	_id(peerIdentity),
 	_numPaths(0),
 	_numPaths(0),
-	_latency(0),
-	_id(peerIdentity)
+	_latency(0)
 {
 {
 	if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
 	if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
 		throw std::runtime_error("new peer identity key agreement failed");
 		throw std::runtime_error("new peer identity key agreement failed");
@@ -57,53 +57,50 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
 
 
 void Peer::received(
 void Peer::received(
 	const RuntimeEnvironment *RR,
 	const RuntimeEnvironment *RR,
-	const SharedPtr<Socket> &fromSock,
 	const InetAddress &remoteAddr,
 	const InetAddress &remoteAddr,
+	int linkDesperation
 	unsigned int hops,
 	unsigned int hops,
 	uint64_t packetId,
 	uint64_t packetId,
 	Packet::Verb verb,
 	Packet::Verb verb,
 	uint64_t inRePacketId,
 	uint64_t inRePacketId,
-	Packet::Verb inReVerb,
-	uint64_t now)
+	Packet::Verb inReVerb)
 {
 {
-	// Update system-wide last packet receive time
-	*((const_cast<uint64_t *>(&(RR->timeOfLastPacketReceived)))) = now;
-
-	// Global last receive time regardless of path
+	const uint64_t now = RR->node->now();
 	_lastReceive = now;
 	_lastReceive = now;
 
 
 	if (!hops) {
 	if (!hops) {
-		// Learn paths from direct packets (hops == 0)
+		/* Learn new paths from direct (hops == 0) packets */
 		{
 		{
+			unsigned int np = _numPaths;
+
 			bool havePath = false;
 			bool havePath = false;
-			for(unsigned int p=0,np=_numPaths;p<np;++p) {
-				if ((_paths[p].address() == remoteAddr)&&(_paths[p].tcp() == fromSock->tcp())) {
-					_paths[p].received(now);
+			for(unsigned int p=0;p<np;++p) {
+				if (_paths[p].address() == remoteAddr) {
+					_paths[p].received(now,linkDesperation);
 					havePath = true;
 					havePath = true;
 					break;
 					break;
 				}
 				}
 			}
 			}
 
 
 			if (!havePath) {
 			if (!havePath) {
-				unsigned int np = _numPaths;
-				if (np >= ZT_PEER_MAX_PATHS)
-					clean(now);
-				np = _numPaths;
+				Path *slot = (Path *)0;
 				if (np < ZT_PEER_MAX_PATHS) {
 				if (np < ZT_PEER_MAX_PATHS) {
-					Path::Type pt = Path::PATH_TYPE_UDP;
-					switch(fromSock->type()) {
-						case Socket::ZT_SOCKET_TYPE_TCP_IN:
-							pt = Path::PATH_TYPE_TCP_IN;
-							break;
-						case Socket::ZT_SOCKET_TYPE_TCP_OUT:
-							pt = Path::PATH_TYPE_TCP_OUT;
-							break;
-						default:
-							break;
+					// Add new path
+					slot = &(_paths[np++]);
+				} else {
+					// Replace oldest non-fixed path
+					uint64_t slotLRmin = 0xffffffffffffffffULL;
+					for(unsigned int p=0;p<ZT_PEER_MAX_PATHS;++p) {
+						if ((!_paths[p].fixed())&&(_paths[p].lastReceived() <= slotLRmin)) {
+							slotLRmin = _paths[p].lastReceived();
+							slot = &(_paths[p]);
+						}
 					}
 					}
-					_paths[np].init(remoteAddr,pt,false);
-					_paths[np].received(now);
-					_numPaths = ++np;
+				}
+				if (slot) {
+					slot->init(remoteAddr,false);
+					slot->received(now,linkDesperation);
+					_numPaths = np;
 				}
 				}
 			}
 			}
 		}
 		}
@@ -126,7 +123,7 @@ void Peer::received(
 					for(std::set<MulticastGroup>::iterator mg(mgs.begin());mg!=mgs.end();++mg) {
 					for(std::set<MulticastGroup>::iterator mg(mgs.begin());mg!=mgs.end();++mg) {
 						if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
 						if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
 							outp.armor(_key,true);
 							outp.armor(_key,true);
-							fromSock->send(remoteAddr,outp.data(),outp.size());
+							RR->node->putPacket(remoteAddr,outp.data(),outp.size(),linkDesperation,false);
 							outp.reset(_id.address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
 							outp.reset(_id.address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
 						}
 						}
 
 
@@ -139,156 +136,70 @@ void Peer::received(
 			}
 			}
 			if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) {
 			if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) {
 				outp.armor(_key,true);
 				outp.armor(_key,true);
-				fromSock->send(remoteAddr,outp.data(),outp.size());
+				RR->node->putPacket(remoteAddr,outp.data(),outp.size(),linkDesperation,false);
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME))
 	if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME))
 		_lastUnicastFrame = now;
 		_lastUnicastFrame = now;
-	else if ((verb == Packet::VERB_P5_MULTICAST_FRAME)||(verb == Packet::VERB_MULTICAST_FRAME))
+	else if (verb == Packet::VERB_MULTICAST_FRAME)
 		_lastMulticastFrame = now;
 		_lastMulticastFrame = now;
 }
 }
 
 
-Path::Type Peer::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
+bool Peer::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
 {
 {
-	/* For sending ordinary packets, paths are divided into two categories:
-	 * "normal" and "TCP out." Normal includes UDP and incoming TCP. We want
-	 * to treat outbound TCP differently since if we use it it may end up
-	 * overriding UDP and UDP performs much better. We only want to initiate
-	 * TCP if it looks like UDP isn't available. */
-	Path *bestNormalPath = (Path *)0;
-	Path *bestTcpOutPath = (Path *)0;
-	uint64_t bestNormalPathLastReceived = 0;
-	uint64_t bestTcpOutPathLastReceived = 0;
-	for(unsigned int p=0,np=_numPaths;p<np;++p) {
-		uint64_t lr = _paths[p].lastReceived();
-		if (_paths[p].type() == Path::PATH_TYPE_TCP_OUT) {
-			if (lr >= bestTcpOutPathLastReceived) {
-				bestTcpOutPathLastReceived = lr;
-				bestTcpOutPath = &(_paths[p]);
-			}
-		} else {
-			if (lr >= bestNormalPathLastReceived) {
-				bestNormalPathLastReceived = lr;
-				bestNormalPath = &(_paths[p]);
-			}
-		}
-	}
-
 	Path *bestPath = (Path *)0;
 	Path *bestPath = (Path *)0;
-	uint64_t normalPathAge = now - bestNormalPathLastReceived;
-	uint64_t tcpOutPathAge = now - bestTcpOutPathLastReceived;
-	if (normalPathAge < ZT_PEER_PATH_ACTIVITY_TIMEOUT) {
-		/* If we have a normal path that looks alive, only use TCP if it looks
-		 * even more alive, if the UDP path is not a very recent acquisition,
-		 * and if TCP tunneling is globally enabled. */
-		bestPath = ( (tcpOutPathAge < normalPathAge) && (normalPathAge > (ZT_PEER_DIRECT_PING_DELAY / 4)) && (RR->tcpTunnelingEnabled) ) ? bestTcpOutPath : bestNormalPath;
-	} else if ( (tcpOutPathAge < ZT_PEER_PATH_ACTIVITY_TIMEOUT) || ((RR->tcpTunnelingEnabled)&&(bestTcpOutPath)) ) {
-		/* Otherwise use a TCP path if we have an active one or if TCP
-		 * fallback has been globally triggered and we know of one at all. */
-		bestPath = bestTcpOutPath;
-	} else if ( (bestNormalPath) && (bestNormalPath->fixed()) ) {
-		/* Finally, use a normal path if we have a "fixed" one as these are
-		 * always considered basically alive. */
-		bestPath = bestNormalPath;
-	}
-
-	/* Old path choice logic -- would attempt to use inactive paths... deprecating and will probably kill.
-	Path *bestPath = (Path *)0;
-	if (bestTcpOutPath) { // we have a TCP out path
-		if (bestNormalPath) { // we have both paths, decide which to use
-			if (RR->tcpTunnelingEnabled) { // TCP tunneling is enabled, so use normal path only if it looks alive
-				if ((bestNormalPathLastReceived > RR->timeOfLastResynchronize)&&((now - bestNormalPathLastReceived) < ZT_PEER_PATH_ACTIVITY_TIMEOUT))
-					bestPath = bestNormalPath;
-				else bestPath = bestTcpOutPath;
-			} else { // TCP tunneling is disabled, use normal path
-				bestPath = bestNormalPath;
-			}
-		} else { // we only have a TCP_OUT path, so use it regardless
-			bestPath = bestTcpOutPath;
-		}
-	} else { // we only have a normal path (or none at all, that case is caught below)
-		bestPath = bestNormalPath;
-	}
-	*/
-
-	if (!bestPath)
-		return Path::PATH_TYPE_NULL;
-
-	RR->antiRec->logOutgoingZT(data,len);
-
-	if (RR->sm->send(bestPath->address(),bestPath->tcp(),bestPath->type() == Path::PATH_TYPE_TCP_OUT,data,len)) {
-		bestPath->sent(now);
-		return bestPath->type();
-	}
-
-	return Path::PATH_TYPE_NULL;
-}
-
-bool Peer::sendPing(const RuntimeEnvironment *RR,uint64_t now)
-{
-	bool sent = false;
-	SharedPtr<Peer> self(this);
-
-	/* Ping (and thus open) outbound TCP connections if we have no other options
-	 * or if the TCP tunneling master switch is enabled and pings have been
-	 * unanswered for ZT_TCP_TUNNEL_FAILOVER_TIMEOUT ms over normal channels. */
-	uint64_t lastNormalPingSent = 0;
-	uint64_t lastNormalReceive = 0;
-	bool haveNormal = false;
+	uint64_t lrMax = 0;
 	for(unsigned int p=0,np=_numPaths;p<np;++p) {
 	for(unsigned int p=0,np=_numPaths;p<np;++p) {
-		if (_paths[p].type() != Path::PATH_TYPE_TCP_OUT) {
-			lastNormalPingSent = std::max(lastNormalPingSent,_paths[p].lastPing());
-			lastNormalReceive = std::max(lastNormalReceive,_paths[p].lastReceived());
-			haveNormal = true;
+		if ((_paths[p].active(now)&&(_paths[p].lastReceived() >= lrMax)) {
+			lrMax = _paths[p].lastReceived();
+			bestPath = &(_paths[p]);
 		}
 		}
 	}
 	}
 
 
-	const bool useTcpOut = ( (!haveNormal) || ( (RR->tcpTunnelingEnabled) && (lastNormalPingSent > RR->timeOfLastResynchronize) && (lastNormalPingSent > lastNormalReceive) && ((lastNormalPingSent - lastNormalReceive) >= ZT_TCP_TUNNEL_FAILOVER_TIMEOUT) ) );
-	TRACE("PING %s (useTcpOut==%d)",_id.address().toString().c_str(),(int)useTcpOut);
-
-	for(unsigned int p=0,np=_numPaths;p<np;++p) {
-		if ((useTcpOut)||(_paths[p].type() != Path::PATH_TYPE_TCP_OUT)) {
-			_paths[p].pinged(now); // attempts to ping are logged whether they look successful or not
-			if (RR->sw->sendHELLO(self,_paths[p])) {
-				_paths[p].sent(now);
-				sent = true;
-			}
+	if (bestPath) {
+		bool spam = ((now - _lastSpammed) >= ZT_DESPERATION_SPAM_INTERVAL);
+		if (RR->node->putPacket(bestPath->address(),data,len,bestPath->desperation(),spam)) {
+			bestPath->sent(now);
+			RR->antiRec->logOutgoingZT(data,len);
+			if (spam)
+				_lastSpammed = now;
+			return true;
 		}
 		}
 	}
 	}
 
 
-	return sent;
-}
-
-void Peer::clean(uint64_t now)
-{
-	unsigned int np = _numPaths;
-	unsigned int x = 0;
-	unsigned int y = 0;
-	while (x < np) {
-		if (_paths[x].active(now))
-			_paths[y++] = _paths[x];
-		++x;
-	}
-	_numPaths = y;
+	return false;
 }
 }
 
 
 void Peer::addPath(const Path &newp)
 void Peer::addPath(const Path &newp)
 {
 {
 	unsigned int np = _numPaths;
 	unsigned int np = _numPaths;
+
 	for(unsigned int p=0;p<np;++p) {
 	for(unsigned int p=0;p<np;++p) {
-		if (_paths[p] == newp) {
+		if (_paths[p].address() == newp.address()) {
 			_paths[p].setFixed(newp.fixed());
 			_paths[p].setFixed(newp.fixed());
 			return;
 			return;
 		}
 		}
 	}
 	}
-	if (np >= ZT_PEER_MAX_PATHS)
-		clean(Utils::now());
-	np = _numPaths;
+
+	Path *slot = (Path *)0;
 	if (np < ZT_PEER_MAX_PATHS) {
 	if (np < ZT_PEER_MAX_PATHS) {
-		_paths[np] = newp;
-		_numPaths = ++np;
+		// Add new path
+		slot = &(_paths[np++]);
+	} else {
+		// Replace oldest non-fixed path
+		uint64_t slotLRmin = 0xffffffffffffffffULL;
+		for(unsigned int p=0;p<ZT_PEER_MAX_PATHS;++p) {
+			if ((!_paths[p].fixed())&&(_paths[p].lastReceived() <= slotLRmin)) {
+				slotLRmin = _paths[p].lastReceived();
+				slot = &(_paths[p]);
+			}
+		}
+	}
+	if (slot) {
+		*slot = newp;
+		_numPaths = np;
 	}
 	}
 }
 }
 
 
@@ -309,11 +220,11 @@ void Peer::clearPaths(bool fixedToo)
 	}
 	}
 }
 }
 
 
-void Peer::getBestActiveUdpPathAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
+void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
 {
 {
 	uint64_t bestV4 = 0,bestV6 = 0;
 	uint64_t bestV4 = 0,bestV6 = 0;
 	for(unsigned int p=0,np=_numPaths;p<np;++p) {
 	for(unsigned int p=0,np=_numPaths;p<np;++p) {
-		if ((_paths[p].type() == Path::PATH_TYPE_UDP)&&(_paths[p].active(now))) {
+		if (_paths[p].active(now)) {
 			uint64_t lr = _paths[p].lastReceived();
 			uint64_t lr = _paths[p].lastReceived();
 			if (lr) {
 			if (lr) {
 				if (_paths[p].address().isV4()) {
 				if (_paths[p].address().isV4()) {

+ 20 - 62
node/Peer.hpp

@@ -35,6 +35,8 @@
 #include <vector>
 #include <vector>
 #include <stdexcept>
 #include <stdexcept>
 
 
+#include "../include/ZeroTierOne.h"
+
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "Path.hpp"
 #include "Path.hpp"
@@ -51,7 +53,7 @@
 /**
 /**
  * Maximum number of paths a peer can have
  * Maximum number of paths a peer can have
  */
  */
-#define ZT_PEER_MAX_PATHS 8
+#define ZT_PEER_MAX_PATHS 3
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
@@ -111,25 +113,23 @@ public:
 	 * and appears to be valid.
 	 * and appears to be valid.
 	 * 
 	 * 
 	 * @param RR Runtime environment
 	 * @param RR Runtime environment
-	 * @param fromSock Socket from which packet was received
 	 * @param remoteAddr Internet address of sender
 	 * @param remoteAddr Internet address of sender
+	 * @param linkDesperation Link desperation level
 	 * @param hops ZeroTier (not IP) hops
 	 * @param hops ZeroTier (not IP) hops
 	 * @param packetId Packet ID
 	 * @param packetId Packet ID
 	 * @param verb Packet verb
 	 * @param verb Packet verb
-	 * @param inRePacketId Packet ID in reply to (for OK/ERROR, 0 otherwise)
-	 * @param inReVerb Verb in reply to (for OK/ERROR, VERB_NOP otherwise)
-	 * @param now Current time
+	 * @param inRePacketId Packet ID in reply to (default: none)
+	 * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP)
 	 */
 	 */
 	void received(
 	void received(
 		const RuntimeEnvironment *RR,
 		const RuntimeEnvironment *RR,
-		const SharedPtr<Socket> &fromSock,
 		const InetAddress &remoteAddr,
 		const InetAddress &remoteAddr,
+		int linkDesperation,
 		unsigned int hops,
 		unsigned int hops,
 		uint64_t packetId,
 		uint64_t packetId,
 		Packet::Verb verb,
 		Packet::Verb verb,
-		uint64_t inRePacketId,
-		Packet::Verb inReVerb,
-		uint64_t now);
+		uint64_t inRePacketId = 0,
+		Packet::Verb inReVerb = Packet::VERB_NOP);
 
 
 	/**
 	/**
 	 * Send a packet directly to this peer
 	 * Send a packet directly to this peer
@@ -141,26 +141,9 @@ public:
 	 * @param data Data to send
 	 * @param data Data to send
 	 * @param len Length of packet
 	 * @param len Length of packet
 	 * @param now Current time
 	 * @param now Current time
-	 * @return Type of path used or Path::PATH_TYPE_NULL on failure
-	 */
-	Path::Type send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now);
-
-	/**
-	 * Send HELLO to a peer via all direct paths available
-	 *
-	 * This begins attempting to use TCP paths if no ping response has been
-	 * received from any UDP path in more than ZT_TCP_FALLBACK_AFTER.
-	 * 
-	 * @param RR Runtime environment
-	 * @param now Current time
-	 * @return True if send appears successful for at least one address type
+	 * @return True if packet appears to have been sent via some available path
 	 */
 	 */
-	bool sendPing(const RuntimeEnvironment *RR,uint64_t now);
-
-	/**
-	 * Called periodically by Topology::clean() to remove stale paths and do other cleanup
-	 */
-	void clean(uint64_t now);
+	bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now);
 
 
 	/**
 	/**
 	 * @return All known direct paths to this peer
 	 * @return All known direct paths to this peer
@@ -173,19 +156,6 @@ public:
 		return pp;
 		return pp;
 	}
 	}
 
 
-	/**
-	 * @param addr IP:port
-	 * @return True if we have a UDP path to this address
-	 */
-	inline bool haveUdpPath(const InetAddress &addr) const
-	{
-		for(unsigned int p=0,np=_numPaths;p<np;++p) {
-			if ((_paths[p].type() == Path::PATH_TYPE_UDP)&&(_paths[p].address() == addr))
-				return true;
-		}
-		return false;
-	}
-
 	/**
 	/**
 	 * @return Time of last direct packet receive for any path
 	 * @return Time of last direct packet receive for any path
 	 */
 	 */
@@ -210,21 +180,6 @@ public:
 		return x;
 		return x;
 	}
 	}
 
 
-	/**
-	 * Get max timestamp of last ping and max timestamp of last receive in a single pass
-	 *
-	 * @param lp Last ping result parameter (init to 0 before calling)
-	 * @param lr Last receive result parameter (init to 0 before calling)
-	 */
-	inline void lastPingAndDirectReceive(uint64_t &lp,uint64_t &lr)
-		throw()
-	{
-		for(unsigned int p=0,np=_numPaths;p<np;++p) {
-			lp = std::max(lp,_paths[p].lastPing());
-			lr = std::max(lr,_paths[p].lastReceived());
-		}
-	}
-
 	/**
 	/**
 	 * @return Time of last receive of anything, whether direct or relayed
 	 * @return Time of last receive of anything, whether direct or relayed
 	 */
 	 */
@@ -378,7 +333,7 @@ public:
 	 * @param v4 Result parameter to receive active IPv4 address, if any
 	 * @param v4 Result parameter to receive active IPv4 address, if any
 	 * @param v6 Result parameter to receive active IPv6 address, if any
 	 * @param v6 Result parameter to receive active IPv6 address, if any
 	 */
 	 */
-	void getBestActiveUdpPathAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const;
+	void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const;
 
 
 	/**
 	/**
 	 * Find a common set of addresses by which two peers can link, if any
 	 * Find a common set of addresses by which two peers can link, if any
@@ -391,8 +346,8 @@ public:
 	static inline std::pair<InetAddress,InetAddress> findCommonGround(const Peer &a,const Peer &b,uint64_t now)
 	static inline std::pair<InetAddress,InetAddress> findCommonGround(const Peer &a,const Peer &b,uint64_t now)
 	{
 	{
 		std::pair<InetAddress,InetAddress> v4,v6;
 		std::pair<InetAddress,InetAddress> v4,v6;
-		b.getBestActiveUdpPathAddresses(now,v4.first,v6.first);
-		a.getBestActiveUdpPathAddresses(now,v4.second,v6.second);
+		b.getBestActiveAddresses(now,v4.first,v6.first);
+		a.getBestActiveAddresses(now,v4.second,v6.second);
 		if ((v6.first)&&(v6.second)) // prefer IPv6 if both have it since NAT-t is (almost) unnecessary
 		if ((v6.first)&&(v6.second)) // prefer IPv6 if both have it since NAT-t is (almost) unnecessary
 			return v6;
 			return v6;
 		else if ((v4.first)&&(v4.second))
 		else if ((v4.first)&&(v4.second))
@@ -403,23 +358,26 @@ public:
 private:
 private:
 	void _announceMulticastGroups(const RuntimeEnvironment *RR,uint64_t now);
 	void _announceMulticastGroups(const RuntimeEnvironment *RR,uint64_t now);
 
 
+	unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH];
+
 	uint64_t _lastUsed;
 	uint64_t _lastUsed;
 	uint64_t _lastReceive; // direct or indirect
 	uint64_t _lastReceive; // direct or indirect
 	uint64_t _lastUnicastFrame;
 	uint64_t _lastUnicastFrame;
 	uint64_t _lastMulticastFrame;
 	uint64_t _lastMulticastFrame;
 	uint64_t _lastAnnouncedTo;
 	uint64_t _lastAnnouncedTo;
+	uint64_t _lastSpammed;
 	uint16_t _vProto;
 	uint16_t _vProto;
 	uint16_t _vMajor;
 	uint16_t _vMajor;
 	uint16_t _vMinor;
 	uint16_t _vMinor;
 	uint16_t _vRevision;
 	uint16_t _vRevision;
 
 
+	Identity _id;
+
 	Path _paths[ZT_PEER_MAX_PATHS];
 	Path _paths[ZT_PEER_MAX_PATHS];
 	unsigned int _numPaths;
 	unsigned int _numPaths;
 
 
 	unsigned int _latency;
 	unsigned int _latency;
-	unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH];
-	Identity _id;
-
+	unsigned int _spamCounter;
 	AtomicCounter __refCount;
 	AtomicCounter __refCount;
 };
 };
 
 

+ 2 - 30
node/Switch.cpp

@@ -270,6 +270,7 @@ void Switch::send(const Packet &packet,bool encrypt)
 	}
 	}
 }
 }
 
 
+#if 0
 void Switch::sendHELLO(const Address &dest)
 void Switch::sendHELLO(const Address &dest)
 {
 {
 	Packet outp(dest,RR->identity.address(),Packet::VERB_HELLO);
 	Packet outp(dest,RR->identity.address(),Packet::VERB_HELLO);
@@ -281,36 +282,7 @@ void Switch::sendHELLO(const Address &dest)
 	RR->identity.serialize(outp,false);
 	RR->identity.serialize(outp,false);
 	send(outp,false);
 	send(outp,false);
 }
 }
-
-bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const Path &path)
-{
-	uint64_t now = Utils::now();
-	Packet outp(dest->address(),RR->identity.address(),Packet::VERB_HELLO);
-	outp.append((unsigned char)ZT_PROTO_VERSION);
-	outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
-	outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
-	outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
-	outp.append(now);
-	RR->identity.serialize(outp,false);
-	outp.armor(dest->key(),false);
-	RR->antiRec->logOutgoingZT(outp.data(),outp.size());
-	return RR->sm->send(path.address(),path.tcp(),path.type() == Path::PATH_TYPE_TCP_OUT,outp.data(),outp.size());
-}
-
-bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &destUdp)
-{
-	uint64_t now = Utils::now();
-	Packet outp(dest->address(),RR->identity.address(),Packet::VERB_HELLO);
-	outp.append((unsigned char)ZT_PROTO_VERSION);
-	outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
-	outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
-	outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
-	outp.append(now);
-	RR->identity.serialize(outp,false);
-	outp.armor(dest->key(),false);
-	RR->antiRec->logOutgoingZT(outp.data(),outp.size());
-	return RR->sm->send(destUdp,false,false,outp.data(),outp.size());
-}
+#endif
 
 
 bool Switch::unite(const Address &p1,const Address &p2,bool force)
 bool Switch::unite(const Address &p1,const Address &p2,bool force)
 {
 {

+ 0 - 25
node/Switch.hpp

@@ -116,31 +116,6 @@ public:
 	 */
 	 */
 	void send(const Packet &packet,bool encrypt);
 	void send(const Packet &packet,bool encrypt);
 
 
-	/**
-	 * Send a HELLO announcement
-	 *
-	 * @param dest Address of destination
-	 */
-	void sendHELLO(const Address &dest);
-
-	/**
-	 * Send a HELLO announcement immediately to the indicated address
-	 *
-	 * @param dest Destination peer
-	 * @param path Network path to peer
-	 * @return True if send appears successful
-	 */
-	bool sendHELLO(const SharedPtr<Peer> &dest,const Path &path);
-
-	/**
-	 * Send a HELLO announcement immediately to the indicated address via UDP
-	 *
-	 * @param dest Destination peer
-	 * @param destUdp UDP inet address
-	 * @return True if send appears successful
-	 */
-	bool sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &destUdp);
-
 	/**
 	/**
 	 * Send RENDEZVOUS to two peers to permit them to directly connect
 	 * Send RENDEZVOUS to two peers to permit them to directly connect
 	 *
 	 *

+ 1 - 4
node/Topology.cpp

@@ -251,10 +251,7 @@ void Topology::clean(uint64_t now)
 	for(std::map< Address,SharedPtr<Peer> >::iterator p(_activePeers.begin());p!=_activePeers.end();) {
 	for(std::map< Address,SharedPtr<Peer> >::iterator p(_activePeers.begin());p!=_activePeers.end();) {
 		if (((now - p->second->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),p->first) == _supernodeAddresses.end())) {
 		if (((now - p->second->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),p->first) == _supernodeAddresses.end())) {
 			_activePeers.erase(p++);
 			_activePeers.erase(p++);
-		} else {
-			p->second->clean(now);
-			++p;
-		}
+		} else ++p;
 	}
 	}
 }
 }
 
 

+ 4 - 37
node/Topology.hpp

@@ -191,6 +191,7 @@ public:
 			f(*this,p->second);
 			f(*this,p->second);
 	}
 	}
 
 
+#if 0
 	/**
 	/**
 	 * Apply a function or function object to all supernode peers
 	 * Apply a function or function object to all supernode peers
 	 *
 	 *
@@ -274,7 +275,7 @@ public:
 			uint64_t lp = 0;
 			uint64_t lp = 0;
 			uint64_t lr = 0;
 			uint64_t lr = 0;
 			p->lastPingAndDirectReceive(lp,lr);
 			p->lastPingAndDirectReceive(lp,lr);
-			if ( (lr < RR->timeOfLastResynchronize) || ((lr < lp)&&((lp - lr) >= ZT_PING_UNANSWERED_AFTER)) || ((_now - lr) >= ZT_PEER_DIRECT_PING_DELAY) )
+			if ( ((lr < lp)&&((lp - lr) >= ZT_PING_UNANSWERED_AFTER)) || ((_now - lr) >= ZT_PEER_DIRECT_PING_DELAY) )
 				p->sendPing(RR,_now);
 				p->sendPing(RR,_now);
 		}
 		}
 
 
@@ -283,22 +284,9 @@ public:
 		const RuntimeEnvironment *RR;
 		const RuntimeEnvironment *RR;
 	};
 	};
 
 
-	/**
-	 * Computes most recent timestamp of direct packet receive over a list of peers
-	 */
-	class FindMostRecentDirectReceiveTimestamp
-	{
-	public:
-		FindMostRecentDirectReceiveTimestamp(uint64_t &ts) throw() : _ts(ts) {}
-		inline void operator()(Topology &t,const SharedPtr<Peer> &p) throw() { _ts = std::max(p->lastDirectReceive(),_ts); }
-	private:
-		uint64_t &_ts;
-	};
-
 	/**
 	/**
 	 * Function object to forget direct links to active peers and then ping them indirectly
 	 * Function object to forget direct links to active peers and then ping them indirectly
 	 */
 	 */
-	/*
 	class ResetActivePeers
 	class ResetActivePeers
 	{
 	{
 	public:
 	public:
@@ -333,28 +321,7 @@ public:
 		std::vector<Address> _supernodeAddresses;
 		std::vector<Address> _supernodeAddresses;
 		const RuntimeEnvironment *RR;
 		const RuntimeEnvironment *RR;
 	};
 	};
-	*/
-
-	/**
-	 * Function object to collect peers with any known direct path
-	 */
-	class CollectPeersWithActiveDirectPath
-	{
-	public:
-		CollectPeersWithActiveDirectPath(std::vector< SharedPtr<Peer> > &v,uint64_t now) throw() :
-			_now(now),
-			_v(v) {}
-
-		inline void operator()(Topology &t,const SharedPtr<Peer> &p)
-		{
-			if (p->hasActiveDirectPath(_now))
-				_v.push_back(p);
-		}
-
-	private:
-		uint64_t _now;
-		std::vector< SharedPtr<Peer> > &_v;
-	};
+#endif
 
 
 	/**
 	/**
 	 * Update our knowledge of exterior network addresses
 	 * Update our knowledge of exterior network addresses
@@ -396,7 +363,7 @@ private:
 	Mutex _lock;
 	Mutex _lock;
 
 
 	// Set to true if my identity is in _supernodes
 	// Set to true if my identity is in _supernodes
-	volatile bool _amSupernode;
+	bool _amSupernode;
 };
 };
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier