summaryrefslogtreecommitdiff
path: root/node/Topology.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/Topology.cpp')
-rw-r--r--node/Topology.cpp207
1 files changed, 97 insertions, 110 deletions
diff --git a/node/Topology.cpp b/node/Topology.cpp
index bf51b585..be6807da 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -48,33 +48,22 @@ Topology::Topology(const RuntimeEnvironment *renv) :
_trustedPathCount(0),
_amRoot(false)
{
- // Get cached world if present
- std::string dsWorld(RR->node->dataStoreGet("world"));
- World cachedWorld;
- if (dsWorld.length() > 0) {
- try {
- Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> dswtmp(dsWorld.data(),(unsigned int)dsWorld.length());
- cachedWorld.deserialize(dswtmp,0);
- } catch ( ... ) {
- cachedWorld = World(); // clear if cached world is invalid
- }
- }
-
- // Use default or cached world depending on which is shinier
- World defaultWorld;
+ World defaultPlanet;
{
Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH);
- defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top
+ defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top
}
- if (cachedWorld.shouldBeReplacedBy(defaultWorld,false)) {
- _setWorld(defaultWorld);
- if (dsWorld.length() > 0)
- RR->node->dataStoreDelete("world");
- } else _setWorld(cachedWorld);
-}
+ addWorld(defaultPlanet,false);
-Topology::~Topology()
-{
+ try {
+ World cachedPlanet;
+ std::string buf(RR->node->dataStoreGet("planet"));
+ if (buf.length() > 0) {
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> dswtmp(buf.data(),(unsigned int)buf.length());
+ cachedPlanet.deserialize(dswtmp,0);
+ }
+ addWorld(cachedPlanet,false);
+ } catch ( ... ) {}
}
SharedPtr<Peer> Topology::addPeer(const SharedPtr<Peer> &peer)
@@ -161,15 +150,14 @@ SharedPtr<Peer> Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi
Mutex::Lock _l(_lock);
if (_amRoot) {
- /* If I am a root server, the "best" root server is the one whose address
- * is numerically greater than mine (with wrap at top of list). This
- * causes packets searching for a route to pretty much literally
- * circumnavigate the globe rather than bouncing between just two. */
-
- for(unsigned long p=0;p<_rootAddresses.size();++p) {
- if (_rootAddresses[p] == RR->identity.address()) {
- for(unsigned long q=1;q<_rootAddresses.size();++q) {
- const SharedPtr<Peer> *const nextsn = _peers.get(_rootAddresses[(p + q) % _rootAddresses.size()]);
+ /* If I am a root, pick another root that isn't mine and that
+ * has a numerically greater ID. This causes packets to roam
+ * around the top rather than bouncing between just two. */
+
+ for(unsigned long p=0;p<_upstreamAddresses.size();++p) {
+ if (_upstreamAddresses[p] == RR->identity.address()) {
+ for(unsigned long q=1;q<_upstreamAddresses.size();++q) {
+ const SharedPtr<Peer> *const nextsn = _peers.get(_upstreamAddresses[(p + q) % _upstreamAddresses.size()]);
if ((nextsn)&&((*nextsn)->hasActiveDirectPath(now)))
return *nextsn;
}
@@ -178,8 +166,7 @@ SharedPtr<Peer> Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi
}
} else {
- /* Otherwise pick the best upstream from among roots and any other
- * designated upstreams that we trust. */
+ /* Otherwise pick the bestest looking upstream */
unsigned int bestQualityOverall = ~((unsigned int)0);
unsigned int bestQualityNotAvoid = ~((unsigned int)0);
@@ -219,82 +206,112 @@ SharedPtr<Peer> Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi
return SharedPtr<Peer>();
}
-bool Topology::isRoot(const Identity &id) const
-{
- Mutex::Lock _l(_lock);
- return (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end());
-}
-
bool Topology::isUpstream(const Identity &id) const
{
Mutex::Lock _l(_lock);
return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end());
}
-void Topology::setUpstream(const Address &a,bool upstream)
+ZT_PeerRole Topology::role(const Address &ztaddr) const
{
- bool needWhois = false;
- {
- Mutex::Lock _l(_lock);
- if (std::find(_rootAddresses.begin(),_rootAddresses.end(),a) == _rootAddresses.end()) {
- if (upstream) {
- if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),a) == _upstreamAddresses.end()) {
- _upstreamAddresses.push_back(a);
- const SharedPtr<Peer> *p = _peers.get(a);
- if (!p) {
- const Identity id(_getIdentity(a));
- if (id) {
- _peers.set(a,SharedPtr<Peer>(new Peer(RR,RR->identity,id)));
- } else {
- needWhois = true; // need to do this later due to _lock
- }
- }
- }
- } else {
- std::vector<Address> ua;
- for(std::vector<Address>::iterator i(_upstreamAddresses.begin());i!=_upstreamAddresses.end();++i) {
- if (a != *i)
- ua.push_back(*i);
- }
- _upstreamAddresses.swap(ua);
- }
+ Mutex::Lock _l(_lock);
+ if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
+ for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
+ if (i->identity.address() == ztaddr)
+ return ZT_PEER_ROLE_ROOT;
}
+ return ZT_PEER_ROLE_UPSTREAM;
}
- if (needWhois)
- RR->sw->requestWhois(a);
+ return ZT_PEER_ROLE_LEAF;
}
bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const
{
Mutex::Lock _l(_lock);
- if (std::find(_rootAddresses.begin(),_rootAddresses.end(),ztaddr) != _rootAddresses.end()) {
- for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
+ // For roots the only permitted addresses are those defined. This adds just a little
+ // bit of extra security against spoofing, replaying, etc.
+ if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
+ for(std::vector<World::Root>::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) {
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
if (ipaddr.ipsEqual(*e))
return false;
}
}
+ for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
+ for(std::vector<World::Root>::const_iterator r(m->roots().begin());r!=m->roots().end();++r) {
+ for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
+ if (ipaddr.ipsEqual(*e))
+ return false;
+ }
+ }
+ }
return true;
}
return false;
}
-bool Topology::worldUpdateIfValid(const World &newWorld)
+bool Topology::addWorld(const World &newWorld,bool updateOnly)
{
+ if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON))
+ return false;
+
Mutex::Lock _l(_lock);
- if (_world.shouldBeReplacedBy(newWorld,true)) {
- _setWorld(newWorld);
- try {
- Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> dswtmp;
- newWorld.serialize(dswtmp,false);
- RR->node->dataStorePut("world",dswtmp.data(),dswtmp.size(),false);
- } catch ( ... ) {
- RR->node->dataStoreDelete("world");
+
+ World *existing = (World *)0;
+ switch(newWorld.type()) {
+ case World::TYPE_PLANET:
+ existing = &_planet;
+ break;
+ case World::TYPE_MOON:
+ for(std::vector< World >::iterator m(_moons.begin());m!=_moons.end();++m) {
+ if (m->id() == newWorld.id()) {
+ existing = &(*m);
+ break;
+ }
+ }
+ break;
+ default:
+ return false;
+ }
+
+ if (existing) {
+ if (existing->shouldBeReplacedBy(newWorld))
+ *existing = newWorld;
+ else return false;
+ } else if ((newWorld.type() == World::TYPE_MOON)&&(!updateOnly)) {
+ _moons.push_back(newWorld);
+ existing = &(_moons.back());
+ } else return false;
+
+ char savePath[64];
+ if (existing->type() == World::TYPE_MOON)
+ Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx",existing->id());
+ else Utils::scopy(savePath,sizeof(savePath),"planet");
+ try {
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> dswtmp;
+ existing->serialize(dswtmp,false);
+ RR->node->dataStorePut(savePath,dswtmp.data(),dswtmp.size(),false);
+ } catch ( ... ) {
+ RR->node->dataStoreDelete(savePath);
+ }
+
+ _upstreamAddresses.clear();
+ _amRoot = false;
+ for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
+ if (i->identity == RR->identity)
+ _amRoot = true;
+ else _upstreamAddresses.push_back(i->identity.address());
+ }
+ for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
+ for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) {
+ if (i->identity == RR->identity)
+ _amRoot = true;
+ else _upstreamAddresses.push_back(i->identity.address());
}
- return true;
}
+
return false;
}
@@ -334,34 +351,4 @@ Identity Topology::_getIdentity(const Address &zta)
return Identity();
}
-void Topology::_setWorld(const World &newWorld)
-{
- // assumed _lock is locked (or in constructor)
-
- std::vector<Address> ua;
- for(std::vector<Address>::iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) {
- if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())
- ua.push_back(*a);
- }
-
- _world = newWorld;
- _rootAddresses.clear();
- _amRoot = false;
-
- for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
- _rootAddresses.push_back(r->identity.address());
- if (std::find(ua.begin(),ua.end(),r->identity.address()) == ua.end())
- ua.push_back(r->identity.address());
- if (r->identity.address() == RR->identity.address()) {
- _amRoot = true;
- } else {
- SharedPtr<Peer> *rp = _peers.get(r->identity.address());
- if (!rp)
- _peers.set(r->identity.address(),SharedPtr<Peer>(new Peer(RR,RR->identity,r->identity)));
- }
- }
-
- _upstreamAddresses.swap(ua);
-}
-
} // namespace ZeroTier