diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2015-10-16 10:10:12 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2015-10-16 10:10:12 -0700 |
commit | 2229e91b57676c1218b550749a2108372e0f37ad (patch) | |
tree | 2e3a67578ffc2cb5c3ab4525cbfd014d7ac001d0 /node | |
parent | 2debde3451838f62ed9b53d9b0086f7112416636 (diff) | |
download | infinitytier-2229e91b57676c1218b550749a2108372e0f37ad.tar.gz infinitytier-2229e91b57676c1218b550749a2108372e0f37ad.zip |
IPv6 support fixes.
Diffstat (limited to 'node')
-rw-r--r-- | node/Node.cpp | 39 | ||||
-rw-r--r-- | node/Peer.cpp | 47 | ||||
-rw-r--r-- | node/Peer.hpp | 8 |
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 |