diff --git a/node/Cluster.cpp b/node/Cluster.cpp index ef09e8423..75a9f29b0 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -516,10 +516,10 @@ void Cluster::broadcastNetworkConfigChunk(const void *chunk,unsigned int len) } } -int Cluster::prepSendViaCluster(const Address &toPeerAddress,void *peerSecret) +int Cluster::prepSendViaCluster(const Address &toPeerAddress,uint64_t &mostRecentTs,void *peerSecret) { const uint64_t now = RR->node->now(); - uint64_t mostRecentTs = 0; + mostRecentTs = 0; int mostRecentMemberId = -1; { Mutex::Lock _l2(_remotePeers_m); diff --git a/node/Cluster.hpp b/node/Cluster.hpp index 90ea3e7d4..72fcd04d9 100644 --- a/node/Cluster.hpp +++ b/node/Cluster.hpp @@ -285,10 +285,11 @@ public: * Note that outp is only armored (or modified at all) if the return value is a member ID. * * @param toPeerAddress Value of outp.destination(), simply to save additional lookup - * @param peerSecret Buffer to fill with peer secret on valid return value, must be at least ZT_PEER_SECRET_KEY_LENGTH bytes + * @param ts Result: set to time of last HAVE_PEER from the cluster + * @param peerSecret Result: Buffer to fill with peer secret on valid return value, must be at least ZT_PEER_SECRET_KEY_LENGTH bytes * @return -1 if cluster does not know this peer, or a member ID to pass to sendViaCluster() */ - int prepSendViaCluster(const Address &toPeerAddress,void *peerSecret); + int prepSendViaCluster(const Address &toPeerAddress,uint64_t &mostRecentTs,void *peerSecret); /** * Send data via cluster front plane (packet head or fragment) diff --git a/node/Switch.cpp b/node/Switch.cpp index 6185037df..1d9f64367 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -692,6 +692,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) const uint64_t now = RR->node->now(); const Address destination(packet.destination()); #ifdef ZT_ENABLE_CLUSTER + uint64_t clusterMostRecentTs = 0; int clusterMostRecentMemberId = -1; uint8_t clusterPeerSecret[ZT_PEER_SECRET_KEY_LENGTH]; #endif @@ -713,25 +714,31 @@ bool Switch::_trySend(Packet &packet,bool encrypt) } if (!viaPath) { -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - clusterMostRecentMemberId = RR->cluster->prepSendViaCluster(destination,clusterPeerSecret); - if (clusterMostRecentMemberId < 0) { -#endif - peer->tryMemorizedPath(now); // periodically attempt memorized or statically defined paths, if any are known - const SharedPtr relay(RR->topology->getUpstreamPeer()); - if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { - if (!(viaPath = peer->getBestPath(now,true))) // last resort: try an expired path... we usually can never get here - return false; - } -#ifdef ZT_ENABLE_CLUSTER - } -#endif + const SharedPtr relay(RR->topology->getUpstreamPeer()); + if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) + viaPath = peer->getBestPath(now,true); } + +#ifdef ZT_ENABLE_CLUSTER + if (RR->cluster) + clusterMostRecentMemberId = RR->cluster->prepSendViaCluster(destination,clusterMostRecentTs,clusterPeerSecret); + if (clusterMostRecentMemberId >= 0) { + if ((viaPath)&&(viaPath->lastIn() < clusterMostRecentTs)) + viaPath.zero(); + } else if (!viaPath) { + peer->tryMemorizedPath(now); // periodically attempt memorized or statically defined paths, if any are known + return false; + } +#else + if (!viaPath) { + peer->tryMemorizedPath(now); // periodically attempt memorized or statically defined paths, if any are known + return false; + } +#endif } else { #ifdef ZT_ENABLE_CLUSTER if (RR->cluster) - clusterMostRecentMemberId = RR->cluster->prepSendViaCluster(destination,clusterPeerSecret); + clusterMostRecentMemberId = RR->cluster->prepSendViaCluster(destination,clusterMostRecentTs,clusterPeerSecret); if (clusterMostRecentMemberId < 0) { #else requestWhois(destination); @@ -742,6 +749,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) #endif } + // Sanity checks #ifdef ZT_ENABLE_CLUSTER if ((!viaPath)&&(clusterMostRecentMemberId < 0)) return false;