A bunch more refactoring to rip out obsolete stuff related to old root system and general cleanup.

This commit is contained in:
Adam Ierymenko 2019-08-15 10:49:50 -07:00
parent b23d551d00
commit 521d371b5d
No known key found for this signature in database
GPG Key ID: 1657198823E52A61
19 changed files with 653 additions and 165 deletions

152
attic/MulticastGroup.hpp Normal file
View File

@ -0,0 +1,152 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#ifndef ZT_MULTICASTGROUP_HPP
#define ZT_MULTICASTGROUP_HPP
#include <stdint.h>
#include "Constants.hpp"
#include "MAC.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
namespace ZeroTier {
/**
* A multicast group composed of a multicast MAC and a 32-bit ADI field
*
* ADI stands for additional distinguishing information. ADI is primarily for
* adding additional information to broadcast (ff:ff:ff:ff:ff:ff) memberships,
* since straight-up broadcast won't scale. Right now it's zero except for
* IPv4 ARP, where it holds the IPv4 address itself to make ARP into a
* selective multicast query that can scale.
*
* In the future we might add some kind of plugin architecture that can add
* ADI for things like mDNS (multicast DNS) to improve the selectivity of
* those protocols.
*
* MulticastGroup behaves as an immutable value object.
*/
class MulticastGroup
{
public:
inline MulticastGroup() :
_mac(),
_adi(0)
{
}
inline MulticastGroup(const MAC &m,uint32_t a) :
_mac(m),
_adi(a)
{
}
/**
* Derive the multicast group used for address resolution (ARP/NDP) for an IP
*
* @param ip IP address (port field is ignored)
* @return Multicast group for ARP/NDP
*/
static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip)
{
if (ip.isV4()) {
// IPv4 wants broadcast MACs, so we shove the V4 address itself into
// the Multicast Group ADI field. Making V4 ARP work is basically why
// ADI was added, as well as handling other things that want mindless
// Ethernet broadcast to all.
return MulticastGroup(MAC(0xffffffffffffULL),Utils::ntoh(*((const uint32_t *)ip.rawIpData())));
} else if (ip.isV6()) {
// IPv6 is better designed in this respect. We can compute the IPv6
// multicast address directly from the IP address, and it gives us
// 24 bits of uniqueness. Collisions aren't likely to be common enough
// to care about.
const unsigned char *a = (const unsigned char *)ip.rawIpData();
return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0);
}
return MulticastGroup();
}
/**
* @return Multicast address
*/
inline const MAC &mac() const { return _mac; }
/**
* @return Additional distinguishing information
*/
inline uint32_t adi() const { return _adi; }
/**
* Compute a 32-bit randomized identifier for this group
*
* This is a 32-bit fnv1a hash of the MAC and ADI. It's part of the protocol as it's
* used to generate unique identifiers for multicast groups for multicast lookup, so
* don't change it lightly.
*/
inline uint32_t id32() const
{
uint32_t h = 0x811c9dc5;
const uint64_t m = _mac.toInt();
const uint32_t p = 0x1000193;
h ^= (uint32_t)(m >> 40) & 0xff; h *= p;
h ^= (uint32_t)(m >> 32) & 0xff; h *= p;
h ^= (uint32_t)(m >> 24) & 0xff; h *= p;
h ^= (uint32_t)(m >> 16) & 0xff; h *= p;
h ^= (uint32_t)(m >> 8) & 0xff; h *= p;
h ^= (uint32_t)m & 0xff; h *= p;
h ^= _adi >> 24; h *= p;
h ^= (_adi >> 16) & 0xff; h *= p;
h ^= (_adi >> 8) & 0xff; h *= p;
h ^= _adi & 0xff; h *= p;
return h;
}
inline unsigned long hashCode() const { return (_mac.hashCode() + (unsigned long)_adi); }
inline bool operator==(const MulticastGroup &g) const { return ((_mac == g._mac)&&(_adi == g._adi)); }
inline bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); }
inline bool operator<(const MulticastGroup &g) const
{
if (_mac < g._mac)
return true;
else if (_mac == g._mac)
return (_adi < g._adi);
return false;
}
inline bool operator>(const MulticastGroup &g) const { return (g < *this); }
inline bool operator<=(const MulticastGroup &g) const { return !(g < *this); }
inline bool operator>=(const MulticastGroup &g) const { return !(*this < g); }
private:
MAC _mac;
uint32_t _adi;
};
} // namespace ZeroTier
#endif

View File

@ -0,0 +1,123 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#ifndef ZT_MULTICASTSUBSCRIPTIONS_HPP
#define ZT_MULTICASTSUBSCRIPTIONS_HPP
#include "Constants.hpp"
#include "MulticastGroup.hpp"
#include "Identity.hpp"
#include "Buffer.hpp"
namespace ZeroTier {
/**
* A compact collection of multicast subscriptions identified by 32-bit hash values
*/
class MulticastSubscriptions
{
public:
inline MulticastSubscriptions() : _signatureLength(0) {}
inline void add(const MulticastGroup &mg)
{
if (_subscriptions.size() < ZT_MAX_MULTICAST_SUBSCRIPTIONS)
_subscriptions.push_back(mg.id32());
}
inline bool sign(const Identity &signer,const int64_t ts)
{
_ts = ts;
std::sort(_subscriptions.begin(),_subscriptions.end());
_subscriptions.erase(std::unique(_subscriptions.begin(),_subscriptions.end()),_subscriptions.end());
_SRec tmp;
tmp.ts = Utils::hton((uint64_t)ts);
for(unsigned long i=0,j=(unsigned long)_subscriptions.size();i<j;++i)
tmp.g[i] = Utils::hton(_subscriptions[i]);
_signatureLength = signer.sign(&tmp,(unsigned int)((_subscriptions.size() * sizeof(uint32_t)) + sizeof(uint64_t)),_signature,sizeof(_signature));
return (_signatureLength > 0);
}
inline bool verify(const Identity &signer)
{
if ((_signatureLength == 0)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return false;
_SRec tmp;
tmp.ts = Utils::hton((uint64_t)_ts);
for(unsigned long i=0,j=(unsigned long)_subscriptions.size();i<j;++i)
tmp.g[i] = Utils::hton(_subscriptions[i]);
return signer.verify(&tmp,(unsigned int)((_subscriptions.size() * sizeof(uint32_t)) + sizeof(uint64_t)),_signature,_signatureLength);
}
inline int64_t timestamp() const { return _ts; }
inline unsigned int count() const { return (unsigned int)_subscriptions.size(); }
inline bool contains(const MulticastGroup &mg) const { return std::binary_search(_subscriptions.begin(),_subscriptions.end(),mg.id32()); }
template<unsigned int C>
inline void serialize(Buffer<C> &b) const
{
b.append((uint64_t)_ts);
b.append((uint16_t)_subscriptions.size());
for(std::vector<uint32_t>::const_iterator i(_subscriptions.begin());i!=_subscriptions.end();++i)
b.append(*i);
b.append((uint16_t)_signatureLength);
b.append(_signature,_signatureLength);
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
unsigned int p = startAt;
_ts = (int64_t)(b.template at<uint64_t>(p)); p += 8;
_subscriptions.resize(b.template at<uint16_t>(p)); p += 2;
for(std::vector<uint32_t>::iterator i(_subscriptions.begin());i!=_subscriptions.end();++i) {
*i = b.template at<uint32_t>(p);
p += 4;
}
_signatureLength = b.template at<uint16_t>(p); p += 2;
if (_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
return (p - startAt);
}
private:
ZT_PACKED_STRUCT(struct _SRec {
uint64_t ts;
uint32_t g[ZT_MAX_MULTICAST_SUBSCRIPTIONS];
});
int64_t _ts;
std::vector<uint32_t> _subscriptions;
unsigned int _signatureLength;
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
};
} // namespace ZeroTier
#endif

View File

@ -130,7 +130,7 @@ extern "C" {
/**
* Maximum number of multicast group subscriptions per network
*/
#define ZT_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS 4096
#define ZT_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS 2048
/**
* Rules engine revision ID, which specifies rules engine capabilities

View File

@ -383,26 +383,11 @@ public:
private:
template<typename O>
static inline unsigned long _hc(const O &obj)
{
return (unsigned long)obj.hashCode();
}
static inline unsigned long _hc(const uint64_t i)
{
return (unsigned long)(i ^ (i >> 32)); // good for network IDs and addresses
}
static inline unsigned long _hc(const uint32_t i)
{
return ((unsigned long)i * (unsigned long)0x9e3779b1);
}
static inline unsigned long _hc(const uint16_t i)
{
return ((unsigned long)i * (unsigned long)0x9e3779b1);
}
static inline unsigned long _hc(const int i)
{
return ((unsigned long)i * (unsigned long)0x9e3379b1);
}
static inline unsigned long _hc(const O &obj) { return (unsigned long)obj.hashCode(); }
static inline unsigned long _hc(const uint64_t i) { return (unsigned long)(i ^ (i >> 32)); }
static inline unsigned long _hc(const uint32_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
static inline unsigned long _hc(const uint16_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
static inline unsigned long _hc(const int i) { return ((unsigned long)i * (unsigned long)0x9e3379b1); }
inline void _grow()
{

View File

@ -75,7 +75,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
return _doHELLO(RR,tPtr,false);
}
const SharedPtr<Peer> peer(RR->topology->getPeer(tPtr,sourceAddress));
const SharedPtr<Peer> peer(RR->topology->get(sourceAddress));
if (peer) {
if (!trusted) {
if (!dearmor(peer->key())) {
@ -170,7 +170,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
case Packet::ERROR_IDENTITY_COLLISION:
// This is a trusted upstream telling us our 5-digit ID is taken. This
// causes the node to generate another.
if (RR->topology->isUpstream(peer->identity()))
if (RR->topology->isRoot(peer->identity()))
RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
break;
@ -283,7 +283,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
return true;
}
SharedPtr<Peer> peer(RR->topology->getPeer(tPtr,id.address()));
SharedPtr<Peer> peer(RR->topology->get(id.address()));
if (peer) {
// We already have an identity with this address -- check for collisions
if (!alreadyAuthenticated) {
@ -351,7 +351,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
return true;
}
peer = RR->topology->addPeer(tPtr,newPeer);
peer = RR->topology->add(newPeer);
// Continue at // VALID
}
@ -363,7 +363,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
if (ptr < size()) {
ptr += externalSurfaceAddress.deserialize(*this,ptr);
if ((externalSurfaceAddress)&&(hops() == 0))
RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now);
RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now);
}
// Send OK(HELLO) with an echo of the packet's timestamp and some of the same
@ -451,13 +451,13 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
if ((externalSurfaceAddress)&&(hops() == 0))
RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now());
RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isRoot(peer->identity()),RR->node->now());
} break;
case Packet::VERB_WHOIS:
if (RR->topology->isUpstream(peer->identity())) {
if (RR->topology->isRoot(peer->identity())) {
const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY);
RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr<Peer>(new Peer(RR,RR->identity,id))));
RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->add(SharedPtr<Peer>(new Peer(RR,RR->identity,id))));
}
break;
@ -550,9 +550,9 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar
bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
if (RR->topology->isUpstream(peer->identity())) {
if (RR->topology->isRoot(peer->identity())) {
const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
const SharedPtr<Peer> rendezvousWith(RR->topology->getPeer(tPtr,with));
const SharedPtr<Peer> rendezvousWith(RR->topology->get(with));
if (rendezvousWith) {
const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
@ -1021,7 +1021,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
const bool amAnchor = (std::find(anchors.begin(),anchors.end(),RR->identity.address()) != anchors.end());
for(std::list<Address>::iterator ra(recipients.begin());ra!=recipients.end();) {
SharedPtr<Peer> recipient(RR->topology->getPeer(tPtr,*ra));
SharedPtr<Peer> recipient(RR->topology->get(*ra));
if ((recipient)&&((recipient->remoteVersionProtocol() < 10)||(amAnchor))) {
Packet outp(*ra,RR->identity.address(),Packet::VERB_MULTICAST_FRAME);
outp.append(field(ZT_PACKET_IDX_PAYLOAD,recipientsOffset - ZT_PACKET_IDX_PAYLOAD),recipientsOffset - ZT_PACKET_IDX_PAYLOAD);

View File

@ -38,6 +38,7 @@ namespace ZeroTier {
const InetAddress InetAddress::LO4((const void *)("\x7f\x00\x00\x01"),4,0);
const InetAddress InetAddress::LO6((const void *)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"),16,0);
const InetAddress InetAddress::NIL;
InetAddress::IpScope InetAddress::ipScope() const
{

View File

@ -64,6 +64,11 @@ struct InetAddress : public sockaddr_storage
*/
static const InetAddress LO6;
/**
* Null address
*/
static const InetAddress NIL;
/**
* IP address scope
*

View File

@ -58,10 +58,11 @@ namespace ZeroTier {
class Locator
{
public:
inline Locator() : _signatureLength(0) {}
inline Locator() : _ts(0),_signatureLength(0) {}
inline const Identity &id() const { return _id; }
inline const Identity &signer() const { return ((_signedBy) ? _signedBy : _id); }
inline int64_t timestamp() const { return _ts; }
inline const std::vector<InetAddress> &phy() const { return _physical; }
inline const std::vector<Identity> &virt() const { return _virtual; }
@ -186,10 +187,9 @@ public:
/**
* Decode TXT records
*
* The supplied TXT records must be sorted in ascending natural sort order prior
* to calling this method. The iterators supplied must be read iterators that
* point to string objects supporting the c_str() method, which can be Str or
* std::string.
* TXT records can be provided as an iterator over std::string, Str, or char *
* values, and TXT records can be provided in any order. Any oversize or empty
* entries will be ignored.
*
* This method checks the decoded locator's signature using the supplied DNS TXT
* record signing public key. False is returned if the TXT records are invalid,
@ -202,11 +202,22 @@ public:
uint8_t dec[256],s384[48];
Buffer<65536> *tmp = nullptr;
try {
tmp = new Buffer<65536>();
std::vector<Str> txtRecords;
while (start != end) {
tmp->append(dec,Utils::b64d(start->c_str(),dec,sizeof(dec)));
try {
Str ts(start);
if (ts.length() > 2)
txtRecords.push_back(ts);
} catch ( ... ) {} // skip any records that trigger out of bounds exceptions
++start;
}
if (txtRecords.empty())
return false;
std::sort(txtRecords.begin(),txtRecords.end());
tmp = new Buffer<65536>();
for(std::vector<Str>::const_iterator i(txtRecords.begin());i!=txtRecords.end();++i)
tmp->append(dec,Utils::b64d(i->c_str() + 2,dec,sizeof(dec)));
if (tmp->size() <= ZT_ECC384_SIGNATURE_SIZE) {
delete tmp;
@ -219,8 +230,8 @@ public:
}
deserialize(*tmp,0);
delete tmp;
return verify();
} catch ( ... ) {
if (tmp) delete tmp;
@ -235,10 +246,10 @@ public:
b.append((uint8_t)0); // version/flags, currently 0
b.append((uint64_t)_ts);
_id.serialise(b,false);
_id.serialize(b,false);
if (_signedBy) {
b.append((uint8_t)1); // number of signers, current max is 1
_signedBy.serialize(b,false);
_signedBy.serialize(b,false); // be sure not to include private key!
} else {
b.append((uint8_t)0); // signer is _id
}
@ -282,7 +293,7 @@ public:
_virtual.resize(virtualCount);
for(unsigned int i=0;i<virtualCount;++i)
p += _virtual[i].deserialize(b,p);
_signatureLen = b.template at<uint16_t>(p); p += 2;
_signatureLength = b.template at<uint16_t>(p); p += 2;
if (_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength);

View File

@ -191,7 +191,7 @@ public:
* @param i Value from 0 to 5 (inclusive)
* @return Byte at said position (address interpreted in big-endian order)
*/
inline unsigned char operator[](unsigned int i) const { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); }
inline uint8_t operator[](unsigned int i) const { return (uint8_t)(_m >> (40 - (i * 8))); }
/**
* @return 6, which is the number of bytes in a MAC, for container compliance
@ -230,7 +230,7 @@ public:
}
inline MAC &operator=(const uint64_t m)
{
_m = m;
_m = m & 0xffffffffffffULL;
return *this;
}

View File

@ -29,6 +29,7 @@
#include <stdint.h>
#include "Constants.hpp"
#include "MAC.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
@ -90,17 +91,10 @@ public:
return MulticastGroup();
}
/**
* @return Multicast address
*/
inline const MAC &mac() const { return _mac; }
/**
* @return Additional distinguishing information
*/
inline uint32_t adi() const { return _adi; }
inline unsigned long hashCode() const { return (_mac.hashCode() ^ (unsigned long)_adi); }
inline unsigned long hashCode() const { return (_mac.hashCode() + (unsigned long)_adi); }
inline bool operator==(const MulticastGroup &g) const { return ((_mac == g._mac)&&(_adi == g._adi)); }
inline bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); }

View File

@ -243,10 +243,6 @@ void Multicaster::send(
Address explicitGatherPeers[16];
unsigned int numExplicitGatherPeers = 0;
SharedPtr<Peer> bestRoot(RR->topology->getUpstreamPeer());
if (bestRoot)
explicitGatherPeers[numExplicitGatherPeers++] = bestRoot->address();
explicitGatherPeers[numExplicitGatherPeers++] = network->controller();
Address ac[ZT_MAX_NETWORK_SPECIALISTS];

View File

@ -1246,15 +1246,12 @@ void Network::clean()
_multicastGroupsBehindMe.erase(*mg);
}
}
{
Address *a = (Address *)0;
Membership *m = (Membership *)0;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
if (!RR->topology->getPeerNoCache(*a))
_memberships.erase(*a);
else m->clean(now,_config);
m->clean(now,_config);
}
}
}
@ -1403,42 +1400,17 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
}
}
void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup)
void Network::_sendUpdatesToMembers(void *tPtr)
{
// Assumes _lock is locked
const int64_t now = RR->node->now();
std::vector<MulticastGroup> groups;
if (newMulticastGroup)
groups.push_back(*newMulticastGroup);
else groups = _allMulticastGroups();
std::vector<Address> alwaysAnnounceTo;
if ((newMulticastGroup)||((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) {
if (!newMulticastGroup)
_lastAnnouncedMulticastGroupsUpstream = now;
alwaysAnnounceTo = _config.alwaysContactAddresses();
if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),controller()) == alwaysAnnounceTo.end())
alwaysAnnounceTo.push_back(controller());
const std::vector<Address> upstreams(RR->topology->upstreamAddresses());
for(std::vector<Address>::const_iterator a(upstreams.begin());a!=upstreams.end();++a) {
if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a) == alwaysAnnounceTo.end())
alwaysAnnounceTo.push_back(*a);
}
std::sort(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end());
for(std::vector<Address>::const_iterator a(alwaysAnnounceTo.begin());a!=alwaysAnnounceTo.end();++a)
_announceMulticastGroupsTo(tPtr,*a,groups);
}
const std::vector<MulticastGroup> groups(_allMulticastGroups());
_announceMulticastGroupsTo(tPtr,controller(),groups);
{
Address *a = (Address *)0;
Membership *m = (Membership *)0;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
if ( ( m->multicastLikeGate(now) || (newMulticastGroup) ) && (m->isAllowedOnNetwork(_config)) && (!std::binary_search(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a)) )
if (m->isAllowedOnNetwork(_config))
_announceMulticastGroupsTo(tPtr,*a,groups);
}
}

View File

@ -193,10 +193,10 @@ public:
Mutex::Lock _l(_lock);
if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
_myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg);
_sendUpdatesToMembers(tPtr,&mg);
_sendUpdatesToMembers(tPtr);
}
}
/**
* Unsubscribe from a multicast group
*
@ -295,7 +295,7 @@ public:
inline void sendUpdatesToMembers(void *tPtr)
{
Mutex::Lock _l(_lock);
_sendUpdatesToMembers(tPtr,(const MulticastGroup *)0);
_sendUpdatesToMembers(tPtr);
}
/**
@ -432,7 +432,7 @@ private:
ZT_VirtualNetworkStatus _status() const;
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
bool _gate(const SharedPtr<Peer> &peer);
void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup);
void _sendUpdatesToMembers(void *tPtr);
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
std::vector<MulticastGroup> _allMulticastGroups() const;

View File

@ -104,7 +104,7 @@ namespace ZeroTier {
#define ZT_NETWORKCONFIG_DICT_CAPACITY (1024 + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP))
// Dictionary capacity needed for max size network meta-data
#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024
#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 2048
// Network config version
#define ZT_NETWORKCONFIG_VERSION 7

View File

@ -126,7 +126,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
m += sws;
RR->mc = new (m) Multicaster(RR);
m += mcs;
RR->topology = new (m) Topology(RR,tptr);
RR->topology = new (m) Topology(RR,RR->identity);
m += topologys;
RR->sa = new (m) SelfAwareness(RR);
} catch ( ... ) {
@ -190,6 +190,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
/*
// Function object used to traverse the peer list, check peer status, and ping
// those that need pinging.
struct _PingPeersThatNeedPing
@ -254,6 +255,7 @@ struct _PingPeersThatNeedPing
bool online;
};
*/
ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
{
@ -282,6 +284,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
_localControllerAuthorizations_m.unlock();
}
/*
// (1) Get peers we should remain connected to and (2) get networks that need config.
Hashtable< Address,std::vector<InetAddress> > alwaysContact;
RR->topology->getAlwaysContact(alwaysContact);
@ -322,6 +325,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
_online = pfunc.online;
if (oldOnline != _online)
postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
*/
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
@ -337,7 +341,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) {
_lastHousekeepingRun = now;
try {
RR->topology->doPeriodicTasks(tptr,now);
RR->topology->doPeriodicTasks(now);
RR->sa->clean(now);
RR->mc->clean(now);
} catch ( ... ) {
@ -454,7 +458,7 @@ ZT_PeerList *Node::peers() const
p->latency = pi->second->latency(_now);
if (p->latency >= 0xffff)
p->latency = -1;
p->role = RR->topology->role(pi->second->identity().address());
p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_PLANET : ZT_PEER_ROLE_LEAF;
std::vector< SharedPtr<Path> > paths(pi->second->paths(_now));
SharedPtr<Path> bestp(pi->second->getAppropriatePath(_now,false));

223
node/Root.hpp Normal file
View File

@ -0,0 +1,223 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#ifndef ZT_ROOT_HPP
#define ZT_ROOT_HPP
#include "Constants.hpp"
#include "Str.hpp"
#include "ECC384.hpp"
#include "Locator.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
#include "Identity.hpp"
#include "Mutex.hpp"
namespace ZeroTier {
/**
* A root entry pointing to a node capable of global identity lookup and indirect transit
*
* Root entries point to DNS records that contain TXT entries that decode to Locator objects
* pointing to actual root nodes. A default root identity and static addresses can also be
* provided as fallback if DNS is not available.
*
* Note that root identities can change if DNS returns a different result, but that DNS entries
* are authenticated using their own signature scheme. This allows a root DNS name to serve
* up different roots based on factors like location or relative load of different roots.
*
* It's also possible to create a root with no DNS and no DNS validator public key. This root
* will be a static entry pointing to a single root identity and set of physical addresses.
*
* This object is thread-safe and may be concurrently accessed and updated.
*/
class Root
{
public:
inline Root() : _dnsPublicKeySize(0) {}
inline Root(const Root &r) { *this = r; }
/**
* Create a new root entry
*
* @param dn DNS name
* @param dnspk DNS public key for record validation
* @param dnspksize Size of DNS public key (currently always the size of a NIST P-384 point compressed public key)
* @param dflId Default identity if DNS is not available
* @param dflAddrs Default IP addresses if DNS is not available
*/
template<typename S>
inline Root(S dn,const uint8_t *const dnspk,const unsigned int dnspksize,const Identity &dflId,const std::vector<InetAddress> &dflAddrs) :
_defaultIdentity(dflId),
_defaultAddresses(dflAddrs),
_dnsName(dn),
_dnsPublicKeySize(dnspksize)
{
if (dnspksize != 0) {
if (dnspksize > sizeof(_dnsPublicKey))
throw ZT_EXCEPTION_INVALID_ARGUMENT;
memcpy(_dnsPublicKey,dnspk,dnspksize);
}
}
inline Root &operator=(const Root &r)
{
Mutex::Lock l(_lock);
Mutex::Lock rl(r._lock);
_defaultIdentity = r._defaultIdentity;
_defaultAddresses = r._defaultAddresses;
_dnsName = r._dnsName;
_lastFetchedLocator = r._lastFetchedLocator;
_dnsPublicKeySize = r._dnsPublicKeySize;
memcpy(_dnsPublicKey,r._dnsPublicKey,_dnsPublicKeySize);
return *this;
}
/**
* @return Current identity (either default or latest locator)
*/
inline const Identity id() const
{
Mutex::Lock l(_lock);
if (_lastFetchedLocator.id())
return _lastFetchedLocator.id();
return _defaultIdentity;
}
/**
* @param id Identity to check
* @return True if identity equals this root's current identity
*/
inline bool is(const Identity &id) const
{
Mutex::Lock l(_lock);
return ((_lastFetchedLocator.id()) ? (id == _lastFetchedLocator.id()) : (id == _defaultIdentity));
}
/**
* @return Current ZeroTier address (either default or latest locator)
*/
inline const Address address() const
{
Mutex::Lock l(_lock);
if (_lastFetchedLocator.id())
return _lastFetchedLocator.id().address();
return _defaultIdentity.address();
}
/**
* @return DNS name for this root (or empty string if none)
*/
inline const Str dnsName() const
{
Mutex::Lock l(_lock);
return _dnsName;
}
/**
* @return Latest locator
*/
inline Locator locator() const
{
Mutex::Lock l(_lock);
return _lastFetchedLocator;
}
/**
* @return Timestamp of latest retrieved locator
*/
inline int64_t locatorTimestamp() const
{
Mutex::Lock l(_lock);
return _lastFetchedLocator.timestamp();
}
/**
* Pick a random physical address
*
* @return Physical address or InetAddress::NIL if none are available
*/
inline const InetAddress randomPhysicalAddress() const
{
Mutex::Lock l(_lock);
if (_lastFetchedLocator.phy().empty()) {
if (_defaultAddresses.empty())
return InetAddress::NIL;
return _defaultAddresses[(unsigned long)Utils::random() % (unsigned long)_defaultAddresses.size()];
}
return _lastFetchedLocator.phy()[(unsigned long)Utils::random() % (unsigned long)_lastFetchedLocator.phy().size()];
}
/**
* Update locator, returning true if new locator is valid and newer than existing
*/
inline bool updateLocator(const Locator &loc)
{
if (!loc.verify())
return false;
Mutex::Lock l(_lock);
if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) {
_lastFetchedLocator = loc;
return true;
}
return false;
}
/**
* Update this root's locator from a series of TXT records
*/
template<typename I>
inline bool updateLocatorFromTxt(I start,I end)
{
try {
Mutex::Lock l(_lock);
if (_dnsPublicKeySize != ZT_ECC384_PUBLIC_KEY_SIZE)
return false;
Locator loc;
if (!loc.decodeTxtRecords(start,end,_dnsPublicKey))
return false;
if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) {
_lastFetchedLocator = loc;
return true;
}
return false;
} catch ( ... ) {}
return false;
}
private:
Identity _defaultIdentity;
std::vector<InetAddress> _defaultAddresses;
Str _dnsName;
Locator _lastFetchedLocator;
unsigned int _dnsPublicKeySize;
uint8_t _dnsPublicKey[ZT_ECC384_PUBLIC_KEY_SIZE];
Mutex _lock;
};
} // namespace ZeroTier
#endif

View File

@ -33,6 +33,8 @@
#include "MAC.hpp"
#include "InetAddress.hpp"
#include <string>
#define ZT_STR_CAPACITY 254
namespace ZeroTier {
@ -58,6 +60,10 @@ public:
_s[0] = 0;
(*this) << s;
}
inline Str(const std::string &s)
{
*this = s;
}
inline Str &operator=(const Str &s)
{
@ -71,6 +77,19 @@ public:
_s[0] = 0;
return ((*this) << s);
}
inline Str &operator=(const std::string &s)
{
if (s.length() > ZT_STR_CAPACITY) {
_l = 0;
_s[0] = 0;
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} else {
_l = (uint8_t)s.length();
memcpy(_s,s.data(),s.length());
_s[s.length()] = 0;
}
return *this;
}
inline char operator[](const unsigned int i) const
{
@ -82,6 +101,7 @@ public:
inline void clear() { _l = 0; _s[0] = 0; }
inline const char *c_str() const { return _s; }
inline unsigned int length() const { return (unsigned int)_l; }
inline bool empty() const { return (_l == 0); }
inline iterator begin() { return (iterator)_s; }
inline iterator end() { return (iterator)(_s + (unsigned long)_l); }
inline const_iterator begin() const { return (const_iterator)_s; }
@ -113,6 +133,7 @@ public:
}
_s[(unsigned long)(_l++)] = c;
_s[(unsigned long)_l] = 0;
return *this;
}
inline Str &operator<<(const unsigned long n)
{
@ -142,6 +163,8 @@ public:
return ((*this) << a.toString(tmp));
}
inline operator bool() const { return (_l != 0); }
inline bool operator==(const Str &s) const { return ((_l == s._l)&&(strcmp(_s,s._s) == 0)); }
inline bool operator!=(const Str &s) const { return ((_l != s._l)||(strcmp(_s,s._s) != 0)); }
inline bool operator<(const Str &s) const { return ((_l < s._l)&&(strcmp(_s,s._s) < 0)); }

View File

@ -73,7 +73,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
return;
if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localSocket,fromAddr))
return;
const SharedPtr<Peer> peer(RR->topology->getPeer(tPtr,beaconAddr));
const SharedPtr<Peer> peer(RR->topology->get(beaconAddr));
if (peer) { // we'll only respond to beacons from known peers
if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses
_lastBeaconResponse = now;
@ -96,12 +96,13 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
// Note: we don't bother initiating NAT-t for fragments, since heads will set that off.
// It wouldn't hurt anything, just redundant and unnecessary.
SharedPtr<Peer> relayTo = RR->topology->getPeer(tPtr,destination);
SharedPtr<Peer> relayTo = RR->topology->get(destination);
if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) {
// Don't know peer or no direct path -- so relay via someone upstream
relayTo = RR->topology->getUpstreamPeer();
if (relayTo)
relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true);
// TODO
//relayTo = RR->topology->getUpstreamPeer();
//if (relayTo)
// relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true);
}
}
} else {
@ -163,22 +164,25 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
Packet packet(data,len);
if (packet.hops() < ZT_RELAY_MAX_HOPS) {
packet.incrementHops();
SharedPtr<Peer> relayTo = RR->topology->getPeer(tPtr,destination);
SharedPtr<Peer> relayTo = RR->topology->get(destination);
if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) {
if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) {
const SharedPtr<Peer> sourcePeer(RR->topology->getPeer(tPtr,source));
const SharedPtr<Peer> sourcePeer(RR->topology->get(source));
if (sourcePeer)
relayTo->introduce(tPtr,now,sourcePeer);
}
} else {
// TODO
/*
relayTo = RR->topology->getUpstreamPeer();
if ((relayTo)&&(relayTo->address() != source)) {
if (relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true)) {
const SharedPtr<Peer> sourcePeer(RR->topology->getPeer(tPtr,source));
const SharedPtr<Peer> sourcePeer(RR->topology->get(source));
if (sourcePeer)
relayTo->introduce(tPtr,now,sourcePeer);
}
}
*/
}
}
} else if ((reinterpret_cast<const uint8_t *>(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) {
@ -402,7 +406,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
// Destination is another ZeroTier peer on the same network
Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this
SharedPtr<Peer> toPeer(RR->topology->getPeer(tPtr,toZT));
SharedPtr<Peer> toPeer(RR->topology->get(toZT));
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked");
@ -763,7 +767,7 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt)
}
_txQueue.push_back(TXQueueEntry(dest,RR->node->now(),packet,encrypt));
}
if (!RR->topology->getPeer(tPtr,dest))
if (!RR->topology->get(dest))
requestWhois(tPtr,RR->node->now(),dest);
}
}
@ -781,6 +785,8 @@ void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr)
else last = now;
}
// TODO
/*
const SharedPtr<Peer> upstream(RR->topology->getUpstreamPeer());
if (upstream) {
Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS);
@ -788,6 +794,7 @@ void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr)
RR->node->expectReplyTo(outp.packetId());
send(tPtr,outp,true);
}
*/
}
void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer)
@ -840,7 +847,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
} else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) {
_txQueue.erase(txi++);
} else {
if (!RR->topology->getPeer(tPtr,txi->dest))
if (!RR->topology->get(txi->dest))
needWhois.push_back(txi->dest);
++txi;
}
@ -857,7 +864,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
rq->timestamp = 0;
} else {
const Address src(rq->frag0.source());
if (!RR->topology->getPeer(tPtr,src))
if (!RR->topology->get(src))
requestWhois(tPtr,now,src);
}
}
@ -905,16 +912,19 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt)
const int64_t now = RR->node->now();
const Address destination(packet.destination());
const SharedPtr<Peer> peer(RR->topology->getPeer(tPtr,destination));
const SharedPtr<Peer> peer(RR->topology->get(destination));
if (peer) {
viaPath = peer->getAppropriatePath(now,false);
if (!viaPath) {
// TODO
/*
peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known
const SharedPtr<Peer> relay(RR->topology->getUpstreamPeer());
if ( (!relay) || (!(viaPath = relay->getAppropriatePath(now,false))) ) {
if (!(viaPath = peer->getAppropriatePath(now,true)))
return false;
}
*/
}
} else {
return false;

View File

@ -45,6 +45,7 @@
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "Root.hpp"
namespace ZeroTier {
@ -56,8 +57,9 @@ class RuntimeEnvironment;
class Topology
{
public:
inline Topology(const RuntimeEnvironment *renv,void *tPtr) :
inline Topology(const RuntimeEnvironment *renv,const Identity &myId) :
RR(renv),
_myIdentity(myId),
_numConfiguredPhysicalPaths(0) {}
inline ~Topology() {}
@ -71,7 +73,7 @@ public:
* @param peer Peer to add
* @return New or existing peer (should replace 'peer')
*/
inline SharedPtr<Peer> addPeer(void *tPtr,const SharedPtr<Peer> &peer)
inline SharedPtr<Peer> add(const SharedPtr<Peer> &peer)
{
SharedPtr<Peer> np;
{
@ -91,13 +93,28 @@ public:
* @param zta ZeroTier address of peer
* @return Peer or NULL if not found
*/
inline SharedPtr<Peer> getPeer(void *tPtr,const Address &zta) const
inline SharedPtr<Peer> get(const Address &zta)
{
if (zta == RR->identity.address())
if (zta == _myIdentity.address())
return SharedPtr<Peer>();
Mutex::Lock _l(_peers_m);
Mutex::Lock l1(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta);
return ((ap) ? *ap : SharedPtr<Peer>());
if (ap)
return *ap;
Mutex::Lock l2(_roots_m);
for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) {
if (r->address() == zta) {
try {
SharedPtr<Peer> rp(new Peer(RR,_myIdentity,r->id()));
_peers[zta] = rp;
return rp;
} catch ( ... ) {}
}
}
return SharedPtr<Peer>();
}
/**
@ -107,8 +124,8 @@ public:
*/
inline Identity getIdentity(void *tPtr,const Address &zta)
{
if (zta == RR->identity.address()) {
return RR->identity;
if (zta == _myIdentity.address()) {
return _myIdentity;
} else {
Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta);
@ -118,25 +135,6 @@ public:
return Identity();
}
/**
* Get a peer only if it is presently in memory (no disk cache)
*
* This also does not update the lastUsed() time for peers, which means
* that it won't prevent them from falling out of RAM. This is currently
* used in the Cluster code to update peer info without forcing all peers
* across the entire cluster to remain in memory cache.
*
* @param zta ZeroTier address
*/
inline SharedPtr<Peer> getPeerNoCache(const Address &zta)
{
Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta);
if (ap)
return *ap;
return SharedPtr<Peer>();
}
/**
* Get a Path object for a given local and remote physical address, creating if needed
*
@ -153,36 +151,24 @@ public:
return p;
}
inline SharedPtr<Peer> getUpstreamPeer() const
/**
* @param id Identity to check
* @return True if this identity corresponds to a root
*/
inline bool isRoot(const Identity &id) const
{
// TODO
return SharedPtr<Peer>();
}
inline bool isUpstream(const Identity &id) const
{
// TODO
Mutex::Lock l(_roots_m);
for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) {
if (r->is(id))
return true;
}
return false;
}
inline ZT_PeerRole role(const Address &ztaddr) const
{
// TODO
return ZT_PEER_ROLE_LEAF;
}
inline void getAlwaysContact(Hashtable< Address,std::vector<InetAddress> > &eps) const
{
// TODO
}
inline std::vector<Address> upstreamAddresses() const
{
// TODO
return std::vector<Address>();
}
inline void doPeriodicTasks(void *tPtr,int64_t now)
/**
* Do periodic tasks such as database cleanup
*/
inline void doPeriodicTasks(int64_t now)
{
{
Mutex::Lock _l1(_peers_m);
@ -357,11 +343,14 @@ public:
private:
const RuntimeEnvironment *const RR;
const Identity _myIdentity;
std::pair<InetAddress,ZT_PhysicalPathConfiguration> _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
unsigned int _numConfiguredPhysicalPaths;
std::vector<Root> _roots;
Hashtable< Address,SharedPtr<Peer> > _peers;
Mutex _peers_m;
Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
Mutex _roots_m;
Mutex _peers_m;
Mutex _paths_m;
};