diff options
| author | Grant Limberg <grant.limberg@zerotier.com> | 2016-11-18 14:00:25 -0800 |
|---|---|---|
| committer | Grant Limberg <grant.limberg@zerotier.com> | 2016-11-18 14:00:25 -0800 |
| commit | 2231e878d5470d86f4c6543cc708dc78661da462 (patch) | |
| tree | 0bcd8215684b0091d7bd8856f75b4e433edef71e /node/Switch.cpp | |
| parent | 299a7cab200c0af4743ab36d41994fd7a582f900 (diff) | |
| parent | 673c0c811ea443c217b3a4ca17eeaed3ab596501 (diff) | |
| download | infinitytier-2231e878d5470d86f4c6543cc708dc78661da462.tar.gz infinitytier-2231e878d5470d86f4c6543cc708dc78661da462.zip | |
Merge branch 'dev' into systemtray
Diffstat (limited to 'node/Switch.cpp')
| -rw-r--r-- | node/Switch.cpp | 173 |
1 files changed, 98 insertions, 75 deletions
diff --git a/node/Switch.cpp b/node/Switch.cpp index 82b13483..a5dd57e4 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -131,8 +131,8 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from } #endif - // Don't know peer or no direct path -- so relay via root server - relayTo = RR->topology->getBestRoot(); + // Don't know peer or no direct path -- so relay via someone upstream + relayTo = RR->topology->getUpstreamPeer(); if (relayTo) relayTo->sendDirect(fragment.data(),fragment.size(),now,true); } @@ -237,7 +237,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)]; if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) { luts = now; - unite(source,destination); + _unite(source,destination); } } else { #ifdef ZT_ENABLE_CLUSTER @@ -254,7 +254,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from return; } #endif - relayTo = RR->topology->getBestRoot(&source,1,true); + relayTo = RR->topology->getUpstreamPeer(&source,1,true); if (relayTo) relayTo->sendDirect(packet.data(),packet.size(),now,true); } @@ -590,75 +590,6 @@ void Switch::send(const Packet &packet,bool encrypt) } } -bool Switch::unite(const Address &p1,const Address &p2) -{ - if ((p1 == RR->identity.address())||(p2 == RR->identity.address())) - return false; - SharedPtr<Peer> p1p = RR->topology->getPeer(p1); - if (!p1p) - return false; - SharedPtr<Peer> p2p = RR->topology->getPeer(p2); - if (!p2p) - return false; - - const uint64_t now = RR->node->now(); - - std::pair<InetAddress,InetAddress> cg(Peer::findCommonGround(*p1p,*p2p,now)); - if ((!(cg.first))||(cg.first.ipScope() != cg.second.ipScope())) - return false; - - TRACE("unite: %s(%s) <> %s(%s)",p1.toString().c_str(),cg.second.toString().c_str(),p2.toString().c_str(),cg.first.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; - 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)cg.first.port()); - if (cg.first.isV6()) { - outp.append((unsigned char)16); - outp.append(cg.first.rawIpData(),16); - } else { - outp.append((unsigned char)4); - outp.append(cg.first.rawIpData(),4); - } - outp.armor(p1p->key(),true); - p1p->sendDirect(outp.data(),outp.size(),now,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)cg.second.port()); - if (cg.second.isV6()) { - outp.append((unsigned char)16); - outp.append(cg.second.rawIpData(),16); - } else { - outp.append((unsigned char)4); - outp.append(cg.second.rawIpData(),4); - } - outp.armor(p2p->key(),true); - p2p->sendDirect(outp.data(),outp.size(),now,true); - } - ++alt; // counts up and also flips LSB - } - - return true; -} - void Switch::requestWhois(const Address &addr) { bool inserted = false; @@ -763,7 +694,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) { - SharedPtr<Peer> upstream(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); + SharedPtr<Peer> upstream(RR->topology->getUpstreamPeer(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); if (upstream) { Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); @@ -793,7 +724,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) viaPath.zero(); } if (!viaPath) { - SharedPtr<Peer> relay(RR->topology->getBestRoot()); + SharedPtr<Peer> relay(RR->topology->getUpstreamPeer()); if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { if (!(viaPath = peer->getBestPath(now,true))) return false; @@ -839,4 +770,96 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) return false; } +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 |
