|
@@ -16,11 +16,13 @@
|
|
|
|
|
|
#include "Constants.hpp"
|
|
#include "Constants.hpp"
|
|
#include "Utils.hpp"
|
|
#include "Utils.hpp"
|
|
-#include "Buffer.hpp"
|
|
|
|
#include "Address.hpp"
|
|
#include "Address.hpp"
|
|
|
|
+#include "Buf.hpp"
|
|
|
|
|
|
#include <cstdint>
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
+#define ZT_DICTIONARY_MAX_CAPACITY 65536
|
|
|
|
+
|
|
namespace ZeroTier {
|
|
namespace ZeroTier {
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -45,32 +47,14 @@ namespace ZeroTier {
|
|
*
|
|
*
|
|
* @tparam C Dictionary max capacity in bytes
|
|
* @tparam C Dictionary max capacity in bytes
|
|
*/
|
|
*/
|
|
-template<unsigned int C>
|
|
|
|
class Dictionary
|
|
class Dictionary
|
|
{
|
|
{
|
|
public:
|
|
public:
|
|
- inline Dictionary() { memset(_d,0,sizeof(_d)); }
|
|
|
|
- inline Dictionary(const char *s) { this->load(s); }
|
|
|
|
- inline Dictionary(const char *s,unsigned int len)
|
|
|
|
- {
|
|
|
|
- for(unsigned int i=0;i<C;++i) {
|
|
|
|
- if ((s)&&(i < len)) {
|
|
|
|
- if (!(_d[i] = *s))
|
|
|
|
- s = (const char *)0;
|
|
|
|
- else ++s;
|
|
|
|
- } else _d[i] = (char)0;
|
|
|
|
- }
|
|
|
|
- _d[C - 1] = (char)0;
|
|
|
|
- }
|
|
|
|
- inline Dictionary(const Dictionary &d) { memcpy(_d,d._d,C); }
|
|
|
|
-
|
|
|
|
- inline Dictionary &operator=(const Dictionary &d)
|
|
|
|
- {
|
|
|
|
- memcpy(_d,d._d,C);
|
|
|
|
- return *this;
|
|
|
|
- }
|
|
|
|
|
|
+ ZT_ALWAYS_INLINE Dictionary() { _d[0] = 0; }
|
|
|
|
+ explicit ZT_ALWAYS_INLINE Dictionary(const char *s) { this->load(s); }
|
|
|
|
+ Dictionary(const char *s,unsigned int len);
|
|
|
|
|
|
- inline operator bool() const { return (_d[0] != 0); }
|
|
|
|
|
|
+ ZT_ALWAYS_INLINE operator bool() const { return (_d[0] != 0); }
|
|
|
|
|
|
/**
|
|
/**
|
|
* Load a dictionary from a C-string
|
|
* Load a dictionary from a C-string
|
|
@@ -78,35 +62,12 @@ public:
|
|
* @param s Dictionary in string form
|
|
* @param s Dictionary in string form
|
|
* @return False if 's' was longer than our capacity
|
|
* @return False if 's' was longer than our capacity
|
|
*/
|
|
*/
|
|
- inline bool load(const char *s)
|
|
|
|
- {
|
|
|
|
- for(unsigned int i=0;i<C;++i) {
|
|
|
|
- if (s) {
|
|
|
|
- if (!(_d[i] = *s))
|
|
|
|
- s = (const char *)0;
|
|
|
|
- else ++s;
|
|
|
|
- } else _d[i] = (char)0;
|
|
|
|
- }
|
|
|
|
- _d[C - 1] = (char)0;
|
|
|
|
- return (!s);
|
|
|
|
- }
|
|
|
|
|
|
+ bool load(const char *s);
|
|
|
|
|
|
/**
|
|
/**
|
|
* Delete all entries
|
|
* Delete all entries
|
|
*/
|
|
*/
|
|
- inline void clear() { memset(_d,0,sizeof(_d)); }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * @return Size of dictionary in bytes not including terminating NULL
|
|
|
|
- */
|
|
|
|
- inline unsigned int sizeBytes() const
|
|
|
|
- {
|
|
|
|
- for(unsigned int i=0;i<C;++i) {
|
|
|
|
- if (!_d[i])
|
|
|
|
- return i;
|
|
|
|
- }
|
|
|
|
- return C-1;
|
|
|
|
- }
|
|
|
|
|
|
+ ZT_ALWAYS_INLINE void clear() { memset(_d,0,sizeof(_d)); }
|
|
|
|
|
|
/**
|
|
/**
|
|
* Get an entry
|
|
* Get an entry
|
|
@@ -130,104 +91,7 @@ public:
|
|
* @param destlen Size of destination buffer
|
|
* @param destlen Size of destination buffer
|
|
* @return -1 if not found, or actual number of bytes stored in dest[] minus trailing 0
|
|
* @return -1 if not found, or actual number of bytes stored in dest[] minus trailing 0
|
|
*/
|
|
*/
|
|
- inline int get(const char *key,char *dest,unsigned int destlen) const
|
|
|
|
- {
|
|
|
|
- const char *p = _d;
|
|
|
|
- const char *const eof = p + C;
|
|
|
|
- const char *k;
|
|
|
|
- bool esc;
|
|
|
|
- int j;
|
|
|
|
-
|
|
|
|
- if (!destlen) // sanity check
|
|
|
|
- return -1;
|
|
|
|
-
|
|
|
|
- while (*p) {
|
|
|
|
- k = key;
|
|
|
|
- while ((*k)&&(*p)) {
|
|
|
|
- if (*p != *k)
|
|
|
|
- break;
|
|
|
|
- ++k;
|
|
|
|
- if (++p == eof) {
|
|
|
|
- dest[0] = (char)0;
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if ((!*k)&&(*p == '=')) {
|
|
|
|
- j = 0;
|
|
|
|
- esc = false;
|
|
|
|
- ++p;
|
|
|
|
- while ((*p != 0)&&(*p != 13)&&(*p != 10)) {
|
|
|
|
- if (esc) {
|
|
|
|
- esc = false;
|
|
|
|
- switch(*p) {
|
|
|
|
- case 'r': dest[j++] = 13; break;
|
|
|
|
- case 'n': dest[j++] = 10; break;
|
|
|
|
- case '0': dest[j++] = (char)0; break;
|
|
|
|
- case 'e': dest[j++] = '='; break;
|
|
|
|
- default: dest[j++] = *p; break;
|
|
|
|
- }
|
|
|
|
- if (j == (int)destlen) {
|
|
|
|
- dest[j-1] = (char)0;
|
|
|
|
- return j-1;
|
|
|
|
- }
|
|
|
|
- } else if (*p == '\\') {
|
|
|
|
- esc = true;
|
|
|
|
- } else {
|
|
|
|
- dest[j++] = *p;
|
|
|
|
- if (j == (int)destlen) {
|
|
|
|
- dest[j-1] = (char)0;
|
|
|
|
- return j-1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (++p == eof) {
|
|
|
|
- dest[0] = (char)0;
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- dest[j] = (char)0;
|
|
|
|
- return j;
|
|
|
|
- } else {
|
|
|
|
- while ((*p)&&(*p != 13)&&(*p != 10)) {
|
|
|
|
- if (++p == eof) {
|
|
|
|
- dest[0] = (char)0;
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (*p) {
|
|
|
|
- if (++p == eof) {
|
|
|
|
- dest[0] = (char)0;
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- dest[0] = (char)0;
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Get the contents of a key into a buffer
|
|
|
|
- *
|
|
|
|
- * @param key Key to get
|
|
|
|
- * @param dest Destination buffer
|
|
|
|
- * @return True if key was found (if false, dest will be empty)
|
|
|
|
- * @tparam BC Buffer capacity (usually inferred)
|
|
|
|
- */
|
|
|
|
- template<unsigned int BC>
|
|
|
|
- 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())),BC);
|
|
|
|
- if (r >= 0) {
|
|
|
|
- dest.setSize((unsigned int)r);
|
|
|
|
- return true;
|
|
|
|
- } else {
|
|
|
|
- dest.clear();
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ int get(const char *key,char *dest,unsigned int destlen) const;
|
|
|
|
|
|
/**
|
|
/**
|
|
* Get a boolean value
|
|
* Get a boolean value
|
|
@@ -236,7 +100,7 @@ public:
|
|
* @param dfl Default value if not found in dictionary
|
|
* @param dfl Default value if not found in dictionary
|
|
* @return Boolean value of key or 'dfl' if not found
|
|
* @return Boolean value of key or 'dfl' if not found
|
|
*/
|
|
*/
|
|
- inline bool getB(const char *key,bool dfl = false) const
|
|
|
|
|
|
+ ZT_ALWAYS_INLINE bool getB(const char *key,bool dfl = false) const
|
|
{
|
|
{
|
|
char tmp[4];
|
|
char tmp[4];
|
|
if (this->get(key,tmp,sizeof(tmp)) >= 0)
|
|
if (this->get(key,tmp,sizeof(tmp)) >= 0)
|
|
@@ -251,7 +115,7 @@ public:
|
|
* @param dfl Default value or 0 if unspecified
|
|
* @param dfl Default value or 0 if unspecified
|
|
* @return Decoded hex UInt value or 'dfl' if not found
|
|
* @return Decoded hex UInt value or 'dfl' if not found
|
|
*/
|
|
*/
|
|
- inline uint64_t getUI(const char *key,uint64_t dfl = 0) const
|
|
|
|
|
|
+ ZT_ALWAYS_INLINE uint64_t getUI(const char *key,uint64_t dfl = 0) const
|
|
{
|
|
{
|
|
char tmp[128];
|
|
char tmp[128];
|
|
if (this->get(key,tmp,sizeof(tmp)) >= 1)
|
|
if (this->get(key,tmp,sizeof(tmp)) >= 1)
|
|
@@ -266,7 +130,7 @@ public:
|
|
* @param dfl Default value or 0 if unspecified
|
|
* @param dfl Default value or 0 if unspecified
|
|
* @return Decoded hex UInt value or 'dfl' if not found
|
|
* @return Decoded hex UInt value or 'dfl' if not found
|
|
*/
|
|
*/
|
|
- inline int64_t getI(const char *key,int64_t dfl = 0) const
|
|
|
|
|
|
+ ZT_ALWAYS_INLINE int64_t getI(const char *key,int64_t dfl = 0) const
|
|
{
|
|
{
|
|
char tmp[128];
|
|
char tmp[128];
|
|
if (this->get(key,tmp,sizeof(tmp)) >= 1)
|
|
if (this->get(key,tmp,sizeof(tmp)) >= 1)
|
|
@@ -288,137 +152,33 @@ public:
|
|
* @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0
|
|
* @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0
|
|
* @return True if there was enough room to add this key=value pair
|
|
* @return True if there was enough room to add this key=value pair
|
|
*/
|
|
*/
|
|
- inline bool add(const char *key,const char *value,int vlen = -1)
|
|
|
|
- {
|
|
|
|
- for(unsigned int i=0;i<C;++i) {
|
|
|
|
- if (!_d[i]) {
|
|
|
|
- unsigned int j = i;
|
|
|
|
-
|
|
|
|
- if (j > 0) {
|
|
|
|
- _d[j++] = (char)10;
|
|
|
|
- if (j == C) {
|
|
|
|
- _d[i] = (char)0;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const char *p = key;
|
|
|
|
- while (*p) {
|
|
|
|
- _d[j++] = *(p++);
|
|
|
|
- if (j == C) {
|
|
|
|
- _d[i] = (char)0;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _d[j++] = '=';
|
|
|
|
- if (j == C) {
|
|
|
|
- _d[i] = (char)0;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- p = value;
|
|
|
|
- int k = 0;
|
|
|
|
- while ( ((vlen < 0)&&(*p)) || (k < vlen) ) {
|
|
|
|
- switch(*p) {
|
|
|
|
- case 0:
|
|
|
|
- case 13:
|
|
|
|
- case 10:
|
|
|
|
- case '\\':
|
|
|
|
- case '=':
|
|
|
|
- _d[j++] = '\\';
|
|
|
|
- if (j == C) {
|
|
|
|
- _d[i] = (char)0;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- switch(*p) {
|
|
|
|
- case 0: _d[j++] = '0'; break;
|
|
|
|
- case 13: _d[j++] = 'r'; break;
|
|
|
|
- case 10: _d[j++] = 'n'; break;
|
|
|
|
- case '\\': _d[j++] = '\\'; break;
|
|
|
|
- case '=': _d[j++] = 'e'; break;
|
|
|
|
- }
|
|
|
|
- if (j == C) {
|
|
|
|
- _d[i] = (char)0;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- _d[j++] = *p;
|
|
|
|
- if (j == C) {
|
|
|
|
- _d[i] = (char)0;
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- ++p;
|
|
|
|
- ++k;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _d[j] = (char)0;
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
|
|
+ bool add(const char *key,const char *value,int vlen = -1);
|
|
|
|
|
|
/**
|
|
/**
|
|
* Add a boolean as a '1' or a '0'
|
|
* Add a boolean as a '1' or a '0'
|
|
*/
|
|
*/
|
|
- inline bool add(const char *key,bool value)
|
|
|
|
- {
|
|
|
|
- return this->add(key,(value) ? "1" : "0",1);
|
|
|
|
- }
|
|
|
|
|
|
+ bool add(const char *key,bool value);
|
|
|
|
|
|
/**
|
|
/**
|
|
* Add a 64-bit integer (unsigned) as a hex value
|
|
* Add a 64-bit integer (unsigned) as a hex value
|
|
*/
|
|
*/
|
|
- inline bool add(const char *key,uint64_t value)
|
|
|
|
- {
|
|
|
|
- char tmp[32];
|
|
|
|
- return this->add(key,Utils::hex(value,tmp),-1);
|
|
|
|
- }
|
|
|
|
|
|
+ bool add(const char *key,uint64_t value);
|
|
|
|
|
|
/**
|
|
/**
|
|
* Add a 64-bit integer (unsigned) as a hex value
|
|
* Add a 64-bit integer (unsigned) as a hex value
|
|
*/
|
|
*/
|
|
- inline bool add(const char *key,int64_t value)
|
|
|
|
- {
|
|
|
|
- char tmp[32];
|
|
|
|
- if (value >= 0) {
|
|
|
|
- return this->add(key,Utils::hex((uint64_t)value,tmp),-1);
|
|
|
|
- } else {
|
|
|
|
- tmp[0] = '-';
|
|
|
|
- return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ bool add(const char *key,int64_t value);
|
|
|
|
|
|
/**
|
|
/**
|
|
* Add a 64-bit integer (unsigned) as a hex value
|
|
* Add a 64-bit integer (unsigned) as a hex value
|
|
*/
|
|
*/
|
|
- inline bool add(const char *key,const Address &a)
|
|
|
|
- {
|
|
|
|
- char tmp[32];
|
|
|
|
- return this->add(key,Utils::hex(a.toInt(),tmp),-1);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Add a binary buffer's contents as a value
|
|
|
|
- *
|
|
|
|
- * @tparam BC Buffer capacity (usually inferred)
|
|
|
|
- */
|
|
|
|
- template<unsigned int BC>
|
|
|
|
- inline bool add(const char *key,const Buffer<BC> &value)
|
|
|
|
- {
|
|
|
|
- return this->add(key,(const char *)value.data(),(int)value.size());
|
|
|
|
- }
|
|
|
|
|
|
+ bool add(const char *key,const Address &a);
|
|
|
|
|
|
/**
|
|
/**
|
|
* @param key Key to check
|
|
* @param key Key to check
|
|
* @return True if key is present
|
|
* @return True if key is present
|
|
*/
|
|
*/
|
|
- inline bool contains(const char *key) const
|
|
|
|
|
|
+ ZT_ALWAYS_INLINE bool contains(const char *key) const
|
|
{
|
|
{
|
|
char tmp[2];
|
|
char tmp[2];
|
|
return (this->get(key,tmp,2) >= 0);
|
|
return (this->get(key,tmp,2) >= 0);
|
|
@@ -427,13 +187,12 @@ public:
|
|
/**
|
|
/**
|
|
* @return Value of C template parameter
|
|
* @return Value of C template parameter
|
|
*/
|
|
*/
|
|
- inline unsigned int capacity() const { return C; }
|
|
|
|
|
|
+ ZT_ALWAYS_INLINE unsigned int capacity() const { return sizeof(_d); }
|
|
|
|
|
|
- inline const char *data() const { return _d; }
|
|
|
|
- inline char *unsafeData() { return _d; }
|
|
|
|
|
|
+ ZT_ALWAYS_INLINE const char *data() const { return _d; }
|
|
|
|
|
|
private:
|
|
private:
|
|
- char _d[C];
|
|
|
|
|
|
+ char _d[ZT_DICTIONARY_MAX_CAPACITY];
|
|
};
|
|
};
|
|
|
|
|
|
} // namespace ZeroTier
|
|
} // namespace ZeroTier
|