Browse Source

IPv6 support fixes.

Adam Ierymenko 10 years ago
parent
commit
2229e91b57
3 changed files with 69 additions and 25 deletions
  1. 29 10
      node/Node.cpp
  2. 35 12
      node/Peer.cpp
  3. 5 3
      node/Peer.hpp

+ 29 - 10
node/Node.cpp

@@ -186,33 +186,52 @@ public:
 	inline void operator()(Topology &t,const SharedPtr<Peer> &p)
 	inline void operator()(Topology &t,const SharedPtr<Peer> &p)
 	{
 	{
 		bool upstream = false;
 		bool upstream = false;
-		InetAddress stableEndpoint;
+		InetAddress stableEndpoint4,stableEndpoint6;
+
+		// If this is a world root, pick (if possible) both an IPv4 and an IPv6 stable endpoint to use if link isn't currently alive.
 		for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
 		for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
 			if (r->identity.address() == p->address()) {
 			if (r->identity.address() == p->address()) {
-				if (r->stableEndpoints.size() > 0)
-					stableEndpoint = r->stableEndpoints[(unsigned long)RR->node->prng() % r->stableEndpoints.size()];
 				upstream = true;
 				upstream = true;
+				for(unsigned long k=0,ptr=RR->node->prng();k<r->stableEndpoints.size();++k) {
+					const InetAddress &addr = r->stableEndpoints[ptr++ % r->stableEndpoints.size()];
+					if (!stableEndpoint4) {
+						if (addr.ss_family == AF_INET)
+							stableEndpoint4 = addr;
+					} else if (!stableEndpoint6) {
+						if (addr.ss_family == AF_INET6)
+							stableEndpoint6 = addr;
+					} else break; // have both!
+				}
 				break;
 				break;
 			}
 			}
 		}
 		}
 
 
+		// If this is a network preferred relay, also always ping and if a stable endpoint is specified use that if not alive
 		if (!upstream) {
 		if (!upstream) {
 			for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
 			for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
 				if (r->first == p->address()) {
 				if (r->first == p->address()) {
-					stableEndpoint = r->second;
+					if (r->second.ss_family == AF_INET)
+						stableEndpoint4 = r->second;
+					else if (r->second.ss_family == AF_INET6)
+						stableEndpoint6 = r->second;
 					upstream = true;
 					upstream = true;
 					break;
 					break;
 				}
 				}
 			}
 			}
 		}
 		}
 
 
-		if ((p->alive(_now))||(upstream)) {
-			if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint))
-				p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now);
-		}
-
-		if (upstream)
+		if (upstream) {
+			// "Upstream" devices are roots and relays and get special treatment -- they stay alive
+			// forever and we try to keep (if available) both IPv4 and IPv6 channels open to them.
+			if ((!p->doPingAndKeepalive(RR,_now,AF_INET))&&(stableEndpoint4))
+				p->attemptToContactAt(RR,InetAddress(),stableEndpoint4,_now);
+			if ((!p->doPingAndKeepalive(RR,_now,AF_INET6))&&(stableEndpoint6))
+				p->attemptToContactAt(RR,InetAddress(),stableEndpoint6,_now);
 			lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream);
 			lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream);
+		} else if (p->alive(_now)) {
+			// Normal nodes get their preferred link kept alive if the node has generated frame traffic recently
+			p->doPingAndKeepalive(RR,_now,0);
+		}
 	}
 	}
 
 
 private:
 private:

+ 35 - 12
node/Peer.cpp

@@ -179,23 +179,31 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo
 	RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
 	RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
 }
 }
 
 
-RemotePath *Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
+bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily)
 {
 {
+	RemotePath *p = (RemotePath *)0;
+
 	Mutex::Lock _l(_lock);
 	Mutex::Lock _l(_lock);
-	RemotePath *const bestPath = _getBestPath(now);
-	if (bestPath) {
-		if ((now - bestPath->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) {
-			TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->lastReceived());
-			attemptToContactAt(RR,bestPath->localAddress(),bestPath->address(),now);
-			bestPath->sent(now);
-		} else if (((now - bestPath->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!bestPath->reliable())) {
-			TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->lastReceived());
+	if (inetAddressFamily != 0) {
+		p = _getBestPath(now,inetAddressFamily);
+	} else {
+		p = _getBestPath(now);
+	}
+
+	if (p) {
+		if ((now - p->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) {
+			TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived());
+			attemptToContactAt(RR,p->localAddress(),p->address(),now);
+			p->sent(now);
+		} else if (((now - p->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!p->reliable())) {
+			TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived());
 			_natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads
 			_natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads
-			RR->node->putPacket(bestPath->localAddress(),bestPath->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf));
-			bestPath->sent(now);
+			RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf));
+			p->sent(now);
 		}
 		}
+		return true;
 	}
 	}
-	return bestPath;
+	return false;
 }
 }
 
 
 void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force)
 void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force)
@@ -465,4 +473,19 @@ RemotePath *Peer::_getBestPath(const uint64_t now)
 	return (RemotePath *)0;
 	return (RemotePath *)0;
 }
 }
 
 
+RemotePath *Peer::_getBestPath(const uint64_t now,int inetAddressFamily)
+{
+	// assumes _lock is locked
+	if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL)
+		_sortPaths(now);
+	for(int k=0;k<2;++k) { // try once, and if it fails sort and try one more time
+		for(unsigned int i=0;i<_numPaths;++i) {
+			if ((_paths[i].active(now))&&((int)_paths[i].address().ss_family == inetAddressFamily))
+				return &(_paths[i]);
+		}
+		_sortPaths(now);
+	}
+	return (RemotePath *)0;
+}
+
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 5 - 3
node/Peer.hpp

@@ -130,7 +130,7 @@ public:
 		Packet::Verb inReVerb = Packet::VERB_NOP);
 		Packet::Verb inReVerb = Packet::VERB_NOP);
 
 
 	/**
 	/**
-	 * Get the best direct path to this peer
+	 * Get the current best direct path to this peer
 	 *
 	 *
 	 * @param now Current time
 	 * @param now Current time
 	 * @return Best path or NULL if there are no active direct paths
 	 * @return Best path or NULL if there are no active direct paths
@@ -178,9 +178,10 @@ public:
 	 *
 	 *
 	 * @param RR Runtime environment
 	 * @param RR Runtime environment
 	 * @param now Current time
 	 * @param now Current time
-	 * @return Current best path or NULL if no active paths
+	 * @param inetAddressFamily Keep this address family alive, or 0 to simply pick current best ignoring family
+	 * @return True if at least one direct path seems alive
 	 */
 	 */
-	RemotePath *doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
+	bool doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily);
 
 
 	/**
 	/**
 	 * Push direct paths if we haven't done so in [rate limit] milliseconds
 	 * Push direct paths if we haven't done so in [rate limit] milliseconds
@@ -559,6 +560,7 @@ public:
 private:
 private:
 	void _sortPaths(const uint64_t now);
 	void _sortPaths(const uint64_t now);
 	RemotePath *_getBestPath(const uint64_t now);
 	RemotePath *_getBestPath(const uint64_t now);
+	RemotePath *_getBestPath(const uint64_t now,int inetAddressFamily);
 
 
 	unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized
 	unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized