|
@@ -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;
|
|
|
}
|
|
|
}
|
|
|
}
|