Make Dictionary templatable so it can be used where we want a higher capacity.

This commit is contained in:
Adam Ierymenko 2016-06-21 07:32:58 -07:00
parent 3ee15e65aa
commit b2d048aa0e
12 changed files with 67 additions and 49 deletions

View File

@ -402,7 +402,7 @@ SqliteNetworkController::~SqliteNetworkController()
} }
} }
NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary &metaData,NetworkConfig &nc) NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,NetworkConfig &nc)
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
return _doNetworkConfigRequest(fromAddr,signingId,identity,nwid,metaData,nc); return _doNetworkConfigRequest(fromAddr,signingId,identity,nwid,metaData,nc);
@ -1576,7 +1576,7 @@ unsigned int SqliteNetworkController::_doCPGet(
return 404; return 404;
} }
NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary &metaData,NetworkConfig &nc) NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,NetworkConfig &nc)
{ {
// Assumes _lock is locked // Assumes _lock is locked

View File

@ -62,7 +62,7 @@ public:
const Identity &signingId, const Identity &signingId,
const Identity &identity, const Identity &identity,
uint64_t nwid, uint64_t nwid,
const Dictionary &metaData, const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,
NetworkConfig &nc); NetworkConfig &nc);
unsigned int handleControlPlaneHttpGET( unsigned int handleControlPlaneHttpGET(
@ -113,7 +113,7 @@ private:
const Identity &signingId, const Identity &signingId,
const Identity &identity, const Identity &identity,
uint64_t nwid, uint64_t nwid,
const Dictionary &metaData, const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,
NetworkConfig &nc); NetworkConfig &nc);
static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report); static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report);

View File

@ -26,9 +26,6 @@
#include <stdint.h> #include <stdint.h>
// Can be increased if it's ever needed, but not too much.
#define ZT_DICTIONARY_MAX_SIZE 8194
namespace ZeroTier { namespace ZeroTier {
/** /**
@ -48,7 +45,10 @@ namespace ZeroTier {
* *
* There is code to test and fuzz this in selftest.cpp. Fuzzing a blob of * There is code to test and fuzz this in selftest.cpp. Fuzzing a blob of
* pointer tricks like this is important after any modifications. * pointer tricks like this is important after any modifications.
*
* @tparam C Dictionary max capacity in bytes
*/ */
template<unsigned int C>
class Dictionary class Dictionary
{ {
public: public:
@ -64,8 +64,8 @@ public:
Dictionary(const char *s,unsigned int len) Dictionary(const char *s,unsigned int len)
{ {
memcpy(_d,s,(len > ZT_DICTIONARY_MAX_SIZE) ? (unsigned int)ZT_DICTIONARY_MAX_SIZE : len); memcpy(_d,s,(len > C) ? (unsigned int)C : len);
_d[ZT_DICTIONARY_MAX_SIZE-1] = (char)0; _d[C-1] = (char)0;
} }
Dictionary(const Dictionary &d) Dictionary(const Dictionary &d)
@ -83,7 +83,7 @@ public:
* Load a dictionary from a C-string * Load a dictionary from a C-string
* *
* @param s Dictionary in string form * @param s Dictionary in string form
* @return False if 's' was longer than ZT_DICTIONARY_MAX_SIZE * @return False if 's' was longer than our capacity
*/ */
inline bool load(const char *s) inline bool load(const char *s)
{ {
@ -103,11 +103,11 @@ public:
*/ */
inline unsigned int sizeBytes() const inline unsigned int sizeBytes() const
{ {
for(unsigned int i=0;i<ZT_DICTIONARY_MAX_SIZE;++i) { for(unsigned int i=0;i<C;++i) {
if (!_d[i]) if (!_d[i])
return i; return i;
} }
return ZT_DICTIONARY_MAX_SIZE; return C;
} }
/** /**
@ -194,9 +194,10 @@ public:
* @param key Key to get * @param key Key to get
* @param dest Destination buffer * @param dest Destination buffer
* @return True if key was found (if false, dest will be empty) * @return True if key was found (if false, dest will be empty)
* @tparam BC Buffer capacity (usually inferred)
*/ */
template<unsigned int C> template<unsigned int BC>
inline bool get(const char *key,Buffer<C> &dest) const inline bool get(const char *key,Buffer<BC> &dest) const
{ {
const int r = this->get(key,const_cast<char *>(reinterpret_cast<const char *>(dest.data())),C); const int r = this->get(key,const_cast<char *>(reinterpret_cast<const char *>(dest.data())),C);
if (r >= 0) { if (r >= 0) {
@ -254,13 +255,13 @@ public:
*/ */
inline bool add(const char *key,const char *value,int vlen = -1) inline bool add(const char *key,const char *value,int vlen = -1)
{ {
for(unsigned int i=0;i<ZT_DICTIONARY_MAX_SIZE;++i) { for(unsigned int i=0;i<C;++i) {
if (!_d[i]) { if (!_d[i]) {
unsigned int j = i; unsigned int j = i;
if (j > 0) { if (j > 0) {
_d[j++] = '\n'; _d[j++] = '\n';
if (j == ZT_DICTIONARY_MAX_SIZE) { if (j == C) {
_d[i] = (char)0; _d[i] = (char)0;
return false; return false;
} }
@ -269,14 +270,14 @@ public:
const char *p = key; const char *p = key;
while (*p) { while (*p) {
_d[j++] = *(p++); _d[j++] = *(p++);
if (j == ZT_DICTIONARY_MAX_SIZE) { if (j == C) {
_d[i] = (char)0; _d[i] = (char)0;
return false; return false;
} }
} }
_d[j++] = '='; _d[j++] = '=';
if (j == ZT_DICTIONARY_MAX_SIZE) { if (j == C) {
_d[i] = (char)0; _d[i] = (char)0;
return false; return false;
} }
@ -291,7 +292,7 @@ public:
case '\\': case '\\':
case '=': case '=':
_d[j++] = '\\'; _d[j++] = '\\';
if (j == ZT_DICTIONARY_MAX_SIZE) { if (j == C) {
_d[i] = (char)0; _d[i] = (char)0;
return false; return false;
} }
@ -302,14 +303,14 @@ public:
case '\\': _d[j++] = '\\'; break; case '\\': _d[j++] = '\\'; break;
case '=': _d[j++] = 'e'; break; case '=': _d[j++] = 'e'; break;
} }
if (j == ZT_DICTIONARY_MAX_SIZE) { if (j == C) {
_d[i] = (char)0; _d[i] = (char)0;
return false; return false;
} }
break; break;
default: default:
_d[j++] = *p; _d[j++] = *p;
if (j == ZT_DICTIONARY_MAX_SIZE) { if (j == C) {
_d[i] = (char)0; _d[i] = (char)0;
return false; return false;
} }
@ -356,10 +357,12 @@ public:
} }
/** /**
* Add a binary buffer * Add a binary buffer's contents as a value
*
* @tparam BC Buffer capacity (usually inferred)
*/ */
template<unsigned int C> template<unsigned int BC>
inline bool add(const char *key,const Buffer<C> &value) inline bool add(const char *key,const Buffer<BC> &value)
{ {
return this->add(key,(const char *)value.data(),(int)value.size()); return this->add(key,(const char *)value.data(),(int)value.size());
} }
@ -385,7 +388,7 @@ public:
*/ */
inline bool erase(const char *key) inline bool erase(const char *key)
{ {
char d2[ZT_DICTIONARY_MAX_SIZE]; char d2[C];
char *saveptr = (char *)0; char *saveptr = (char *)0;
unsigned int d2ptr = 0; unsigned int d2ptr = 0;
bool found = false; bool found = false;
@ -419,8 +422,13 @@ public:
*/ */
inline const char *data() const { return _d; } inline const char *data() const { return _d; }
/**
* @return Value of C template parameter
*/
inline unsigned int capacity() const { return C; }
private: private:
char _d[ZT_DICTIONARY_MAX_SIZE]; char _d[C];
}; };
} // namespace ZeroTier } // namespace ZeroTier

View File

@ -403,7 +403,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
if ((nw)&&(nw->controller() == peer->address())) { if ((nw)&&(nw->controller() == peer->address())) {
const unsigned int nclen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); const unsigned int nclen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN);
if (nclen) { if (nclen) {
Dictionary dconf((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,nclen),nclen); Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> dconf((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,nclen),nclen);
NetworkConfig nconf; NetworkConfig nconf;
if (nconf.fromDictionary(dconf)) { if (nconf.fromDictionary(dconf)) {
nw->setConfiguration(nconf,true); nw->setConfiguration(nconf,true);
@ -684,7 +684,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
const unsigned int metaDataLength = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); const unsigned int metaDataLength = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN);
const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength);
const Dictionary metaData(metaDataBytes,metaDataLength); const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> metaData(metaDataBytes,metaDataLength);
//const uint64_t haveRevision = ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength + 8) <= size()) ? at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength) : 0ULL; //const uint64_t haveRevision = ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength + 8) <= size()) ? at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength) : 0ULL;
@ -697,7 +697,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,netconf)) { switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,netconf)) {
case NetworkController::NETCONF_QUERY_OK: { case NetworkController::NETCONF_QUERY_OK: {
Dictionary dconf; Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> dconf;
if (netconf.toDictionary(dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { if (netconf.toDictionary(dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);

View File

@ -64,7 +64,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) :
try { try {
std::string conf(RR->node->dataStoreGet(confn)); std::string conf(RR->node->dataStoreGet(confn));
if (conf.length()) { if (conf.length()) {
Dictionary dconf(conf.c_str()); Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> dconf(conf.c_str());
NetworkConfig nconf; NetworkConfig nconf;
if (nconf.fromDictionary(dconf)) { if (nconf.fromDictionary(dconf)) {
this->setConfiguration(nconf,false); this->setConfiguration(nconf,false);
@ -193,7 +193,7 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk)
if (saveToDisk) { if (saveToDisk) {
char n[64]; char n[64];
Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id);
Dictionary d; Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> d;
if (nconf.toDictionary(d,false)) if (nconf.toDictionary(d,false))
RR->node->dataStorePut(n,(const void *)d.data(),d.sizeBytes(),true); RR->node->dataStorePut(n,(const void *)d.data(),d.sizeBytes(),true);
} }
@ -210,7 +210,7 @@ void Network::requestConfiguration()
if (_id == ZT_TEST_NETWORK_ID) // pseudo-network-ID, uses locally generated static config if (_id == ZT_TEST_NETWORK_ID) // pseudo-network-ID, uses locally generated static config
return; return;
Dictionary rmd; Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> rmd;
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION);
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,(uint64_t)ZT_PROTO_VERSION); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,(uint64_t)ZT_PROTO_VERSION);
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MAJOR); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MAJOR);

View File

@ -23,9 +23,9 @@
namespace ZeroTier { namespace ZeroTier {
bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const
{ {
Buffer<ZT_DICTIONARY_MAX_SIZE> tmp; Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> tmp;
d.clear(); d.clear();
@ -259,11 +259,11 @@ bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const
return true; return true;
} }
bool NetworkConfig::fromDictionary(const Dictionary &d) bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d)
{ {
try { try {
Buffer<ZT_DICTIONARY_MAX_SIZE> tmp; Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> tmp;
char tmp2[ZT_DICTIONARY_MAX_SIZE]; char tmp2[ZT_NETWORKCONFIG_DICT_CAPACITY];
memset(this,0,sizeof(NetworkConfig)); memset(this,0,sizeof(NetworkConfig));

View File

@ -64,6 +64,9 @@
namespace ZeroTier { namespace ZeroTier {
// Maximum size of a network config dictionary (can be increased)
#define ZT_NETWORKCONFIG_DICT_CAPACITY 8194
// Network config version // Network config version
#define ZT_NETWORKCONFIG_VERSION 6 #define ZT_NETWORKCONFIG_VERSION 6
@ -234,7 +237,7 @@ public:
* @param includeLegacy If true, include legacy fields for old node versions * @param includeLegacy If true, include legacy fields for old node versions
* @return True if dictionary was successfully created, false if e.g. overflow * @return True if dictionary was successfully created, false if e.g. overflow
*/ */
bool toDictionary(Dictionary &d,bool includeLegacy) const; bool toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const;
/** /**
* Read this network config from a dictionary * Read this network config from a dictionary
@ -242,7 +245,7 @@ public:
* @param d Dictionary * @param d Dictionary
* @return True if dictionary was valid and network config successfully initialized * @return True if dictionary was valid and network config successfully initialized
*/ */
bool fromDictionary(const Dictionary &d); bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d);
/** /**
* @return True if passive bridging is allowed (experimental) * @return True if passive bridging is allowed (experimental)

View File

@ -22,12 +22,12 @@
#include <stdint.h> #include <stdint.h>
#include "Constants.hpp" #include "Constants.hpp"
#include "Dictionary.hpp"
#include "NetworkConfig.hpp"
namespace ZeroTier { namespace ZeroTier {
class RuntimeEnvironment; class RuntimeEnvironment;
class NetworkConfig;
class Dictionary;
class Identity; class Identity;
class Address; class Address;
struct InetAddress; struct InetAddress;
@ -75,7 +75,7 @@ public:
const Identity &signingId, const Identity &signingId,
const Identity &identity, const Identity &identity,
uint64_t nwid, uint64_t nwid,
const Dictionary &metaData, const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,
NetworkConfig &nc) = 0; NetworkConfig &nc) = 0;
}; };

View File

@ -95,7 +95,7 @@ LinuxEthernetTap::LinuxEthernetTap(
// Try to recall our last device name, or pick an unused one if that fails. // Try to recall our last device name, or pick an unused one if that fails.
bool recalledDevice = false; bool recalledDevice = false;
std::string devmapbuf; std::string devmapbuf;
Dictionary devmap; Dictionary<8194> devmap;
if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) { if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) {
devmap.load(devmapbuf.c_str()); devmap.load(devmapbuf.c_str());
char desiredDevice[128]; char desiredDevice[128];

View File

@ -354,7 +354,7 @@ OSXEthernetTap::OSXEthernetTap(
// Try to reopen the last device we had, if we had one and it's still unused. // Try to reopen the last device we had, if we had one and it's still unused.
bool recalledDevice = false; bool recalledDevice = false;
std::string devmapbuf; std::string devmapbuf;
Dictionary devmap; Dictionary<8194> devmap;
if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) { if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) {
devmap.load(devmapbuf.c_str()); devmap.load(devmapbuf.c_str());
char desiredDevice[128]; char desiredDevice[128];

View File

@ -766,7 +766,7 @@ static int testOther()
std::cout << "[other] Testing/fuzzing Dictionary... "; std::cout.flush(); std::cout << "[other] Testing/fuzzing Dictionary... "; std::cout.flush();
for(int k=0;k<1000;++k) { for(int k=0;k<1000;++k) {
Dictionary test; Dictionary<8194> test;
char key[32][16]; char key[32][16];
char value[32][128]; char value[32][128];
for(unsigned int q=0;q<32;++q) { for(unsigned int q=0;q<32;++q) {
@ -807,12 +807,12 @@ static int testOther()
int foo = 0; int foo = 0;
volatile int *volatile bar = &foo; // force compiler not to optimize out test.get() below volatile int *volatile bar = &foo; // force compiler not to optimize out test.get() below
for(int k=0;k<100;++k) { for(int k=0;k<100;++k) {
int r = rand() % ZT_DICTIONARY_MAX_SIZE; int r = rand() % 8194;
unsigned char tmp[ZT_DICTIONARY_MAX_SIZE]; unsigned char tmp[8194];
for(int q=0;q<r;++q) for(int q=0;q<r;++q)
tmp[q] = (unsigned char)((rand() % 254) + 1); tmp[q] = (unsigned char)((rand() % 254) + 1);
tmp[r] = 0; tmp[r] = 0;
Dictionary test((const char *)tmp); Dictionary<8194> test((const char *)tmp);
for(unsigned int q=0;q<100;++q) { for(unsigned int q=0;q<100;++q) {
char tmp[16]; char tmp[16];
Utils::snprintf(tmp,16,"%.8lx",(unsigned long)rand()); Utils::snprintf(tmp,16,"%.8lx",(unsigned long)rand());

View File

@ -1571,6 +1571,7 @@ public:
inline int nodePathCheckFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) inline int nodePathCheckFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr)
{ {
Mutex::Lock _l(_nets_m); Mutex::Lock _l(_nets_m);
for(std::map<uint64_t,NetworkState>::const_iterator n(_nets.begin());n!=_nets.end();++n) { for(std::map<uint64_t,NetworkState>::const_iterator n(_nets.begin());n!=_nets.end();++n) {
if (n->second.tap) { if (n->second.tap) {
std::vector<InetAddress> ips(n->second.tap->ips()); std::vector<InetAddress> ips(n->second.tap->ips());
@ -1581,7 +1582,13 @@ public:
} }
} }
} }
// TODO: also check routing table for L3 routes via ZeroTier managed devices
/* Note: I do not think we need to scan for overlap with managed routes
* because of the "route forking" and interface binding that we do. This
* ensures (we hope) that ZeroTier traffic will still take the physical
* path even if its managed routes override this for other traffic. Will
* revisit if we see problems with this. */
return 1; return 1;
} }