summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/ZeroTierOne.h5
-rw-r--r--node/Constants.hpp18
-rw-r--r--node/IncomingPacket.cpp2
-rw-r--r--node/Node.cpp25
-rw-r--r--node/Peer.cpp117
-rw-r--r--node/Peer.hpp46
-rw-r--r--node/SelfAwareness.cpp22
-rw-r--r--node/SelfAwareness.hpp1
-rw-r--r--node/Switch.cpp22
-rw-r--r--node/Topology.cpp5
-rw-r--r--service/ControlPlane.cpp6
11 files changed, 126 insertions, 143 deletions
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index 583abfe4..0c22ae9d 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -1054,6 +1054,11 @@ typedef struct
uint64_t trustedPathId;
/**
+ * Is path expired?
+ */
+ int expired;
+
+ /**
* Is path preferred?
*/
int preferred;
diff --git a/node/Constants.hpp b/node/Constants.hpp
index ea4c434d..67e6fb58 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -244,17 +244,22 @@
* This is also how often pings will be retried to upstream peers (relays, roots)
* constantly until something is heard.
*/
-#define ZT_PING_CHECK_INVERVAL 9000
+#define ZT_PING_CHECK_INVERVAL 10000
/**
* How frequently to send heartbeats over in-use paths
*/
-#define ZT_PATH_HEARTBEAT_PERIOD 15000
+#define ZT_PATH_HEARTBEAT_PERIOD 10000
/**
* Paths are considered inactive if they have not received traffic in this long
*/
-#define ZT_PATH_ALIVE_TIMEOUT 35000
+#define ZT_PATH_ALIVE_TIMEOUT 25000
+
+/**
+ * Minimum time between attempts to check dead paths to see if they can be re-awakened
+ */
+#define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500
/**
* Delay between full-fledge pings of directly connected peers
@@ -262,11 +267,16 @@
#define ZT_PEER_PING_PERIOD 60000
/**
- * Peers forget paths that have not spoken in this long
+ * Paths are considered expired if they have not produced a real packet in this long
*/
#define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000)
/**
+ * How often to retry expired paths that we're still remembering
+ */
+#define ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD (ZT_PEER_PING_PERIOD * 10)
+
+/**
* Timeout for overall peer activity (measured from last receive)
*/
#define ZT_PEER_ACTIVITY_TIMEOUT 500000
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 3d2d586e..891607ed 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -1163,7 +1163,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
remainingHopsPtr += ZT_ADDRESS_LENGTH;
SharedPtr<Peer> nhp(RR->topology->getPeer(nextHop[h]));
if (nhp) {
- SharedPtr<Path> nhbp(nhp->getBestPath(now));
+ SharedPtr<Path> nhbp(nhp->getBestPath(now,false));
if ((nhbp)&&(nhbp->alive(now)))
nextHopBestPathAddress[h] = nhbp->address();
}
diff --git a/node/Node.cpp b/node/Node.cpp
index a7d4cfa9..edd48575 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -202,14 +202,6 @@ public:
}
}
- if (!upstream) {
- // If I am a root server, only ping other root servers -- roots don't ping "down"
- // since that would just be a waste of bandwidth and could potentially cause route
- // flapping in Cluster mode.
- if (RR->topology->amRoot())
- return;
- }
-
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.
@@ -415,15 +407,16 @@ ZT_PeerList *Node::peers() const
p->latency = pi->second->latency();
p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF;
- std::vector< SharedPtr<Path> > paths(pi->second->paths());
- SharedPtr<Path> bestp(pi->second->getBestPath(_now));
+ std::vector< std::pair< SharedPtr<Path>,bool > > paths(pi->second->paths(_now));
+ SharedPtr<Path> bestp(pi->second->getBestPath(_now,false));
p->pathCount = 0;
- for(std::vector< SharedPtr<Path> >::iterator path(paths.begin());path!=paths.end();++path) {
- memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage));
- p->paths[p->pathCount].lastSend = (*path)->lastOut();
- p->paths[p->pathCount].lastReceive = (*path)->lastIn();
- p->paths[p->pathCount].preferred = (*path == bestp) ? 1 : 0;
- p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address());
+ for(std::vector< std::pair< SharedPtr<Path>,bool > >::iterator path(paths.begin());path!=paths.end();++path) {
+ memcpy(&(p->paths[p->pathCount].address),&(path->first->address()),sizeof(struct sockaddr_storage));
+ p->paths[p->pathCount].lastSend = path->first->lastOut();
+ p->paths[p->pathCount].lastReceive = path->first->lastIn();
+ p->paths[p->pathCount].expired = path->second;
+ p->paths[p->pathCount].preferred = (path->first == bestp) ? 1 : 0;
+ p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address());
++p->pathCount;
}
}
diff --git a/node/Peer.cpp b/node/Peer.cpp
index abbbea72..a2a91769 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -27,6 +27,14 @@
#include "Cluster.hpp"
#include "Packet.hpp"
+#ifndef AF_MAX
+#if AF_INET > AF_INET6
+#define AF_MAX AF_INET
+#else
+#define AF_MAX AF_INET6
+#endif
+#endif
+
namespace ZeroTier {
// Used to send varying values for NAT keepalive
@@ -150,7 +158,7 @@ void Peer::received(
uint64_t worstScore = 0xffffffffffffffffULL;
for(unsigned int p=0;p<_numPaths;++p) {
if (_paths[p].path->address().ss_family == path->address().ss_family) {
- const uint64_t s = _pathScore(p);
+ const uint64_t s = _pathScore(p,now);
if (s < worstScore) {
worstScore = s;
worstSlot = (int)p;
@@ -163,7 +171,7 @@ void Peer::received(
// If we can't find one with the same family, replace the worst of any family
slot = ZT_MAX_PEER_NETWORK_PATHS - 1;
for(unsigned int p=0;p<_numPaths;++p) {
- const uint64_t s = _pathScore(p);
+ const uint64_t s = _pathScore(p,now);
if (s < worstScore) {
worstScore = s;
slot = p;
@@ -210,7 +218,7 @@ bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const
{
Mutex::Lock _l(_paths_m);
for(unsigned int p=0;p<_numPaths;++p) {
- if ( (_paths[p].path->address() == addr) && (_paths[p].path->alive(now)) )
+ if ( (_paths[p].path->address() == addr) && ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) )
return true;
}
return false;
@@ -223,8 +231,8 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE
int bestp = -1;
uint64_t best = 0ULL;
for(unsigned int p=0;p<_numPaths;++p) {
- if (_paths[p].path->alive(now)||(forceEvenIfDead)) {
- const uint64_t s = _pathScore(p);
+ if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)||(forceEvenIfDead)) ) {
+ const uint64_t s = _pathScore(p,now);
if (s >= best) {
best = s;
bestp = (int)p;
@@ -239,17 +247,19 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE
}
}
-SharedPtr<Path> Peer::getBestPath(uint64_t now)
+SharedPtr<Path> Peer::getBestPath(uint64_t now,bool includeExpired)
{
Mutex::Lock _l(_paths_m);
int bestp = -1;
uint64_t best = 0ULL;
for(unsigned int p=0;p<_numPaths;++p) {
- const uint64_t s = _pathScore(p);
- if (s >= best) {
- best = s;
- bestp = (int)p;
+ if ( ((now - _paths[p].lastReceive) < ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) {
+ const uint64_t s = _pathScore(p,now);
+ if (s >= best) {
+ best = s;
+ bestp = (int)p;
+ }
}
}
@@ -283,8 +293,8 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily)
int bestp = -1;
uint64_t best = 0ULL;
for(unsigned int p=0;p<_numPaths;++p) {
- if ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) {
- const uint64_t s = _pathScore(p);
+ if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) ) {
+ const uint64_t s = _pathScore(p,now);
if (s >= best) {
best = s;
bestp = (int)p;
@@ -293,7 +303,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily)
}
if (bestp >= 0) {
- if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) {
+ if ((now - _paths[best].lastReceive) >= ZT_PEER_PING_PERIOD) {
sendHELLO(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now);
} else if (_paths[bestp].path->needsHeartbeat(now)) {
_natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads
@@ -309,39 +319,24 @@ bool Peer::hasActiveDirectPath(uint64_t now) const
{
Mutex::Lock _l(_paths_m);
for(unsigned int p=0;p<_numPaths;++p) {
- if (_paths[p].path->alive(now))
+ if (((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION)&&(_paths[p].path->alive(now)))
return true;
}
return false;
}
-bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now)
+bool Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now)
{
Mutex::Lock _l(_paths_m);
- unsigned int np = _numPaths;
- unsigned int x = 0;
- unsigned int y = 0;
- while (x < np) {
- if (_paths[x].path->address().ipScope() == scope) {
- // Resetting a path means sending a HELLO and then forgetting it. If we
- // get OK(HELLO) then it will be re-learned.
- sendHELLO(_paths[x].path->localAddress(),_paths[x].path->address(),now);
- } else {
- if (x != y) {
- _paths[y].lastReceive = _paths[x].lastReceive;
- _paths[y].path = _paths[x].path;
-#ifdef ZT_ENABLE_CLUSTER
- _paths[y].localClusterSuboptimal = _paths[x].localClusterSuboptimal;
-#endif
- }
- ++y;
+ bool resetSomething = false;
+ for(unsigned int p=0;p<_numPaths;++p) {
+ if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) {
+ sendHELLO(_paths[p].path->localAddress(),_paths[p].path->address(),now);
+ _paths[p].lastReceive >>= 2; // de-prioritize heavily vs. other paths, will get reset if we get OK(HELLO) or other traffic
+ resetSomething = true;
}
- ++x;
}
- _numPaths = y;
- while (y < ZT_MAX_PEER_NETWORK_PATHS)
- _paths[y++].path.zero(); // let go of unused SmartPtr<>'s
- return (_numPaths < np);
+ return resetSomething;
}
void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
@@ -351,17 +346,19 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6)
int bestp4 = -1,bestp6 = -1;
uint64_t best4 = 0ULL,best6 = 0ULL;
for(unsigned int p=0;p<_numPaths;++p) {
- if (_paths[p].path->address().ss_family == AF_INET) {
- const uint64_t s = _pathScore(p);
- if (s >= best4) {
- best4 = s;
- bestp4 = (int)p;
- }
- } else if (_paths[p].path->address().ss_family == AF_INET6) {
- const uint64_t s = _pathScore(p);
- if (s >= best6) {
- best6 = s;
- bestp6 = (int)p;
+ if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) {
+ if (_paths[p].path->address().ss_family == AF_INET) {
+ const uint64_t s = _pathScore(p,now);
+ if (s >= best4) {
+ best4 = s;
+ bestp4 = (int)p;
+ }
+ } else if (_paths[p].path->address().ss_family == AF_INET6) {
+ const uint64_t s = _pathScore(p,now);
+ if (s >= best6) {
+ best6 = s;
+ bestp6 = (int)p;
+ }
}
}
}
@@ -372,30 +369,6 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6)
v6 = _paths[bestp6].path->address();
}
-void Peer::clean(uint64_t now)
-{
- Mutex::Lock _l(_paths_m);
- unsigned int np = _numPaths;
- unsigned int x = 0;
- unsigned int y = 0;
- while (x < np) {
- if ((now - _paths[x].lastReceive) <= ZT_PEER_PATH_EXPIRATION) {
- if (y != x) {
- _paths[y].lastReceive = _paths[x].lastReceive;
- _paths[y].path = _paths[x].path;
-#ifdef ZT_ENABLE_CLUSTER
- _paths[y].localClusterSuboptimal = _paths[x].localClusterSuboptimal;
-#endif
- }
- ++y;
- }
- ++x;
- }
- _numPaths = y;
- while (y < ZT_MAX_PEER_NETWORK_PATHS)
- _paths[y++].path.zero(); // let go of unused SmartPtr<>'s
-}
-
bool Peer::_pushDirectPaths(const SharedPtr<Path> &path,uint64_t now)
{
#ifdef ZT_ENABLE_CLUSTER
diff --git a/node/Peer.hpp b/node/Peer.hpp
index 3ffabb05..6e1d378f 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -149,9 +149,10 @@ public:
* Get the best current direct path
*
* @param now Current time
+ * @param includeDead If true, include even expired paths
* @return Best current path or NULL if none
*/
- SharedPtr<Path> getBestPath(uint64_t now);
+ SharedPtr<Path> getBestPath(uint64_t now,bool includeExpired);
/**
* Send a HELLO to this peer at a specified physical address
@@ -175,18 +176,22 @@ public:
/**
* @param now Current time
- * @return True if this peer has at least one active direct path
+ * @return True if this peer has at least one active and alive direct path
*/
bool hasActiveDirectPath(uint64_t now) const;
/**
- * Reset paths within a given scope
+ * Reset paths within a given IP scope and address family
*
- * @param scope IP scope of paths to reset
+ * Resetting a path involves sending a HELLO to it and then de-prioritizing
+ * it vs. other paths.
+ *
+ * @param scope IP scope
+ * @param inetAddressFamily Family e.g. AF_INET
* @param now Current time
- * @return True if at least one path was forgotten
+ * @return True if we forgot at least one path
*/
- bool resetWithinScope(InetAddress::IpScope scope,uint64_t now);
+ bool resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now);
/**
* Get most recently active path addresses for IPv4 and/or IPv6
@@ -201,21 +206,15 @@ public:
void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const;
/**
- * Perform periodic cleaning operations
- *
* @param now Current time
+ * @return All known direct paths to this peer and whether they are expired (true == expired)
*/
- void clean(uint64_t now);
-
- /**
- * @return All known direct paths to this peer (active or inactive)
- */
- inline std::vector< SharedPtr<Path> > paths() const
+ inline std::vector< std::pair< SharedPtr<Path>,bool > > paths(const uint64_t now) const
{
- std::vector< SharedPtr<Path> > pp;
+ std::vector< std::pair< SharedPtr<Path>,bool > > pp;
Mutex::Lock _l(_paths_m);
for(unsigned int p=0,np=_numPaths;p<np;++p)
- pp.push_back(_paths[p].path);
+ pp.push_back(std::pair< SharedPtr<Path>,bool >(_paths[p].path,(now - _paths[p].lastReceive) > ZT_PEER_PATH_EXPIRATION));
return pp;
}
@@ -370,11 +369,12 @@ public:
private:
bool _pushDirectPaths(const SharedPtr<Path> &path,uint64_t now);
- inline uint64_t _pathScore(const unsigned int p) const
+ inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const
{
- uint64_t s = ZT_PEER_PING_PERIOD;
+ uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK));
+
if (_paths[p].path->address().ss_family == AF_INET) {
- s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast<const struct sockaddr_in *>(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4));
+ s += (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast<const struct sockaddr_in *>(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4));
} else if (_paths[p].path->address().ss_family == AF_INET6) {
uint64_t clusterWeight = ZT_PEER_PING_PERIOD;
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&(_paths[p].path->address()))->sin6_addr.s6_addr);
@@ -384,13 +384,15 @@ private:
break;
}
}
- s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + clusterWeight;
- } else {
- s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK));
+ s += clusterWeight;
}
+
+ s += (ZT_PEER_PING_PERIOD / 2) * (uint64_t)_paths[p].path->alive(now);
+
#ifdef ZT_ENABLE_CLUSTER
s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal;
#endif
+
return s;
}
diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp
index b9ab9d67..6bf50720 100644
--- a/node/SelfAwareness.cpp
+++ b/node/SelfAwareness.cpp
@@ -33,37 +33,31 @@
#include "Switch.hpp"
// Entry timeout -- make it fairly long since this is just to prevent stale buildup
-#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 3600000
+#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000
namespace ZeroTier {
class _ResetWithinScope
{
public:
- _ResetWithinScope(uint64_t now,InetAddress::IpScope scope) :
+ _ResetWithinScope(uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) :
_now(now),
+ _family(inetAddressFamily),
_scope(scope) {}
- inline void operator()(Topology &t,const SharedPtr<Peer> &p)
- {
- if (p->resetWithinScope(_scope,_now))
- peersReset.push_back(p);
- }
+ inline void operator()(Topology &t,const SharedPtr<Peer> &p) { if (p->resetWithinScope(_scope,_family,_now)) peersReset.push_back(p); }
std::vector< SharedPtr<Peer> > peersReset;
private:
uint64_t _now;
+ int _family;
InetAddress::IpScope _scope;
};
SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
RR(renv),
- _phy(32)
-{
-}
-
-SelfAwareness::~SelfAwareness()
+ _phy(128)
{
}
@@ -98,8 +92,8 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLoc
}
}
- // Reset all paths within this scope
- _ResetWithinScope rset(now,(InetAddress::IpScope)scope);
+ // Reset all paths within this scope and address family
+ _ResetWithinScope rset(now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope);
RR->topology->eachPeer<_ResetWithinScope &>(rset);
// Send a NOP to all peers for whom we forgot a path. This will cause direct
diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp
index c7bde87e..4bdafeb2 100644
--- a/node/SelfAwareness.hpp
+++ b/node/SelfAwareness.hpp
@@ -36,7 +36,6 @@ class SelfAwareness
{
public:
SelfAwareness(const RuntimeEnvironment *renv);
- ~SelfAwareness();
/**
* Called when a trusted remote peer informs us of our external network address
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 28a2564b..21d0b3c9 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -747,14 +747,20 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread
bool Switch::_trySend(const Packet &packet,bool encrypt)
{
- SharedPtr<Peer> peer(RR->topology->getPeer(packet.destination()));
-
+ const SharedPtr<Peer> peer(RR->topology->getPeer(packet.destination()));
if (peer) {
const uint64_t now = RR->node->now();
- SharedPtr<Path> viaPath(peer->getBestPath(now));
+ // First get the best path, and if it's dead (and this is not a root)
+ // we attempt to re-activate that path but this packet will flow
+ // upstream. If the path comes back alive, it will be used in the future.
+ // For roots we don't do the alive check since roots are not required
+ // to send heartbeats "down" and because we have to at least try to
+ // go somewhere.
+
+ SharedPtr<Path> viaPath(peer->getBestPath(now,false));
if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isRoot(peer->identity())) ) {
- if ((now - viaPath->lastOut()) > 5000) {
+ if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) >> 2,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ECHO);
outp.armor(peer->key(),true);
viaPath->send(RR,outp.data(),outp.size(),now);
@@ -763,8 +769,10 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
}
if (!viaPath) {
SharedPtr<Peer> relay(RR->topology->getBestRoot());
- if ( (!relay) || (!(viaPath = relay->getBestPath(now))) )
- return false;
+ if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) {
+ if (!(viaPath = peer->getBestPath(now,true)))
+ return false;
+ }
}
Packet tmp(packet);
@@ -787,7 +795,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
unsigned int fragsRemaining = (remaining / (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH));
if ((fragsRemaining * (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining)
++fragsRemaining;
- unsigned int totalFragments = fragsRemaining + 1;
+ const unsigned int totalFragments = fragsRemaining + 1;
for(unsigned int fno=1;fno<totalFragments;++fno) {
chunkSize = std::min(remaining,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH));
diff --git a/node/Topology.cpp b/node/Topology.cpp
index c6d46dc5..6e2fd071 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -256,11 +256,8 @@ void Topology::clean(uint64_t now)
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
while (i.next(a,p)) {
- if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())) {
+ if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()))
_peers.erase(*a);
- } else {
- (*p)->clean(now);
- }
}
}
{
diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp
index a24e3eb4..b443a7fa 100644
--- a/service/ControlPlane.cpp
+++ b/service/ControlPlane.cpp
@@ -183,14 +183,16 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath *
"%s\t\"address\": \"%s\",\n"
"%s\t\"lastSend\": %llu,\n"
"%s\t\"lastReceive\": %llu,\n"
- "%s\t\"active\": true,\n"
+ "%s\t\"active\": %s,\n"
+ "%s\t\"expired\": %s,\n"
"%s\t\"preferred\": %s,\n"
"%s\t\"trustedPathId\": %llu\n"
"%s}",
prefix,_jsonEscape(reinterpret_cast<const InetAddress *>(&(pp[i].address))->toString()).c_str(),
prefix,pp[i].lastSend,
prefix,pp[i].lastReceive,
- prefix,
+ prefix,(pp[i].expired != 0) ? "false" : "true",
+ prefix,(pp[i].expired == 0) ? "false" : "true",
prefix,(pp[i].preferred == 0) ? "false" : "true",
prefix,pp[i].trustedPathId,
prefix);