diff options
-rw-r--r-- | node/Constants.hpp | 2 | ||||
-rw-r--r-- | node/IncomingPacket.cpp | 32 | ||||
-rw-r--r-- | node/Node.cpp | 18 | ||||
-rw-r--r-- | node/Peer.cpp | 273 | ||||
-rw-r--r-- | node/Peer.hpp | 119 | ||||
-rw-r--r-- | node/Topology.hpp | 4 |
6 files changed, 182 insertions, 266 deletions
diff --git a/node/Constants.hpp b/node/Constants.hpp index 410a245b..93184efa 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -289,7 +289,7 @@ #define ZT_PEER_PING_PERIOD 60000 /** - * Paths are considered expired if they have not produced a real packet in this long + * Paths are considered expired if they have not sent us a real packet in this long */ #define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 52794fd7..a0f5ee1d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1200,16 +1200,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt switch(addrType) { case 4: { - InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4)); - - bool redundant = false; - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimal(a); - } else { - redundant = peer->hasActivePathTo(now,a); - } - - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { + const InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4)); + if ( + ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + { if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); @@ -1219,16 +1215,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt } } break; case 6: { - InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16)); - - bool redundant = false; - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimal(a); - } else { - redundant = peer->hasActivePathTo(now,a); - } - - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { + const InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16)); + if ( + ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + { if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); diff --git a/node/Node.cpp b/node/Node.cpp index 9844b09e..1bc96cca 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -407,17 +407,17 @@ ZT_PeerList *Node::peers() const p->latency = pi->second->latency(); p->role = RR->topology->role(pi->second->identity().address()); - std::vector< std::pair< SharedPtr<Path>,bool > > paths(pi->second->paths(_now)); + std::vector< SharedPtr<Path> > paths(pi->second->paths(_now)); SharedPtr<Path> bestp(pi->second->getBestPath(_now,false)); p->pathCount = 0; - for(std::vector< std::pair< SharedPtr<Path>,bool > >::iterator path(paths.begin());path!=paths.end();++path) { - memcpy(&(p->paths[p->pathCount].address),&(path->first->address()),sizeof(struct sockaddr_storage)); - p->paths[p->pathCount].lastSend = path->first->lastOut(); - p->paths[p->pathCount].lastReceive = path->first->lastIn(); - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address()); - p->paths[p->pathCount].linkQuality = (int)path->first->linkQuality(); - p->paths[p->pathCount].expired = path->second; - p->paths[p->pathCount].preferred = (path->first == bestp) ? 1 : 0; + for(std::vector< SharedPtr<Path> >::iterator path(paths.begin());path!=paths.end();++path) { + memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage)); + p->paths[p->pathCount].lastSend = (*path)->lastOut(); + p->paths[p->pathCount].lastReceive = (*path)->lastIn(); + p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); + p->paths[p->pathCount].linkQuality = (int)(*path)->linkQuality(); + p->paths[p->pathCount].expired = 0; + p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0; ++p->pathCount; } } diff --git a/node/Peer.cpp b/node/Peer.cpp index 0795a6ea..2711dd19 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -27,14 +27,6 @@ #include "Cluster.hpp" #include "Packet.hpp" -#ifndef AF_MAX -#if AF_INET > AF_INET6 -#define AF_MAX AF_INET -#else -#define AF_MAX AF_INET6 -#endif -#endif - namespace ZeroTier { Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : @@ -51,18 +43,15 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), - _remoteClusterOptimal4(0), _vProto(0), _vMajor(0), _vMinor(0), _vRevision(0), _id(peerIdentity), - _numPaths(0), _latency(0), _directPathPushCutoffCount(0), _credentialsCutoffCount(0) { - memset(_remoteClusterOptimal6,0,sizeof(_remoteClusterOptimal6)); if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) throw std::runtime_error("new peer identity key agreement failed"); } @@ -80,7 +69,7 @@ void Peer::received( const uint64_t now = RR->node->now(); #ifdef ZT_ENABLE_CLUSTER - bool suboptimalPath = false; + bool isClusterSuboptimalPath = false; if ((RR->cluster)&&(hops == 0)) { // Note: findBetterEndpoint() is first since we still want to check // for a better endpoint even if we don't actually send a redirect. @@ -146,65 +135,60 @@ void Peer::received( path->updateLinkQuality((unsigned int)(packetId & 7)); if (hops == 0) { - bool pathIsConfirmed = false; + bool pathAlreadyKnown = false; { Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address() == path->address()) { - _paths[p].lastReceive = now; - _paths[p].path = path; // local address may have changed! + if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) { + const struct sockaddr_in *const r = reinterpret_cast<const struct sockaddr_in *>(&(path->address())); + const struct sockaddr_in *const l = reinterpret_cast<const struct sockaddr_in *>(&(_v4Path.p->address())); + const struct sockaddr_in *const rl = reinterpret_cast<const struct sockaddr_in *>(&(path->localAddress())); + const struct sockaddr_in *const ll = reinterpret_cast<const struct sockaddr_in *>(&(_v4Path.p->localAddress())); + if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(rl->sin_addr.s_addr == ll->sin_addr.s_addr)&&(rl->sin_port == ll->sin_port)) { + _v4Path.lr = now; #ifdef ZT_ENABLE_CLUSTER - _paths[p].localClusterSuboptimal = suboptimalPath; + _v4Path.localClusterSuboptimal = isClusterSuboptimalPath; #endif - pathIsConfirmed = true; - break; + pathAlreadyKnown = true; + } + } else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) { + const struct sockaddr_in6 *const r = reinterpret_cast<const struct sockaddr_in6 *>(&(path->address())); + const struct sockaddr_in6 *const l = reinterpret_cast<const struct sockaddr_in6 *>(&(_v6Path.p->address())); + const struct sockaddr_in6 *const rl = reinterpret_cast<const struct sockaddr_in6 *>(&(path->localAddress())); + const struct sockaddr_in6 *const ll = reinterpret_cast<const struct sockaddr_in6 *>(&(_v6Path.p->localAddress())); + if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(!memcmp(rl->sin6_addr.s6_addr,ll->sin6_addr.s6_addr,16))&&(rl->sin6_port == ll->sin6_port)) { + _v6Path.lr = now; +#ifdef ZT_ENABLE_CLUSTER + _v6Path.localClusterSuboptimal = isClusterSuboptimalPath; +#endif + pathAlreadyKnown = true; } } } - if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { + if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); - - // Since this is a new path, figure out where to put it (possibly replacing an old/dead one) - unsigned int slot; - if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { - slot = _numPaths++; - } else { - // First try to replace the worst within the same address family, if possible - int worstSlot = -1; - uint64_t worstScore = 0xffffffffffffffffULL; - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address().ss_family == path->address().ss_family) { - const uint64_t s = _pathScore(p,now); - if (s < worstScore) { - worstScore = s; - worstSlot = (int)p; - } - } - } - if (worstSlot >= 0) { - slot = (unsigned int)worstSlot; - } else { - // If we can't find one with the same family, replace the worst of any family - slot = ZT_MAX_PEER_NETWORK_PATHS - 1; - for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p,now); - if (s < worstScore) { - worstScore = s; - slot = p; - } - } + if (path->address().ss_family == AF_INET) { + if ((!_v4Path.p)||(!_v4Path.p->alive(now))||(path->preferenceRank() >= _v4Path.p->preferenceRank())) { + _v4Path.lr = now; + _v4Path.p = path; +#ifdef ZT_ENABLE_CLUSTER + _v4Path.localClusterSuboptimal = isClusterSuboptimalPath; + if (RR->cluster) + RR->cluster->broadcastHavePeer(_id); +#endif } - } - - _paths[slot].lastReceive = now; - _paths[slot].path = path; + } else if (path->address().ss_family == AF_INET6) { + if ((!_v6Path.p)||(!_v6Path.p->alive(now))||(path->preferenceRank() >= _v6Path.p->preferenceRank())) { + _v6Path.lr = now; + _v6Path.p = path; #ifdef ZT_ENABLE_CLUSTER - _paths[slot].localClusterSuboptimal = suboptimalPath; - if (RR->cluster) - RR->cluster->broadcastHavePeer(_id); + _v6Path.localClusterSuboptimal = isClusterSuboptimalPath; + if (RR->cluster) + RR->cluster->broadcastHavePeer(_id); #endif + } + } } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); @@ -214,10 +198,10 @@ void Peer::received( } else if (this->trustEstablished(now)) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) #ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - const bool haveCluster = (RR->cluster); + // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection + const bool haveCluster = (RR->cluster); #else - const bool haveCluster = false; + const bool haveCluster = false; #endif if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) { _lastDirectPathPushSent = now; @@ -290,60 +274,50 @@ void Peer::received( } } -bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address() == addr) && ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) - return true; - } - return false; -} - -bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) +bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force) { Mutex::Lock _l(_paths_m); - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)||(forceEvenIfDead)) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; - } + uint64_t v6lr = 0; + if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) + v6lr = _v6Path.p->lastIn(); + uint64_t v4lr = 0; + if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) + v4lr = _v4Path.p->lastIn(); + + if ( (v6lr > v4lr) && ((now - v6lr) < ZT_PATH_ALIVE_TIMEOUT) ) { + return _v6Path.p->send(RR,tPtr,data,len,now); + } else if ((now - v4lr) < ZT_PATH_ALIVE_TIMEOUT) { + return _v4Path.p->send(RR,tPtr,data,len,now); + } else if (force) { + if (v6lr > v4lr) { + return _v6Path.p->send(RR,tPtr,data,len,now); + } else if (v4lr) { + return _v4Path.p->send(RR,tPtr,data,len,now); } } - if (bestp >= 0) { - return _paths[bestp].path->send(RR,tPtr,data,len,now); - } else { - return false; - } + return false; } SharedPtr<Path> Peer::getBestPath(uint64_t now,bool includeExpired) { Mutex::Lock _l(_paths_m); - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; - } - } + uint64_t v6lr = 0; + if ( ( includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v6Path.p) ) + v6lr = _v6Path.p->lastIn(); + uint64_t v4lr = 0; + if ( ( includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v4Path.p) ) + v4lr = _v4Path.p->lastIn(); + + if (v6lr > v4lr) { + return _v6Path.p; + } else if (v4lr) { + return _v4Path.p; } - if (bestp >= 0) { - return _paths[bestp].path; - } else { - return SharedPtr<Path>(); - } + return SharedPtr<Path>(); } void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) @@ -420,79 +394,44 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; + if (inetAddressFamily < 0) { + uint64_t v6lr = 0; + if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) + v6lr = _v6Path.p->lastIn(); + uint64_t v4lr = 0; + if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) + v4lr = _v4Path.p->lastIn(); + + if (v6lr > v4lr) { + if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + _v6Path.p->sent(now); + return true; + } + } else if (v4lr) { + if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + _v4Path.p->sent(now); + return true; } } - } - - if (bestp >= 0) { - if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); - _paths[bestp].path->sent(now); - } - return true; } else { - return false; - } -} - -bool Peer::hasActiveDirectPath(uint64_t now) const -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if (((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION)&&(_paths[p].path->alive(now))) - return true; - } - return false; -} - -void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(tPtr,_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); - _paths[p].path->sent(now); - _paths[p].lastReceive = 0; // path will not be used unless it speaks again - } - } -} - -void Peer::getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const -{ - Mutex::Lock _l(_paths_m); - - int bestp4 = -1,bestp6 = -1; - uint64_t best4 = 0ULL,best6 = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) { - if (_paths[p].path->address().ss_family == AF_INET) { - const uint64_t s = _pathScore(p,now); - if (s >= best4) { - best4 = s; - bestp4 = (int)p; - } - } else if (_paths[p].path->address().ss_family == AF_INET6) { - const uint64_t s = _pathScore(p,now); - if (s >= best6) { - best6 = s; - bestp6 = (int)p; - } + if ( (inetAddressFamily == AF_INET) && ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { + if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + _v4Path.p->sent(now); + return true; + } + } else if ( (inetAddressFamily == AF_INET6) && ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { + if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + _v6Path.p->sent(now); + return true; } } } - if (bestp4 >= 0) - v4 = _paths[bestp4].path->address(); - if (bestp6 >= 0) - v6 = _paths[bestp6].path->address(); + return false; } } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 41836410..f225eb85 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -108,20 +108,10 @@ public: * @param addr Remote address * @return True if we have an active path to this destination */ - bool hasActivePathTo(uint64_t now,const InetAddress &addr) const; - - /** - * Set which known path for an address family is optimal - * - * @param addr Address to make exclusive - */ - inline void setClusterOptimal(const InetAddress &addr) + inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const { - if (addr.ss_family == AF_INET) { - _remoteClusterOptimal4 = (uint32_t)reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_addr.s_addr; - } else if (addr.ss_family == AF_INET6) { - memcpy(_remoteClusterOptimal6,reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_addr.s6_addr,16); - } + Mutex::Lock _l(_paths_m); + return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) ); } /** @@ -131,14 +121,17 @@ public: * @param data Packet data * @param len Packet length * @param now Current time - * @param forceEvenIfDead If true, send even if the path is not 'alive' + * @param force If true, send even if path is not alive * @return True if we actually sent something */ - bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); + bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force); /** * Get the best current direct path * + * This does not check Path::alive(), but does return the most recently + * active path and does check expiration (which is a longer timeout). + * * @param now Current time * @param includeExpired If true, include even expired paths * @return Best current path or NULL if none @@ -193,12 +186,6 @@ public: bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); /** - * @param now Current time - * @return True if this peer has at least one active and alive direct path - */ - bool hasActiveDirectPath(uint64_t now) const; - - /** * Reset paths within a given IP scope and address family * * Resetting a path involves sending an ECHO to it and then deactivating @@ -209,30 +196,48 @@ public: * @param inetAddressFamily Family e.g. AF_INET * @param now Current time */ - void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); + inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) + { + Mutex::Lock _l(_paths_m); + if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) { + attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + _v4Path.p->sent(now); + _v4Path.lr = 0; // path will not be used unless it speaks again + } else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) { + attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + _v6Path.p->sent(now); + _v6Path.lr = 0; // path will not be used unless it speaks again + } + } /** - * Get most recently active path addresses for IPv4 and/or IPv6 - * - * Note that v4 and v6 are not modified if they are not found, so - * initialize these to a NULL address to be able to check. + * Fill parameters with V4 and V6 addresses if known and alive * * @param now Current time * @param v4 Result parameter to receive active IPv4 address, if any * @param v6 Result parameter to receive active IPv6 address, if any */ - void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; + inline void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const + { + Mutex::Lock _l(_paths_m); + if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) + v4 = _v4Path.p->address(); + if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) + v6 = _v6Path.p->address(); + } /** * @param now Current time - * @return All known direct paths to this peer and whether they are expired (true == expired) + * @return All known paths to this peer */ - inline std::vector< std::pair< SharedPtr<Path>,bool > > paths(const uint64_t now) const + inline std::vector< SharedPtr<Path> > paths(const uint64_t now) const { - std::vector< std::pair< SharedPtr<Path>,bool > > pp; + std::vector< SharedPtr<Path> > pp; Mutex::Lock _l(_paths_m); - for(unsigned int p=0,np=_numPaths;p<np;++p) - pp.push_back(std::pair< SharedPtr<Path>,bool >(_paths[p].path,(now - _paths[p].lastReceive) > ZT_PEER_PATH_EXPIRATION)); + if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) + pp.push_back(_v4Path.p); + if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) + pp.push_back(_v6Path.p); return pp; } @@ -424,32 +429,19 @@ public: } private: - inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const + struct _PeerPath { - uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); - - if (_paths[p].path->address().ss_family == AF_INET) { - s += (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast<const struct sockaddr_in *>(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4)); - } else if (_paths[p].path->address().ss_family == AF_INET6) { - uint64_t clusterWeight = ZT_PEER_PING_PERIOD; - const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&(_paths[p].path->address()))->sin6_addr.s6_addr); - for(long i=0;i<16;++i) { - if (a[i] != _remoteClusterOptimal6[i]) { - clusterWeight = 0; - break; - } - } - s += clusterWeight; - } - - s += (ZT_PEER_PING_PERIOD / 2) * (uint64_t)_paths[p].path->alive(now); - #ifdef ZT_ENABLE_CLUSTER - s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal; + _PeerPath() : lr(0),p(),localClusterSuboptimal(false) {} +#else + _PeerPath() : lr(0),p() {} #endif - - return s; - } + uint64_t lr; // time of last valid ZeroTier packet + SharedPtr<Path> p; +#ifdef ZT_ENABLE_CLUSTER + bool localClusterSuboptimal; // true if our cluster has determined that we should not be serving this peer +#endif + }; uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; @@ -468,26 +460,17 @@ private: uint64_t _lastCredentialsReceived; uint64_t _lastTrustEstablishedPacketReceived; - uint8_t _remoteClusterOptimal6[16]; - uint32_t _remoteClusterOptimal4; - uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; uint16_t _vRevision; - Identity _id; - - struct { - uint64_t lastReceive; - SharedPtr<Path> path; -#ifdef ZT_ENABLE_CLUSTER - bool localClusterSuboptimal; -#endif - } _paths[ZT_MAX_PEER_NETWORK_PATHS]; + _PeerPath _v4Path; // IPv4 direct path + _PeerPath _v6Path; // IPv6 direct path Mutex _paths_m; - unsigned int _numPaths; + Identity _id; + unsigned int _latency; unsigned int _directPathPushCutoffCount; unsigned int _credentialsCutoffCount; diff --git a/node/Topology.hpp b/node/Topology.hpp index 4870ab5e..d29c424e 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -314,7 +314,9 @@ public: Address *a = (Address *)0; SharedPtr<Peer> *p = (SharedPtr<Peer> *)0; while (i.next(a,p)) { - cnt += (unsigned long)((*p)->hasActiveDirectPath(now)); + const SharedPtr<Path> pp((*p)->getBestPath(now,false)); + if ((pp)&&(pp->alive(now))) + ++cnt; } return cnt; } |