Slight refactor to RENEDEZVOUS sending code for federation.

This commit is contained in:
Adam Ierymenko 2017-02-03 23:54:02 -08:00
parent 8a2ff0b31e
commit dcb1233b0d
5 changed files with 72 additions and 109 deletions

View File

@ -400,7 +400,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len)
SharedPtr<Peer> localPeer(RR->topology->getPeerNoCache(localPeerAddress));
if ((localPeer)&&(numRemotePeerPaths > 0)) {
InetAddress bestLocalV4,bestLocalV6;
localPeer->getBestActiveAddresses(now,bestLocalV4,bestLocalV6);
localPeer->getRendezvousAddresses(now,bestLocalV4,bestLocalV6);
InetAddress bestRemoteV4,bestRemoteV6;
for(unsigned int i=0;i<numRemotePeerPaths;++i) {
@ -652,7 +652,7 @@ void Cluster::relayViaCluster(const Address &fromPeerAddress,const Address &toPe
if (fromPeerAddress) {
SharedPtr<Peer> fromPeer(RR->topology->getPeerNoCache(fromPeerAddress));
if (fromPeer)
fromPeer->getBestActiveAddresses(now,v4,v6);
fromPeer->getRendezvousAddresses(now,v4,v6);
}
uint8_t addrCount = 0;
if (v4)

View File

@ -446,7 +446,7 @@ void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin
}
}
void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
void Peer::getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
{
Mutex::Lock _l(_paths_m);

View File

@ -208,7 +208,7 @@ public:
* @param v4 Result parameter to receive active IPv4 address, if any
* @param v6 Result parameter to receive active IPv6 address, if any
*/
void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const;
void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const;
/**
* @param now Current time

View File

@ -64,10 +64,6 @@ Switch::Switch(const RuntimeEnvironment *renv) :
{
}
Switch::~Switch()
{
}
void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len)
{
try {
@ -221,7 +217,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from
if (packet.hops() < ZT_RELAY_MAX_HOPS) {
#ifdef ZT_ENABLE_CLUSTER
if (source != RR->identity.address())
if (source != RR->identity.address()) // don't increment hops for cluster frontplane relays
packet.incrementHops();
#else
packet.incrementHops();
@ -229,13 +225,74 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from
SharedPtr<Peer> relayTo = RR->topology->getPeer(destination);
if ((relayTo)&&((relayTo->sendDirect(packet.data(),packet.size(),now,false)))) {
if (source != RR->identity.address()) {
Mutex::Lock _l(_lastUniteAttempt_m);
uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)];
if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) {
luts = now;
_unite(source,destination);
if (source != RR->identity.address()) { // don't send RENDEZVOUS for cluster frontplane relays
bool shouldUnite;
{
Mutex::Lock _l(_lastUniteAttempt_m);
uint64_t &lastUniteAt = _lastUniteAttempt[_LastUniteKey(source,destination)];
shouldUnite = ((now - lastUniteAt) >= ZT_MIN_UNITE_INTERVAL);
if (shouldUnite)
lastUniteAt = now;
}
if (shouldUnite) {
const InetAddress *hintToSource = (InetAddress *)0;
const InetAddress *hintToDest = (InetAddress *)0;
InetAddress destV4,destV6;
InetAddress sourceV4,sourceV6;
relayTo->getRendezvousAddresses(now,destV4,destV6);
const SharedPtr<Peer> sourcePeer(RR->topology->getPeer(source));
if (sourcePeer) {
sourcePeer->getRendezvousAddresses(now,sourceV4,sourceV6);
if ((destV6)&&(sourceV6)) {
hintToSource = &destV6;
hintToDest = &sourceV6;
} else if ((destV4)&&(sourceV4)) {
hintToSource = &destV4;
hintToDest = &sourceV4;
}
if ((hintToSource)&&(hintToDest)) {
TRACE(">> RENDEZVOUS: %s(%s) <> %s(%s)",p1.toString().c_str(),p1a->toString().c_str(),p2.toString().c_str(),p2a->toString().c_str());
unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for obscure NAT-t reasons
const unsigned int completed = alt + 2;
while (alt != completed) {
if ((alt & 1) == 0) {
Packet outp(source,RR->identity.address(),Packet::VERB_RENDEZVOUS);
outp.append((uint8_t)0);
destination.appendTo(outp);
outp.append((uint16_t)hintToSource->port());
if (hintToSource->ss_family == AF_INET6) {
outp.append((uint8_t)16);
outp.append(hintToSource->rawIpData(),16);
} else {
outp.append((uint8_t)4);
outp.append(hintToSource->rawIpData(),4);
}
send(outp,true);
} else {
Packet outp(destination,RR->identity.address(),Packet::VERB_RENDEZVOUS);
outp.append((uint8_t)0);
source.appendTo(outp);
outp.append((uint16_t)hintToDest->port());
if (hintToDest->ss_family == AF_INET6) {
outp.append((uint8_t)16);
outp.append(hintToDest->rawIpData(),16);
} else {
outp.append((uint8_t)4);
outp.append(hintToDest->rawIpData(),4);
}
send(outp,true);
}
++alt;
}
}
}
}
}
} else {
#ifdef ZT_ENABLE_CLUSTER
@ -824,96 +881,4 @@ bool Switch::_trySend(Packet &packet,bool encrypt)
return true;
}
bool Switch::_unite(const Address &p1,const Address &p2)
{
if ((p1 == RR->identity.address())||(p2 == RR->identity.address()))
return false;
const uint64_t now = RR->node->now();
InetAddress *p1a = (InetAddress *)0;
InetAddress *p2a = (InetAddress *)0;
InetAddress p1v4,p1v6,p2v4,p2v6,uv4,uv6;
{
const SharedPtr<Peer> p1p(RR->topology->getPeer(p1));
const SharedPtr<Peer> p2p(RR->topology->getPeer(p2));
if ((!p1p)&&(!p2p)) return false;
if (p1p) p1p->getBestActiveAddresses(now,p1v4,p1v6);
if (p2p) p2p->getBestActiveAddresses(now,p2v4,p2v6);
}
if ((p1v6)&&(p2v6)) {
p1a = &p1v6;
p2a = &p2v6;
} else if ((p1v4)&&(p2v4)) {
p1a = &p1v4;
p2a = &p2v4;
} else {
SharedPtr<Peer> upstream(RR->topology->getUpstreamPeer());
if (!upstream)
return false;
upstream->getBestActiveAddresses(now,uv4,uv6);
if ((p1v6)&&(uv6)) {
p1a = &p1v6;
p2a = &uv6;
} else if ((p1v4)&&(uv4)) {
p1a = &p1v4;
p2a = &uv4;
} else if ((p2v6)&&(uv6)) {
p1a = &p2v6;
p2a = &uv6;
} else if ((p2v4)&&(uv4)) {
p1a = &p2v4;
p2a = &uv4;
} else return false;
}
TRACE("unite: %s(%s) <> %s(%s)",p1.toString().c_str(),p1a->toString().c_str(),p2.toString().c_str(),p2a->toString().c_str());
/* Tell P1 where to find P2 and vice versa, sending the packets to P1 and
* P2 in randomized order in terms of which gets sent first. This is done
* since in a few cases NAT-t can be sensitive to slight timing differences
* in terms of when the two peers initiate. Normally this is accounted for
* by the nearly-simultaneous RENDEZVOUS kickoff from the relay, but
* given that relay are hosted on cloud providers this can in some
* cases have a few ms of latency between packet departures. By randomizing
* the order we make each attempted NAT-t favor one or the other going
* first, meaning if it doesn't succeed the first time it might the second
* and so forth. */
unsigned int alt = (unsigned int)RR->node->prng() & 1;
const unsigned int completed = alt + 2;
while (alt != completed) {
if ((alt & 1) == 0) {
// Tell p1 where to find p2.
Packet outp(p1,RR->identity.address(),Packet::VERB_RENDEZVOUS);
outp.append((unsigned char)0);
p2.appendTo(outp);
outp.append((uint16_t)p2a->port());
if (p2a->isV6()) {
outp.append((unsigned char)16);
outp.append(p2a->rawIpData(),16);
} else {
outp.append((unsigned char)4);
outp.append(p2a->rawIpData(),4);
}
send(outp,true);
} else {
// Tell p2 where to find p1.
Packet outp(p2,RR->identity.address(),Packet::VERB_RENDEZVOUS);
outp.append((unsigned char)0);
p1.appendTo(outp);
outp.append((uint16_t)p1a->port());
if (p1a->isV6()) {
outp.append((unsigned char)16);
outp.append(p1a->rawIpData(),16);
} else {
outp.append((unsigned char)4);
outp.append(p1a->rawIpData(),4);
}
send(outp,true);
}
++alt; // counts up and also flips LSB
}
return true;
}
} // namespace ZeroTier

View File

@ -55,7 +55,6 @@ class Switch : NonCopyable
{
public:
Switch(const RuntimeEnvironment *renv);
~Switch();
/**
* Called when a packet is received from the real network
@ -127,7 +126,6 @@ public:
private:
Address _sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted);
bool _trySend(Packet &packet,bool encrypt); // packet is modified if return is true
bool _unite(const Address &p1,const Address &p2);
const RuntimeEnvironment *const RR;
uint64_t _lastBeaconResponse;