From d04e5a1fe01f1d1c732a1c2d138d2a417f4dbbfb Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 3 Feb 2014 11:09:09 -0800 Subject: [PATCH] Add a simple but very nice mechanism for avoiding potentially dead supernodes. --- node/Constants.hpp | 5 +++++ node/Topology.cpp | 27 +++++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index e64fec1c0..241fb7429 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -304,6 +304,11 @@ error_no_byte_order_defined; */ #define ZT_PEER_LINK_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 2) + 1000) +/** + * Stop relaying via peers that have not responded to direct sends in this long + */ +#define ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD 10000 + /** * Number of outgoing verb/packetId pairs to keep for sends expecting responses */ diff --git a/node/Topology.cpp b/node/Topology.cpp index b499063cf..b3748da63 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -134,19 +134,31 @@ void Topology::saveIdentity(const Identity &id) SharedPtr Topology::getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid) const { SharedPtr bestSupernode; - unsigned int bestSupernodeLatency = 0xffff; + unsigned int bestSupernodeLatency = 65536; uint64_t now = Utils::now(); Mutex::Lock _l(_supernodes_m); - if (_supernodePeers.empty()) - return bestSupernode; - + // First look for a best supernode by comparing latencies, but exclude + // supernodes that have not responded to direct messages in order to + // try to exclude any that are dead or unreachable. for(std::vector< SharedPtr >::const_iterator sn=_supernodePeers.begin();sn!=_supernodePeers.end();) { + // Skip explicitly avoided relays for(unsigned int i=0;iaddress()) - goto skip_and_try_next_supernode; + if (avoid[i] == (*sn)->address()) { + ++sn; + continue; + } } + + // Skip possibly comatose or unreachable relays + uint64_t lds = (*sn)->lastDirectSend(); + uint64_t ldr = (*sn)->lastDirectReceive(); + if ((lds)&&(ldr > lds)&&((lds - ldr) > ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD)) { + ++sn; + continue; + } + if ((*sn)->hasActiveDirectPath(now)) { unsigned int l = (*sn)->latency(); if (bestSupernode) { @@ -160,8 +172,6 @@ SharedPtr Topology::getBestSupernode(const Address *avoid,unsigned int avo bestSupernode = *sn; } } -skip_and_try_next_supernode: - ++sn; } if (bestSupernode) { @@ -170,6 +180,7 @@ skip_and_try_next_supernode: } else if (strictAvoid) return SharedPtr(); + // If we have nothing from above, just pick one without avoidance criteria. for(std::vector< SharedPtr >::const_iterator sn=_supernodePeers.begin();sn!=_supernodePeers.end();++sn) { if ((*sn)->hasActiveDirectPath(now)) { unsigned int l = (*sn)->latency();