mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 03:53:44 +02:00
Simplify Dictionary and reduce memory usage, now no more std::maps in core.
This commit is contained in:
parent
76a95dc58f
commit
5384f185ae
4 changed files with 99 additions and 73 deletions
|
@ -32,6 +32,68 @@
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
Dictionary::iterator Dictionary::find(const std::string &key)
|
||||||
|
{
|
||||||
|
for(iterator i(begin());i!=end();++i) {
|
||||||
|
if (i->first == key)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
Dictionary::const_iterator Dictionary::find(const std::string &key) const
|
||||||
|
{
|
||||||
|
for(const_iterator i(begin());i!=end();++i) {
|
||||||
|
if (i->first == key)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dictionary::getBoolean(const std::string &key,bool dfl) const
|
||||||
|
{
|
||||||
|
const_iterator e(find(key));
|
||||||
|
if (e == end())
|
||||||
|
return dfl;
|
||||||
|
if (e->second.length() < 1)
|
||||||
|
return dfl;
|
||||||
|
switch(e->second[0]) {
|
||||||
|
case '1':
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
case 'y':
|
||||||
|
case 'Y':
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string &Dictionary::operator[](const std::string &key)
|
||||||
|
{
|
||||||
|
for(iterator i(begin());i!=end();++i) {
|
||||||
|
if (i->first == key)
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
push_back(std::pair<std::string,std::string>(key,std::string()));
|
||||||
|
std::sort(begin(),end());
|
||||||
|
for(iterator i(begin());i!=end();++i) {
|
||||||
|
if (i->first == key)
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
return front().second; // should be unreachable!
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Dictionary::toString() const
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
for(const_iterator kv(begin());kv!=end();++kv) {
|
||||||
|
_appendEsc(kv->first.data(),(unsigned int)kv->first.length(),s);
|
||||||
|
s.push_back('=');
|
||||||
|
_appendEsc(kv->second.data(),(unsigned int)kv->second.length(),s);
|
||||||
|
s.append(ZT_EOL_S);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
void Dictionary::updateFromString(const char *s,unsigned int maxlen)
|
void Dictionary::updateFromString(const char *s,unsigned int maxlen)
|
||||||
{
|
{
|
||||||
bool escapeState = false;
|
bool escapeState = false;
|
||||||
|
@ -80,6 +142,16 @@ void Dictionary::fromString(const char *s,unsigned int maxlen)
|
||||||
updateFromString(s,maxlen);
|
updateFromString(s,maxlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Dictionary::eraseKey(const std::string &key)
|
||||||
|
{
|
||||||
|
for(iterator i(begin());i!=end();++i) {
|
||||||
|
if (i->first == key) {
|
||||||
|
this->erase(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Dictionary::sign(const Identity &id,uint64_t now)
|
bool Dictionary::sign(const Identity &id,uint64_t now)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -31,8 +31,9 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <vector>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Constants.hpp"
|
#include "Constants.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
@ -56,12 +57,12 @@ class Identity;
|
||||||
*
|
*
|
||||||
* Keys beginning with "~!" are reserved for signature data fields.
|
* Keys beginning with "~!" are reserved for signature data fields.
|
||||||
*
|
*
|
||||||
* Note: the signature code depends on std::map<> being sorted, but no
|
* It's stored as a simple vector and can be linearly scanned or
|
||||||
* other code does. So if the underlying data structure is ever swapped
|
* binary searched. Dictionaries are only used for very small things
|
||||||
* out for an unsorted one, the signature code will have to be updated
|
* outside the core loop, so this is not a significant performance
|
||||||
* to sort before composing the string to sign.
|
* issue and it reduces memory use and code footprint.
|
||||||
*/
|
*/
|
||||||
class Dictionary : public std::map<std::string,std::string>
|
class Dictionary : public std::vector< std::pair<std::string,std::string> >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Dictionary() {}
|
Dictionary() {}
|
||||||
|
@ -77,21 +78,8 @@ public:
|
||||||
*/
|
*/
|
||||||
Dictionary(const std::string &s) { fromString(s.c_str(),(unsigned int)s.length()); }
|
Dictionary(const std::string &s) { fromString(s.c_str(),(unsigned int)s.length()); }
|
||||||
|
|
||||||
/**
|
iterator find(const std::string &key);
|
||||||
* Get a key, throwing an exception if it is not present
|
const_iterator find(const std::string &key) const;
|
||||||
*
|
|
||||||
* @param key Key to look up
|
|
||||||
* @return Reference to value
|
|
||||||
* @throws std::invalid_argument Key not found
|
|
||||||
*/
|
|
||||||
inline const std::string &get(const std::string &key) const
|
|
||||||
throw(std::invalid_argument)
|
|
||||||
{
|
|
||||||
const_iterator e(find(key));
|
|
||||||
if (e == end())
|
|
||||||
throw std::invalid_argument(std::string("missing required field: ")+key);
|
|
||||||
return e->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a key, returning a default if not present
|
* Get a key, returning a default if not present
|
||||||
|
@ -113,23 +101,7 @@ public:
|
||||||
* @param dfl Default boolean result if key not found or empty (default: false)
|
* @param dfl Default boolean result if key not found or empty (default: false)
|
||||||
* @return Boolean value of key
|
* @return Boolean value of key
|
||||||
*/
|
*/
|
||||||
inline bool getBoolean(const std::string &key,bool dfl = false) const
|
bool getBoolean(const std::string &key,bool dfl = false) const;
|
||||||
{
|
|
||||||
const_iterator e(find(key));
|
|
||||||
if (e == end())
|
|
||||||
return dfl;
|
|
||||||
if (e->second.length() < 1)
|
|
||||||
return dfl;
|
|
||||||
switch(e->second[0]) {
|
|
||||||
case '1':
|
|
||||||
case 't':
|
|
||||||
case 'T':
|
|
||||||
case 'y':
|
|
||||||
case 'Y':
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param key Key to get
|
* @param key Key to get
|
||||||
|
@ -170,6 +142,8 @@ public:
|
||||||
return Utils::strTo64(e->second.c_str());
|
return Utils::strTo64(e->second.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string &operator[](const std::string &key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param key Key to set
|
* @param key Key to set
|
||||||
* @param value String value
|
* @param value String value
|
||||||
|
@ -239,17 +213,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return String-serialized dictionary
|
* @return String-serialized dictionary
|
||||||
*/
|
*/
|
||||||
inline std::string toString() const
|
std::string toString() const;
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
for(const_iterator kv(begin());kv!=end();++kv) {
|
|
||||||
_appendEsc(kv->first.data(),(unsigned int)kv->first.length(),s);
|
|
||||||
s.push_back('=');
|
|
||||||
_appendEsc(kv->second.data(),(unsigned int)kv->second.length(),s);
|
|
||||||
s.append(ZT_EOL_S);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear and initialize from a string
|
* Clear and initialize from a string
|
||||||
|
@ -278,14 +242,19 @@ public:
|
||||||
*/
|
*/
|
||||||
uint64_t signatureTimestamp() const;
|
uint64_t signatureTimestamp() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key Key to erase
|
||||||
|
*/
|
||||||
|
void eraseKey(const std::string &key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove any signature from this dictionary
|
* Remove any signature from this dictionary
|
||||||
*/
|
*/
|
||||||
inline void removeSignature()
|
inline void removeSignature()
|
||||||
{
|
{
|
||||||
erase(ZT_DICTIONARY_SIGNATURE);
|
eraseKey(ZT_DICTIONARY_SIGNATURE);
|
||||||
erase(ZT_DICTIONARY_SIGNATURE_IDENTITY);
|
eraseKey(ZT_DICTIONARY_SIGNATURE_IDENTITY);
|
||||||
erase(ZT_DICTIONARY_SIGNATURE_TIMESTAMP);
|
eraseKey(ZT_DICTIONARY_SIGNATURE_TIMESTAMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -305,21 +274,6 @@ public:
|
||||||
*/
|
*/
|
||||||
bool verify(const Identity &id) const;
|
bool verify(const Identity &id) const;
|
||||||
|
|
||||||
inline bool operator==(const Dictionary &d) const
|
|
||||||
{
|
|
||||||
// std::map::operator== is broken on uclibc++
|
|
||||||
if (size() != d.size())
|
|
||||||
return false;
|
|
||||||
const_iterator a(begin());
|
|
||||||
const_iterator b(d.begin());
|
|
||||||
while (a != end()) {
|
|
||||||
if (*(a++) != *(b++))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
inline bool operator!=(const Dictionary &d) const { return (!(*this == d)); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _mkSigBuf(std::string &buf) const;
|
void _mkSigBuf(std::string &buf) const;
|
||||||
static void _appendEsc(const char *data,unsigned int len,std::string &to);
|
static void _appendEsc(const char *data,unsigned int len,std::string &to);
|
||||||
|
|
|
@ -87,27 +87,27 @@ void NetworkConfig::_fromDictionary(const Dictionary &d)
|
||||||
|
|
||||||
// NOTE: d.get(name) throws if not found, d.get(name,default) returns default
|
// NOTE: d.get(name) throws if not found, d.get(name,default) returns default
|
||||||
|
|
||||||
_nwid = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID).c_str());
|
_nwid = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,"0").c_str());
|
||||||
if (!_nwid)
|
if (!_nwid)
|
||||||
throw std::invalid_argument("configuration contains zero network ID");
|
throw std::invalid_argument("configuration contains zero network ID");
|
||||||
|
|
||||||
_timestamp = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP).c_str());
|
_timestamp = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,"0").c_str());
|
||||||
_revision = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_REVISION,"1").c_str()); // older controllers don't send this, so default to 1
|
_revision = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_REVISION,"1").c_str()); // older controllers don't send this, so default to 1
|
||||||
|
|
||||||
memset(_etWhitelist,0,sizeof(_etWhitelist));
|
memset(_etWhitelist,0,sizeof(_etWhitelist));
|
||||||
std::vector<std::string> ets(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES).c_str(),",","",""));
|
std::vector<std::string> ets(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES,"").c_str(),",","",""));
|
||||||
for(std::vector<std::string>::const_iterator et(ets.begin());et!=ets.end();++et) {
|
for(std::vector<std::string>::const_iterator et(ets.begin());et!=ets.end();++et) {
|
||||||
unsigned int tmp = Utils::hexStrToUInt(et->c_str()) & 0xffff;
|
unsigned int tmp = Utils::hexStrToUInt(et->c_str()) & 0xffff;
|
||||||
_etWhitelist[tmp >> 3] |= (1 << (tmp & 7));
|
_etWhitelist[tmp >> 3] |= (1 << (tmp & 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
_issuedTo = Address(d.get(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO));
|
_issuedTo = Address(d.get(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,"0"));
|
||||||
_multicastLimit = Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,zero).c_str());
|
_multicastLimit = Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,zero).c_str());
|
||||||
if (_multicastLimit == 0) _multicastLimit = ZT_MULTICAST_DEFAULT_LIMIT;
|
if (_multicastLimit == 0) _multicastLimit = ZT_MULTICAST_DEFAULT_LIMIT;
|
||||||
_allowPassiveBridging = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING,zero).c_str()) != 0);
|
_allowPassiveBridging = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING,zero).c_str()) != 0);
|
||||||
_private = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE,one).c_str()) != 0);
|
_private = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE,one).c_str()) != 0);
|
||||||
_enableBroadcast = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST,one).c_str()) != 0);
|
_enableBroadcast = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST,one).c_str()) != 0);
|
||||||
_name = d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME);
|
_name = d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,"");
|
||||||
if (_name.length() > ZT_MAX_NETWORK_SHORT_NAME_LENGTH)
|
if (_name.length() > ZT_MAX_NETWORK_SHORT_NAME_LENGTH)
|
||||||
throw std::invalid_argument("network short name too long (max: 255 characters)");
|
throw std::invalid_argument("network short name too long (max: 255 characters)");
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ void Topology::setRootServers(const Dictionary &sn)
|
||||||
if ((d->first.length() == ZT_ADDRESS_LENGTH_HEX)&&(d->second.length() > 0)) {
|
if ((d->first.length() == ZT_ADDRESS_LENGTH_HEX)&&(d->second.length() > 0)) {
|
||||||
try {
|
try {
|
||||||
Dictionary snspec(d->second);
|
Dictionary snspec(d->second);
|
||||||
std::vector<InetAddress> &a = m[Identity(snspec.get("id"))];
|
std::vector<InetAddress> &a = m[Identity(snspec.get("id",""))];
|
||||||
std::string udp(snspec.get("udp",std::string()));
|
std::string udp(snspec.get("udp",std::string()));
|
||||||
if (udp.length() > 0)
|
if (udp.length() > 0)
|
||||||
a.push_back(InetAddress(udp));
|
a.push_back(InetAddress(udp));
|
||||||
|
|
Loading…
Add table
Reference in a new issue