summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
Diffstat (limited to 'node')
-rw-r--r--node/Dictionary.cpp72
-rw-r--r--node/Dictionary.hpp88
-rw-r--r--node/NetworkConfig.cpp10
-rw-r--r--node/Topology.cpp2
4 files changed, 99 insertions, 73 deletions
diff --git a/node/Dictionary.cpp b/node/Dictionary.cpp
index fb49002a..578fdedc 100644
--- a/node/Dictionary.cpp
+++ b/node/Dictionary.cpp
@@ -32,6 +32,68 @@
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)
{
bool escapeState = false;
@@ -80,6 +142,16 @@ void Dictionary::fromString(const char *s,unsigned int 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)
{
try {
diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp
index 1e643788..24f2ac8f 100644
--- a/node/Dictionary.hpp
+++ b/node/Dictionary.hpp
@@ -31,8 +31,9 @@
#include <stdint.h>
#include <string>
-#include <map>
+#include <vector>
#include <stdexcept>
+#include <algorithm>
#include "Constants.hpp"
#include "Utils.hpp"
@@ -56,12 +57,12 @@ class Identity;
*
* Keys beginning with "~!" are reserved for signature data fields.
*
- * Note: the signature code depends on std::map<> being sorted, but no
- * other code does. So if the underlying data structure is ever swapped
- * out for an unsorted one, the signature code will have to be updated
- * to sort before composing the string to sign.
+ * It's stored as a simple vector and can be linearly scanned or
+ * binary searched. Dictionaries are only used for very small things
+ * outside the core loop, so this is not a significant performance
+ * 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:
Dictionary() {}
@@ -77,21 +78,8 @@ public:
*/
Dictionary(const std::string &s) { fromString(s.c_str(),(unsigned int)s.length()); }
- /**
- * Get a key, throwing an exception if it is not present
- *
- * @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;
- }
+ iterator find(const std::string &key);
+ const_iterator find(const std::string &key) const;
/**
* 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)
* @return Boolean value of key
*/
- inline 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;
- }
+ bool getBoolean(const std::string &key,bool dfl = false) const;
/**
* @param key Key to get
@@ -170,6 +142,8 @@ public:
return Utils::strTo64(e->second.c_str());
}
+ std::string &operator[](const std::string &key);
+
/**
* @param key Key to set
* @param value String value
@@ -239,17 +213,7 @@ public:
/**
* @return String-serialized dictionary
*/
- inline 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;
- }
+ std::string toString() const;
/**
* Clear and initialize from a string
@@ -279,13 +243,18 @@ public:
uint64_t signatureTimestamp() const;
/**
+ * @param key Key to erase
+ */
+ void eraseKey(const std::string &key);
+
+ /**
* Remove any signature from this dictionary
*/
inline void removeSignature()
{
- erase(ZT_DICTIONARY_SIGNATURE);
- erase(ZT_DICTIONARY_SIGNATURE_IDENTITY);
- erase(ZT_DICTIONARY_SIGNATURE_TIMESTAMP);
+ eraseKey(ZT_DICTIONARY_SIGNATURE);
+ eraseKey(ZT_DICTIONARY_SIGNATURE_IDENTITY);
+ eraseKey(ZT_DICTIONARY_SIGNATURE_TIMESTAMP);
}
/**
@@ -305,21 +274,6 @@ public:
*/
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:
void _mkSigBuf(std::string &buf) const;
static void _appendEsc(const char *data,unsigned int len,std::string &to);
diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp
index e46da4a4..cd32600f 100644
--- a/node/NetworkConfig.cpp
+++ b/node/NetworkConfig.cpp
@@ -87,27 +87,27 @@ void NetworkConfig::_fromDictionary(const Dictionary &d)
// 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)
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
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) {
unsigned int tmp = Utils::hexStrToUInt(et->c_str()) & 0xffff;
_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());
if (_multicastLimit == 0) _multicastLimit = ZT_MULTICAST_DEFAULT_LIMIT;
_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);
_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)
throw std::invalid_argument("network short name too long (max: 255 characters)");
diff --git a/node/Topology.cpp b/node/Topology.cpp
index 65abfc6f..908acbc8 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -140,7 +140,7 @@ void Topology::setRootServers(const Dictionary &sn)
if ((d->first.length() == ZT_ADDRESS_LENGTH_HEX)&&(d->second.length() > 0)) {
try {
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()));
if (udp.length() > 0)
a.push_back(InetAddress(udp));