Browse Source

A few more tweaks to TCP failover... seems to be switching back and forth pretty well now!

Adam Ierymenko 11 years ago
parent
commit
fe85426df6
4 changed files with 32 additions and 41 deletions
  1. 26 31
      node/Peer.cpp
  2. 3 8
      node/Peer.hpp
  3. 2 2
      node/Topology.hpp
  4. 1 0
      node/UdpSocket.cpp

+ 26 - 31
node/Peer.cpp

@@ -120,25 +120,24 @@ void Peer::receive(
 
 bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now)
 {
-	// Note: we'll still use TCP here if that's all we have, but if this
-	// is false we will prefer UDP.
-	bool useTcp = isTcpFailoverTime(_r,now);
-
 	Mutex::Lock _l(_lock);
+	bool useTcp = _isTcpFailoverTime(_r,now);
 
 	std::vector<Path>::iterator p(_paths.begin());
+	if (useTcp) {
+		while ((p->tcp())&&(p != _paths.end()))
+			++p;
+	}
 	if (p == _paths.end())
 		return false;
 
 	uint64_t bestPathLastReceived = p->lastReceived();
 	std::vector<Path>::iterator bestPath = p;
-	bool bestPathIsTcp = p->tcp();
 	while (++p != _paths.end()) {
 		uint64_t lr = p->lastReceived();
-		if ( (lr > bestPathLastReceived) || ((bestPathIsTcp)&&(!useTcp)) ) {
+		if ( (lr > bestPathLastReceived) && ((useTcp)||(!p->tcp())) ) {
 			bestPathLastReceived = lr;
 			bestPath = p;
-			bestPathIsTcp = p->tcp();
 		}
 	}
 
@@ -167,13 +166,11 @@ bool Peer::sendPing(const RuntimeEnvironment *_r,uint64_t now)
 {
 	bool sent = false;
 	SharedPtr<Peer> self(this);
-
-	// In the ping case we will never send TCP unless this returns true.
-	bool useTcp = isTcpFailoverTime(_r,now);
+	Mutex::Lock _l(_lock);
+	bool useTcp = _isTcpFailoverTime(_r,now);
 
 	TRACE("PING %s (useTcp==%d)",_id.address().toString().c_str(),(int)useTcp);
 
-	Mutex::Lock _l(_lock);
 	for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
 		if ((useTcp)||(!p->tcp())) {
 			p->pinged(now); // we log pings sent even if the send "fails", since what we want to track is when we last tried to ping
@@ -187,9 +184,22 @@ bool Peer::sendPing(const RuntimeEnvironment *_r,uint64_t now)
 	return sent;
 }
 
-bool Peer::isTcpFailoverTime(const RuntimeEnvironment *_r,uint64_t now) const
+void Peer::clean(uint64_t now)
+{
+	Mutex::Lock _l(_lock);
+	unsigned long i = 0,o = 0,l = (unsigned long)_paths.size();
+	while (i != l) {
+		if (_paths[i].active(now))
+			_paths[o++] = _paths[i];
+		++i;
+	}
+	_paths.resize(o);
+}
+
+bool Peer::_isTcpFailoverTime(const RuntimeEnvironment *_r,uint64_t now) const
 	throw()
 {
+	// assumes _lock is locked
 	uint64_t lastResync = _r->timeOfLastResynchronize;
 	if ((now - lastResync) >= ZT_TCP_TUNNEL_FAILOVER_TIMEOUT) {
 		if ((now - _r->timeOfLastPacketReceived) >= ZT_TCP_TUNNEL_FAILOVER_TIMEOUT)
@@ -198,13 +208,10 @@ bool Peer::isTcpFailoverTime(const RuntimeEnvironment *_r,uint64_t now) const
 		uint64_t lastUdpPingSent = 0;
 		uint64_t lastUdpReceive = 0;
 
-		{
-			Mutex::Lock _l(_lock);
-			for(std::vector<Path>::const_iterator p(_paths.begin());p!=_paths.end();++p) {
-				if (p->type() == Path::PATH_TYPE_UDP) {
-					lastUdpPingSent = std::max(lastUdpPingSent,p->lastPing());
-					lastUdpReceive = std::max(lastUdpReceive,p->lastReceived());
-				}
+		for(std::vector<Path>::const_iterator p(_paths.begin());p!=_paths.end();++p) {
+			if (p->type() == Path::PATH_TYPE_UDP) {
+				lastUdpPingSent = std::max(lastUdpPingSent,p->lastPing());
+				lastUdpReceive = std::max(lastUdpReceive,p->lastReceived());
 			}
 		}
 
@@ -213,16 +220,4 @@ bool Peer::isTcpFailoverTime(const RuntimeEnvironment *_r,uint64_t now) const
 	return false;
 }
 
-void Peer::clean(uint64_t now)
-{
-	Mutex::Lock _l(_lock);
-	unsigned long i = 0,o = 0,l = (unsigned long)_paths.size();
-	while (i != l) {
-		if (_paths[i].active(now))
-			_paths[o++] = _paths[i];
-		++i;
-	}
-	_paths.resize(o);
-}
-
 } // namespace ZeroTier

+ 3 - 8
node/Peer.hpp

@@ -282,14 +282,6 @@ public:
 		return _lastAnnouncedTo;
 	}
 
-	/**
-	 * @param _r Runtime environment
-	 * @param now Current time
-	 * @return True if it's time to attempt TCP failover (if we have TCP_OUT paths)
-	 */
-	bool isTcpFailoverTime(const RuntimeEnvironment *_r,uint64_t now) const
-		throw();
-
 	/**
 	 * @return Current latency or 0 if unknown (max: 65535)
 	 */
@@ -508,6 +500,9 @@ public:
 	}
 
 private:
+	bool _isTcpFailoverTime(const RuntimeEnvironment *_r,uint64_t now) const
+		throw();
+
 	unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH];
 	Identity _id;
 

+ 2 - 2
node/Topology.hpp

@@ -235,7 +235,7 @@ public:
 			 * than time of last send in order to only count full round trips. */
 			if ( (!_supernodeAddresses.count(p->address())) &&
 			     ((_now - p->lastFrame()) < ZT_PEER_PATH_ACTIVITY_TIMEOUT) &&
-				 ((_now - p->lastDirectReceive()) > ZT_PEER_DIRECT_PING_DELAY) ) {
+			     ((_now - p->lastDirectReceive()) > ZT_PEER_DIRECT_PING_DELAY) ) {
 				p->sendPing(_r,_now);
 			}
 		}
@@ -261,7 +261,7 @@ public:
 			/* For supernodes we always ping even if no frames have been seen, and
 			 * we ping aggressively if pings are unanswered. The limit to this
 			 * frequency is set in the main loop to no more than ZT_STARTUP_AGGRO. */
-			if ( (p->pingUnanswered(_r,_now)) || ((_now - p->lastDirectReceive()) > ZT_PEER_DIRECT_PING_DELAY) )
+			if ( (p->pingUnanswered(_r,_now)) || ((_now - p->lastDirectReceive()) > ZT_PEER_DIRECT_PING_DELAY) || (p->lastDirectReceive() < _r->timeOfLastResynchronize) )
 				p->sendPing(_r,_now);
 		}
 

+ 1 - 0
node/UdpSocket.cpp

@@ -49,6 +49,7 @@
 #endif
 
 // Uncomment to intentionally break UDP in order to test TCP fallback
+// This is here so I can commit it to the repo and drive myself insane.
 //#define ZT_BREAK_UDP
 
 namespace ZeroTier {