diff options
Diffstat (limited to 'node/Topology.cpp')
-rw-r--r-- | node/Topology.cpp | 119 |
1 files changed, 73 insertions, 46 deletions
diff --git a/node/Topology.cpp b/node/Topology.cpp index 109cbca2..183ee06a 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -161,65 +161,92 @@ void Topology::saveIdentity(const Identity &id) SharedPtr<Peer> Topology::getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid) const { SharedPtr<Peer> bestSupernode; - unsigned int l,bestSupernodeLatency = 65536; uint64_t now = Utils::now(); - uint64_t lds,ldr; - Mutex::Lock _l(_supernodes_m); - // 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<Peer> >::const_iterator sn(_supernodePeers.begin());sn!=_supernodePeers.end();) { - // Skip explicitly avoided relays - for(unsigned int i=0;i<avoidCount;++i) { - if (avoid[i] == (*sn)->address()) - goto keep_searching_for_supernodes; + if (_amSupernode) { + /* If I am a supernode, the "best" supernode is the one whose address + * is numerically greater than mine (with wrap at top of list). This + * causes packets searching for a route to pretty much literally + * circumnavigate the globe rather than bouncing between just two. */ + + if (_supernodeAddresses.size() > 1) { // gotta be one other than me for this to work + std::set<Address>::const_iterator sna(_supernodeAddresses.find(_r->identity.address())); + if (sna != _supernodeAddresses.end()) { // sanity check -- _amSupernode should've been false in this case + for(;;) { + if (++sna == _supernodeAddresses.end()) + sna = _supernodeAddresses.begin(); // wrap around at end + if (*sna != _r->identity.address()) { // pick one other than us -- starting from me+1 in sorted set order + SharedPtr<Peer> p(getPeer(*sna)); + if ((p)&&(p->hasActiveDirectPath(now))) { + bestSupernode = p; + break; + } + } + } + } } + } else { + /* If I am not a supernode, the best supernode is the active one with + * the lowest latency. */ + + unsigned int l,bestSupernodeLatency = 65536; + uint64_t lds,ldr; + + // 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<Peer> >::const_iterator sn(_supernodePeers.begin());sn!=_supernodePeers.end();) { + // Skip explicitly avoided relays + for(unsigned int i=0;i<avoidCount;++i) { + if (avoid[i] == (*sn)->address()) + goto keep_searching_for_supernodes; + } + + // Skip possibly comatose or unreachable relays + lds = (*sn)->lastDirectSend(); + ldr = (*sn)->lastDirectReceive(); + if ((lds)&&(lds > ldr)&&((lds - ldr) > ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD)) + goto keep_searching_for_supernodes; - // Skip possibly comatose or unreachable relays - lds = (*sn)->lastDirectSend(); - ldr = (*sn)->lastDirectReceive(); - if ((lds)&&(lds > ldr)&&((lds - ldr) > ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD)) - goto keep_searching_for_supernodes; - - if ((*sn)->hasActiveDirectPath(now)) { - l = (*sn)->latency(); - if (bestSupernode) { - if ((l)&&(l < bestSupernodeLatency)) { - bestSupernodeLatency = l; + if ((*sn)->hasActiveDirectPath(now)) { + l = (*sn)->latency(); + if (bestSupernode) { + if ((l)&&(l < bestSupernodeLatency)) { + bestSupernodeLatency = l; + bestSupernode = *sn; + } + } else { + if (l) + bestSupernodeLatency = l; bestSupernode = *sn; } - } else { - if (l) - bestSupernodeLatency = l; - bestSupernode = *sn; } - } keep_searching_for_supernodes: - ++sn; - } - - if (bestSupernode) { - bestSupernode->use(now); - return bestSupernode; - } else if (strictAvoid) - return SharedPtr<Peer>(); + ++sn; + } - // If we have nothing from above, just pick one without avoidance criteria. - for(std::vector< SharedPtr<Peer> >::const_iterator sn=_supernodePeers.begin();sn!=_supernodePeers.end();++sn) { - if ((*sn)->hasActiveDirectPath(now)) { - unsigned int l = (*sn)->latency(); - if (bestSupernode) { - if ((l)&&(l < bestSupernodeLatency)) { - bestSupernodeLatency = l; + if (bestSupernode) { + bestSupernode->use(now); + return bestSupernode; + } else if (strictAvoid) + return SharedPtr<Peer>(); + + // If we have nothing from above, just pick one without avoidance criteria. + for(std::vector< SharedPtr<Peer> >::const_iterator sn=_supernodePeers.begin();sn!=_supernodePeers.end();++sn) { + if ((*sn)->hasActiveDirectPath(now)) { + unsigned int l = (*sn)->latency(); + if (bestSupernode) { + if ((l)&&(l < bestSupernodeLatency)) { + bestSupernodeLatency = l; + bestSupernode = *sn; + } + } else { + if (l) + bestSupernodeLatency = l; bestSupernode = *sn; } - } else { - if (l) - bestSupernodeLatency = l; - bestSupernode = *sn; } } } |