summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2015-10-16 10:10:12 -0700
committerAdam Ierymenko <adam.ierymenko@gmail.com>2015-10-16 10:10:12 -0700
commit2229e91b57676c1218b550749a2108372e0f37ad (patch)
tree2e3a67578ffc2cb5c3ab4525cbfd014d7ac001d0 /node
parent2debde3451838f62ed9b53d9b0086f7112416636 (diff)
downloadinfinitytier-2229e91b57676c1218b550749a2108372e0f37ad.tar.gz
infinitytier-2229e91b57676c1218b550749a2108372e0f37ad.zip
IPv6 support fixes.
Diffstat (limited to 'node')
-rw-r--r--node/Node.cpp39
-rw-r--r--node/Peer.cpp47
-rw-r--r--node/Peer.hpp8
3 files changed, 69 insertions, 25 deletions
diff --git a/node/Node.cpp b/node/Node.cpp
index d72bc73f..5aa4b7d3 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -186,33 +186,52 @@ public:
inline void operator()(Topology &t,const SharedPtr<Peer> &p)
{
bool upstream = false;
- InetAddress stableEndpoint;
+ InetAddress stableEndpoint4,stableEndpoint6;
+
+ // If this is a world root, pick (if possible) both an IPv4 and an IPv6 stable endpoint to use if link isn't currently alive.
for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
if (r->identity.address() == p->address()) {
- if (r->stableEndpoints.size() > 0)
- stableEndpoint = r->stableEndpoints[(unsigned long)RR->node->prng() % r->stableEndpoints.size()];
upstream = true;
+ for(unsigned long k=0,ptr=RR->node->prng();k<r->stableEndpoints.size();++k) {
+ const InetAddress &addr = r->stableEndpoints[ptr++ % r->stableEndpoints.size()];
+ if (!stableEndpoint4) {
+ if (addr.ss_family == AF_INET)
+ stableEndpoint4 = addr;
+ } else if (!stableEndpoint6) {
+ if (addr.ss_family == AF_INET6)
+ stableEndpoint6 = addr;
+ } else break; // have both!
+ }
break;
}
}
+ // If this is a network preferred relay, also always ping and if a stable endpoint is specified use that if not alive
if (!upstream) {
for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
if (r->first == p->address()) {
- stableEndpoint = r->second;
+ if (r->second.ss_family == AF_INET)
+ stableEndpoint4 = r->second;
+ else if (r->second.ss_family == AF_INET6)
+ stableEndpoint6 = r->second;
upstream = true;
break;
}
}
}
- if ((p->alive(_now))||(upstream)) {
- if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint))
- p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now);
- }
-
- if (upstream)
+ if (upstream) {
+ // "Upstream" devices are roots and relays and get special treatment -- they stay alive
+ // forever and we try to keep (if available) both IPv4 and IPv6 channels open to them.
+ if ((!p->doPingAndKeepalive(RR,_now,AF_INET))&&(stableEndpoint4))
+ p->attemptToContactAt(RR,InetAddress(),stableEndpoint4,_now);
+ if ((!p->doPingAndKeepalive(RR,_now,AF_INET6))&&(stableEndpoint6))
+ p->attemptToContactAt(RR,InetAddress(),stableEndpoint6,_now);
lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream);
+ } else if (p->alive(_now)) {
+ // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently
+ p->doPingAndKeepalive(RR,_now,0);
+ }
}
private:
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 697ba75d..becc77f9 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -179,23 +179,31 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo
RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
}
-RemotePath *Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
+bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily)
{
+ RemotePath *p = (RemotePath *)0;
+
Mutex::Lock _l(_lock);
- RemotePath *const bestPath = _getBestPath(now);
- if (bestPath) {
- if ((now - bestPath->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) {
- TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->lastReceived());
- attemptToContactAt(RR,bestPath->localAddress(),bestPath->address(),now);
- bestPath->sent(now);
- } else if (((now - bestPath->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!bestPath->reliable())) {
- TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->lastReceived());
+ if (inetAddressFamily != 0) {
+ p = _getBestPath(now,inetAddressFamily);
+ } else {
+ p = _getBestPath(now);
+ }
+
+ if (p) {
+ if ((now - p->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) {
+ TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived());
+ attemptToContactAt(RR,p->localAddress(),p->address(),now);
+ p->sent(now);
+ } else if (((now - p->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!p->reliable())) {
+ TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived());
_natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads
- RR->node->putPacket(bestPath->localAddress(),bestPath->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf));
- bestPath->sent(now);
+ RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf));
+ p->sent(now);
}
+ return true;
}
- return bestPath;
+ return false;
}
void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force)
@@ -465,4 +473,19 @@ RemotePath *Peer::_getBestPath(const uint64_t now)
return (RemotePath *)0;
}
+RemotePath *Peer::_getBestPath(const uint64_t now,int inetAddressFamily)
+{
+ // assumes _lock is locked
+ if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL)
+ _sortPaths(now);
+ for(int k=0;k<2;++k) { // try once, and if it fails sort and try one more time
+ for(unsigned int i=0;i<_numPaths;++i) {
+ if ((_paths[i].active(now))&&((int)_paths[i].address().ss_family == inetAddressFamily))
+ return &(_paths[i]);
+ }
+ _sortPaths(now);
+ }
+ return (RemotePath *)0;
+}
+
} // namespace ZeroTier
diff --git a/node/Peer.hpp b/node/Peer.hpp
index 0139f386..4fb399c5 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -130,7 +130,7 @@ public:
Packet::Verb inReVerb = Packet::VERB_NOP);
/**
- * Get the best direct path to this peer
+ * Get the current best direct path to this peer
*
* @param now Current time
* @return Best path or NULL if there are no active direct paths
@@ -178,9 +178,10 @@ public:
*
* @param RR Runtime environment
* @param now Current time
- * @return Current best path or NULL if no active paths
+ * @param inetAddressFamily Keep this address family alive, or 0 to simply pick current best ignoring family
+ * @return True if at least one direct path seems alive
*/
- RemotePath *doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
+ bool doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily);
/**
* Push direct paths if we haven't done so in [rate limit] milliseconds
@@ -559,6 +560,7 @@ public:
private:
void _sortPaths(const uint64_t now);
RemotePath *_getBestPath(const uint64_t now);
+ RemotePath *_getBestPath(const uint64_t now,int inetAddressFamily);
unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized