summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/Peer.hpp26
-rw-r--r--node/Switch.cpp7
-rw-r--r--node/Topology.cpp37
3 files changed, 44 insertions, 26 deletions
diff --git a/node/Peer.hpp b/node/Peer.hpp
index ad4c6746..a70d9868 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -236,15 +236,33 @@ public:
inline uint64_t activelyTransferringFrames(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); }
/**
- * @return Current latency or 0 if unknown (max: 65535)
+ * @return Latency in milliseconds or 0 if unknown
*/
- inline unsigned int latency() const
- throw()
+ inline unsigned int latency() const { return _latency; }
+
+ /**
+ * This computes a quality score for relays and root servers
+ *
+ * If we haven't heard anything from these in ZT_PEER_ACTIVITY_TIMEOUT, they
+ * receive the worst possible quality (max unsigned int). Otherwise the
+ * quality is a product of latency and the number of potential missed
+ * pings. This causes roots and relays to switch over a bit faster if they
+ * fail.
+ *
+ * @return Relay quality score computed from latency and other factors, lower is better
+ */
+ inline unsigned int relayQuality(const uint64_t now) const
{
+ const uint64_t tsr = now - _lastReceive;
+ if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT)
+ return (~(unsigned int)0);
unsigned int l = _latency;
- return std::min(l,(unsigned int)65535);
+ if (!l)
+ l = 0xffff;
+ return (l * (((unsigned int)tsr / (ZT_PEER_DIRECT_PING_DELAY + 1000)) + 1));
}
+
/**
* Update latency with a new direct measurment
*
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 120ce7a4..b7a9c522 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -741,12 +741,15 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid)
if (!viaPath) {
// See if this network has a preferred relay (if packet has an associated network)
if (nconf) {
- unsigned int latency = ~((unsigned int)0);
+ unsigned int bestq = ~((unsigned int)0);
for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(nconf->relays().begin());r!=nconf->relays().end();++r) {
if (r->first != peer->address()) {
SharedPtr<Peer> rp(RR->topology->getPeer(r->first));
- if ((rp)&&(rp->hasActiveDirectPath(now))&&(rp->latency() <= latency))
+ const unsigned int q = rp->relayQuality(now);
+ if ((rp)&&(q < bestq)) { // SUBTILE: < == don't use these if they are nil quality (unsigned int max), instead use a root
+ bestq = q;
rp.swap(relay);
+ }
}
}
}
diff --git a/node/Topology.cpp b/node/Topology.cpp
index b8bb55f2..bea97ab9 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -227,33 +227,30 @@ SharedPtr<Peer> Topology::getBestRoot(const Address *avoid,unsigned int avoidCou
} else {
/* If I am not a root server, the best root server is the active one with
- * the lowest latency. */
+ * the lowest quality score. (lower == better) */
- unsigned int bestLatencyOverall = ~((unsigned int)0);
- unsigned int bestLatencyNotAvoid = ~((unsigned int)0);
+ unsigned int bestQualityOverall = ~((unsigned int)0);
+ unsigned int bestQualityNotAvoid = ~((unsigned int)0);
const SharedPtr<Peer> *bestOverall = (const SharedPtr<Peer> *)0;
const SharedPtr<Peer> *bestNotAvoid = (const SharedPtr<Peer> *)0;
for(std::vector< SharedPtr<Peer> >::const_iterator r(_rootPeers.begin());r!=_rootPeers.end();++r) {
- if ((*r)->hasActiveDirectPath(now)) {
- bool avoiding = false;
- for(unsigned int i=0;i<avoidCount;++i) {
- if (avoid[i] == (*r)->address()) {
- avoiding = true;
- break;
- }
- }
- unsigned int l = (*r)->latency();
- if (!l) l = ~l; // zero latency indicates no measurment, so make this 'max'
- if (l <= bestLatencyOverall) {
- bestLatencyOverall = l;
- bestOverall = &(*r);
- }
- if ((!avoiding)&&(l <= bestLatencyNotAvoid)) {
- bestLatencyNotAvoid = l;
- bestNotAvoid = &(*r);
+ bool avoiding = false;
+ for(unsigned int i=0;i<avoidCount;++i) {
+ if (avoid[i] == (*r)->address()) {
+ avoiding = true;
+ break;
}
}
+ const unsigned int q = (*r)->relayQuality(now);
+ if (q <= bestQualityOverall) {
+ bestQualityOverall = q;
+ bestOverall = &(*r);
+ }
+ if ((!avoiding)&&(q <= bestQualityNotAvoid)) {
+ bestQualityNotAvoid = q;
+ bestNotAvoid = &(*r);
+ }
}
if (bestNotAvoid) {