Add TCP channel support for supernode list, make Peer pick the first path if all paths are equally dead.

This commit is contained in:
Adam Ierymenko 2014-03-26 15:35:15 -07:00
parent 73c1d43f2f
commit daaec84c6b
7 changed files with 46 additions and 38 deletions

View File

@ -43,11 +43,11 @@ namespace ZeroTier {
const Defaults ZT_DEFAULTS; const Defaults ZT_DEFAULTS;
static inline std::map< Identity,std::vector<InetAddress> > _mkSupernodeMap() static inline std::map< Identity,std::vector< std::pair<InetAddress,bool> > > _mkSupernodeMap()
{ {
std::map< Identity,std::vector<InetAddress> > sn; std::map< Identity,std::vector< std::pair<InetAddress,bool> > > sn;
Identity id; Identity id;
std::vector<InetAddress> addrs; std::vector< std::pair<InetAddress,bool> > addrs;
// Nothing special about a supernode... except that they are // Nothing special about a supernode... except that they are
// designated as such and trusted to provide WHOIS lookup. // designated as such and trusted to provide WHOIS lookup.
@ -56,35 +56,36 @@ static inline std::map< Identity,std::vector<InetAddress> > _mkSupernodeMap()
addrs.clear(); addrs.clear();
if (!id.fromString("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5")) if (!id.fromString("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"))
throw std::runtime_error("invalid identity in Defaults"); throw std::runtime_error("invalid identity in Defaults");
addrs.push_back(InetAddress("162.243.77.111",ZT_DEFAULT_PORT)); addrs.push_back(std::pair<InetAddress,bool>(InetAddress("162.243.77.111",ZT_DEFAULT_PORT),false));
addrs.push_back(std::pair<InetAddress,bool>(InetAddress("162.243.77.111",443),true));
sn[id] = addrs; sn[id] = addrs;
// nyarlathotep.zerotier.com - San Francisco, California, USA // nyarlathotep.zerotier.com - San Francisco, California, USA
addrs.clear(); addrs.clear();
if (!id.fromString("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa")) if (!id.fromString("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"))
throw std::runtime_error("invalid identity in Defaults"); throw std::runtime_error("invalid identity in Defaults");
addrs.push_back(InetAddress("198.199.97.220",ZT_DEFAULT_PORT)); addrs.push_back(std::pair<InetAddress,bool>(InetAddress("198.199.97.220",ZT_DEFAULT_PORT),false));
sn[id] = addrs; sn[id] = addrs;
// shub-niggurath.zerotier.com - Amsterdam, Netherlands // shub-niggurath.zerotier.com - Amsterdam, Netherlands
addrs.clear(); addrs.clear();
if (!id.fromString("36f63d6574:0:67a776487a1a99b32f413329f2b67c43fbf6152e42c6b66e89043e69d93e48314c7d709b58a83016bd2612dd89400b856e18c553da94892f7d3ca16bf2c92c24")) if (!id.fromString("36f63d6574:0:67a776487a1a99b32f413329f2b67c43fbf6152e42c6b66e89043e69d93e48314c7d709b58a83016bd2612dd89400b856e18c553da94892f7d3ca16bf2c92c24"))
throw std::runtime_error("invalid identity in Defaults"); throw std::runtime_error("invalid identity in Defaults");
addrs.push_back(InetAddress("198.211.127.172",ZT_DEFAULT_PORT)); addrs.push_back(std::pair<InetAddress,bool>(InetAddress("198.211.127.172",ZT_DEFAULT_PORT),false));
sn[id] = addrs; sn[id] = addrs;
// mi-go.zerotier.com - Singapore // mi-go.zerotier.com - Singapore
addrs.clear(); addrs.clear();
if (!id.fromString("abbb7f4622:0:89d2c6b2062b10f4ce314dfcb914c082566247090a6f74c8ba1c15c63b205f540758f0abae85287397152c9d8cf463cfe51e7a480946cd6a31495b24ca13253c")) if (!id.fromString("abbb7f4622:0:89d2c6b2062b10f4ce314dfcb914c082566247090a6f74c8ba1c15c63b205f540758f0abae85287397152c9d8cf463cfe51e7a480946cd6a31495b24ca13253c"))
throw std::runtime_error("invalid identity in Defaults"); throw std::runtime_error("invalid identity in Defaults");
addrs.push_back(InetAddress("128.199.254.204",ZT_DEFAULT_PORT)); addrs.push_back(std::pair<InetAddress,bool>(InetAddress("128.199.254.204",ZT_DEFAULT_PORT),false));
sn[id] = addrs; sn[id] = addrs;
// shoggoth.zerotier.com - Tokyo, Japan // shoggoth.zerotier.com - Tokyo, Japan
addrs.clear(); addrs.clear();
if (!id.fromString("48e8f875cb:0:5ca54f55e1094f65589f3e6d74158b6964d418ddac3570757128f1c6a2498322d92fcdcd47de459f4d1f9b38df2afd0c7b3fc247ba3d773c38ba35288f24988e")) if (!id.fromString("48e8f875cb:0:5ca54f55e1094f65589f3e6d74158b6964d418ddac3570757128f1c6a2498322d92fcdcd47de459f4d1f9b38df2afd0c7b3fc247ba3d773c38ba35288f24988e"))
throw std::runtime_error("invalid identity in Defaults"); throw std::runtime_error("invalid identity in Defaults");
addrs.push_back(InetAddress("108.61.200.101",ZT_DEFAULT_PORT)); addrs.push_back(std::pair<InetAddress,bool>(InetAddress("108.61.200.101",ZT_DEFAULT_PORT),false));
sn[id] = addrs; sn[id] = addrs;
return sn; return sn;

View File

@ -64,9 +64,9 @@ public:
const std::string defaultHomePath; const std::string defaultHomePath;
/** /**
* Supernodes on the ZeroTier network * Supernodes on the ZeroTier network (identity, address/tcp?)
*/ */
const std::map< Identity,std::vector<InetAddress> > supernodes; const std::map< Identity,std::vector< std::pair<InetAddress,bool> > > supernodes;
/** /**
* Identities permitted to sign software updates * Identities permitted to sign software updates

View File

@ -91,6 +91,7 @@ void Peer::receive(
} }
// Announce multicast LIKEs to peers to whom we have a direct link // Announce multicast LIKEs to peers to whom we have a direct link
// Lock can't be locked here or it'll recurse and deadlock.
if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) {
_lastAnnouncedTo = now; _lastAnnouncedTo = now;
_r->sw->announceMulticastGroups(SharedPtr<Peer>(this)); _r->sw->announceMulticastGroups(SharedPtr<Peer>(this));
@ -107,12 +108,14 @@ bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,u
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
if (_paths.empty()) std::vector<Path>::iterator p(_paths.begin());
if (p == _paths.end()) {
TRACE("send to %s failed: no paths available",_id.address().toString().c_str());
return false; return false;
}
uint64_t bestPathLastReceived = 0; uint64_t bestPathLastReceived = p->lastReceived();
std::vector<Path>::iterator bestPath; std::vector<Path>::iterator bestPath = p;
for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) { while (++p != _paths.end()) {
uint64_t lr = p->lastReceived(); uint64_t lr = p->lastReceived();
if (lr >= bestPathLastReceived) { if (lr >= bestPathLastReceived) {
bestPathLastReceived = lr; bestPathLastReceived = lr;
@ -120,6 +123,8 @@ bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,u
} }
} }
TRACE("send to %s: using path: %s",_id.address().toString().c_str(),bestPath->toString().c_str());
if (_r->sm->send(bestPath->address(),bestPath->tcp(),data,len)) { if (_r->sm->send(bestPath->address(),bestPath->tcp(),data,len)) {
bestPath->sent(now); bestPath->sent(now);
return true; return true;
@ -147,19 +152,22 @@ bool Peer::sendPing(const RuntimeEnvironment *_r,uint64_t now,bool firstSinceRes
SharedPtr<Peer> self(this); SharedPtr<Peer> self(this);
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
bool allPingsUnanswered; bool pingTcp;
if (!firstSinceReset) { if (!firstSinceReset) {
allPingsUnanswered = true; // Do not use TCP if one of our UDP endpoints has answered recently.
pingTcp = true;
for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) { for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
if (!p->pingUnanswered(now)) { if (!p->pingUnanswered(now)) {
allPingsUnanswered = false; pingTcp = false;
break; break;
} }
} }
} else allPingsUnanswered = false; } else pingTcp = false;
TRACE("PING %s (pingTcp==%d)",_id.address().toString().c_str(),(int)pingTcp);
for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) { for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
if ((allPingsUnanswered)||(!p->tcp())) { if ((pingTcp)||(!p->tcp())) {
if (_r->sw->sendHELLO(self,p->address(),p->tcp())) { if (_r->sw->sendHELLO(self,p->address(),p->tcp())) {
p->sent(now); p->sent(now);
p->pinged(now); p->pinged(now);

View File

@ -752,13 +752,13 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
} }
} }
#ifdef ZT_TRACE /* #ifdef ZT_TRACE
if (via != peer) { if (via != peer) {
TRACE(">> %s to %s via %s (%d)",Packet::verbString(packet.verb()),peer->address().toString().c_str(),via->address().toString().c_str(),(int)packet.size()); TRACE(">> %s to %s via %s (%d)",Packet::verbString(packet.verb()),peer->address().toString().c_str(),via->address().toString().c_str(),(int)packet.size());
} else { } else {
TRACE(">> %s to %s (%d)",Packet::verbString(packet.verb()),peer->address().toString().c_str(),(int)packet.size()); TRACE(">> %s to %s (%d)",Packet::verbString(packet.verb()),peer->address().toString().c_str(),(int)packet.size());
} }
#endif #endif */
return true; return true;
} }

View File

@ -50,7 +50,7 @@ Topology::~Topology()
_dumpPeers(); _dumpPeers();
} }
void Topology::setSupernodes(const std::map< Identity,std::vector<InetAddress> > &sn) void Topology::setSupernodes(const std::map< Identity,std::vector< std::pair<InetAddress,bool> > > &sn)
{ {
Mutex::Lock _l(_supernodes_m); Mutex::Lock _l(_supernodes_m);
@ -59,14 +59,13 @@ void Topology::setSupernodes(const std::map< Identity,std::vector<InetAddress> >
_supernodePeers.clear(); _supernodePeers.clear();
uint64_t now = Utils::now(); uint64_t now = Utils::now();
for(std::map< Identity,std::vector<InetAddress> >::const_iterator i(sn.begin());i!=sn.end();++i) { for(std::map< Identity,std::vector< std::pair<InetAddress,bool> > >::const_iterator i(sn.begin());i!=sn.end();++i) {
if (i->first != _r->identity) { if (i->first != _r->identity) {
SharedPtr<Peer> p(getPeer(i->first.address())); SharedPtr<Peer> p(getPeer(i->first.address()));
if (!p) if (!p)
p = addPeer(SharedPtr<Peer>(new Peer(_r->identity,i->first))); p = addPeer(SharedPtr<Peer>(new Peer(_r->identity,i->first)));
for(std::vector<InetAddress>::const_iterator j(i->second.begin());j!=i->second.end();++j) { for(std::vector< std::pair<InetAddress,bool> >::const_iterator j(i->second.begin());j!=i->second.end();++j)
p->addPath(Path(*j,false,true)); p->addPath(Path(j->first,j->second,true));
}
p->use(now); p->use(now);
_supernodePeers.push_back(p); _supernodePeers.push_back(p);
} }

View File

@ -63,7 +63,7 @@ public:
* *
* @param sn Supernodes for this network * @param sn Supernodes for this network
*/ */
void setSupernodes(const std::map< Identity,std::vector<InetAddress> > &sn); void setSupernodes(const std::map< Identity,std::vector< std::pair<InetAddress,bool> > > &sn);
/** /**
* Add a peer to database * Add a peer to database
@ -103,15 +103,6 @@ public:
*/ */
void saveIdentity(const Identity &id); void saveIdentity(const Identity &id);
/**
* @return Current network supernodes
*/
inline std::map< Identity,std::vector<InetAddress> > supernodes() const
{
Mutex::Lock _l(_supernodes_m);
return _supernodes;
}
/** /**
* @return Vector of peers that are supernodes * @return Vector of peers that are supernodes
*/ */
@ -313,7 +304,7 @@ private:
std::map< Address,SharedPtr<Peer> > _activePeers; std::map< Address,SharedPtr<Peer> > _activePeers;
Mutex _activePeers_m; Mutex _activePeers_m;
std::map< Identity,std::vector<InetAddress> > _supernodes; std::map< Identity,std::vector< std::pair<InetAddress,bool> > > _supernodes;
std::set< Address > _supernodeAddresses; std::set< Address > _supernodeAddresses;
std::vector< SharedPtr<Peer> > _supernodePeers; std::vector< SharedPtr<Peer> > _supernodePeers;
Mutex _supernodes_m; Mutex _supernodes_m;

View File

@ -48,6 +48,9 @@
#include <signal.h> #include <signal.h>
#endif #endif
// Uncomment to intentionally break UDP in order to test TCP fallback
#define ZT_BREAK_UDP
namespace ZeroTier { namespace ZeroTier {
UdpSocket::~UdpSocket() UdpSocket::~UdpSocket()
@ -66,6 +69,9 @@ bool UdpSocket::send(const InetAddress &to,const void *msg,unsigned int msglen)
bool UdpSocket::sendWithHopLimit(const InetAddress &to,const void *msg,unsigned int msglen,int hopLimit) bool UdpSocket::sendWithHopLimit(const InetAddress &to,const void *msg,unsigned int msglen,int hopLimit)
{ {
#ifdef ZT_BREAK_UDP
return true;
#else
if (hopLimit <= 0) if (hopLimit <= 0)
hopLimit = 255; hopLimit = 255;
if (to.isV6()) { if (to.isV6()) {
@ -87,6 +93,7 @@ bool UdpSocket::sendWithHopLimit(const InetAddress &to,const void *msg,unsigned
return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen); return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen);
#endif #endif
} }
#endif
} }
bool UdpSocket::notifyAvailableForRead(const SharedPtr<Socket> &self,SocketManager *sm) bool UdpSocket::notifyAvailableForRead(const SharedPtr<Socket> &self,SocketManager *sm)
@ -97,7 +104,9 @@ bool UdpSocket::notifyAvailableForRead(const SharedPtr<Socket> &self,SocketManag
int n = (int)recvfrom(_sock,(char *)(buf.data()),ZT_SOCKET_MAX_MESSAGE_LEN,0,from.saddr(),&salen); int n = (int)recvfrom(_sock,(char *)(buf.data()),ZT_SOCKET_MAX_MESSAGE_LEN,0,from.saddr(),&salen);
if (n > 0) { if (n > 0) {
buf.setSize((unsigned int)n); buf.setSize((unsigned int)n);
#ifndef ZT_BREAK_UDP
sm->handleReceivedPacket(self,from,buf); sm->handleReceivedPacket(self,from,buf);
#endif
} }
return true; return true;
} }