summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/Hashtable.hpp5
-rw-r--r--node/Switch.cpp38
-rw-r--r--node/Switch.hpp19
3 files changed, 39 insertions, 23 deletions
diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp
index 29c54838..bcc111e3 100644
--- a/node/Hashtable.hpp
+++ b/node/Hashtable.hpp
@@ -39,8 +39,9 @@ namespace ZeroTier {
* A minimal hash table implementation for the ZeroTier core
*
* This is not a drop-in replacement for STL containers, and has several
- * limitations. It's designed to be small and fast for use in the
- * ZeroTier core.
+ * limitations. Keys can be uint64_t or an object, and if the latter they
+ * must implement a method called hashCode() that returns an unsigned long
+ * value that is evenly distributed.
*/
template<typename K,typename V>
class Hashtable
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 7d6f8094..d5ee3e23 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -309,31 +309,18 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
const uint64_t now = RR->node->now();
- std::pair<InetAddress,InetAddress> cg(Peer::findCommonGround(*p1p,*p2p,now));
- if (!(cg.first))
- return false;
-
- if (cg.first.ipScope() != cg.second.ipScope())
- return false;
-
- // Addresses are sorted in key for last unite attempt map for order
- // invariant lookup: (p1,p2) == (p2,p1)
- Array<Address,2> uniteKey;
- if (p1 >= p2) {
- uniteKey[0] = p2;
- uniteKey[1] = p1;
- } else {
- uniteKey[0] = p1;
- uniteKey[1] = p2;
- }
{
Mutex::Lock _l(_lastUniteAttempt_m);
- std::map< Array< Address,2 >,uint64_t >::const_iterator e(_lastUniteAttempt.find(uniteKey));
- if ((!force)&&(e != _lastUniteAttempt.end())&&((now - e->second) < ZT_MIN_UNITE_INTERVAL))
+ uint64_t &luts = _lastUniteAttempt[_LastUniteKey(p1,p2)];
+ if (((now - luts) < ZT_MIN_UNITE_INTERVAL)&&(!force))
return false;
- else _lastUniteAttempt[uniteKey] = now;
+ luts = now;
}
+ std::pair<InetAddress,InetAddress> cg(Peer::findCommonGround(*p1p,*p2p,now));
+ if ((!(cg.first))||(cg.first.ipScope() != cg.second.ipScope()))
+ return false;
+
TRACE("unite: %s(%s) <> %s(%s)",p1.toString().c_str(),cg.second.toString().c_str(),p2.toString().c_str(),cg.first.toString().c_str());
/* Tell P1 where to find P2 and vice versa, sending the packets to P1 and
@@ -543,6 +530,17 @@ unsigned long Switch::doTimerTasks(uint64_t now)
}
}
+ { // Remove really old last unite attempt entries to keep table size controlled
+ Mutex::Lock _l(_lastUniteAttempt_m);
+ Hashtable< _LastUniteKey,uint64_t >::Iterator i(_lastUniteAttempt);
+ _LastUniteKey *k = (_LastUniteKey *)0;
+ uint64_t *v = (uint64_t *)0;
+ while (i.next(k,v)) {
+ if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 16))
+ _lastUniteAttempt.erase(*k);
+ }
+ }
+
return nextDelay;
}
diff --git a/node/Switch.hpp b/node/Switch.hpp
index 0791681f..2d83b70c 100644
--- a/node/Switch.hpp
+++ b/node/Switch.hpp
@@ -235,7 +235,24 @@ private:
Mutex _txQueue_m;
// Tracks sending of VERB_RENDEZVOUS to relaying peers
- std::map< Array< Address,2 >,uint64_t > _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior
+ struct _LastUniteKey
+ {
+ _LastUniteKey() : x(0),y(0) {}
+ _LastUniteKey(const Address &a1,const Address &a2)
+ {
+ if (a1 > a2) {
+ x = a2.toInt();
+ y = a1.toInt();
+ } else {
+ x = a1.toInt();
+ y = a2.toInt();
+ }
+ }
+ inline unsigned long hashCode() const throw() { return ((unsigned long)x ^ (unsigned long)y); }
+ inline bool operator==(const _LastUniteKey &k) const throw() { return ((x == k.x)&&(y == k.y)); }
+ uint64_t x,y;
+ };
+ Hashtable< _LastUniteKey,uint64_t > _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior
Mutex _lastUniteAttempt_m;
// Active attempts to contact remote peers, including state of multi-phase NAT traversal