Dictionary.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2024-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #ifndef ZT_DICTIONARY_HPP
  14. #define ZT_DICTIONARY_HPP
  15. #include "Constants.hpp"
  16. #include "Utils.hpp"
  17. #include "Address.hpp"
  18. #include "Buf.hpp"
  19. #include <cstdint>
  20. #include <vector>
  21. #include <map>
  22. namespace ZeroTier {
  23. /**
  24. * A simple key-value store for short keys
  25. *
  26. * This data structure is used for network configurations, node meta-data,
  27. * and other open-definition protocol objects. It consists of a key-value
  28. * store with short (max: 8 characters) keys that map to strings, blobs,
  29. * or integers with the latter being by convention in hex format.
  30. *
  31. * If this seems a little odd, it is. It dates back to the very first alpha
  32. * versions of ZeroTier and if it were redesigned today we'd use some kind
  33. * of simple or standardized binary encoding. Nevertheless it is efficient
  34. * and it works so there is no need to change it and break backward
  35. * compatibility.
  36. */
  37. class Dictionary
  38. {
  39. public:
  40. Dictionary();
  41. ~Dictionary();
  42. /**
  43. * Get a reference to a value
  44. *
  45. * @param k Key to look up
  46. * @return Reference to value
  47. */
  48. std::vector<uint8_t> &operator[](const char *k);
  49. /**
  50. * Get a const reference to a value
  51. *
  52. * @param k Key to look up
  53. * @return Reference to value or to empty vector if not found
  54. */
  55. const std::vector<uint8_t> &operator[](const char *k) const;
  56. /**
  57. * Add a boolean as '1' or '0'
  58. */
  59. void add(const char *k,bool v);
  60. /**
  61. * Add an integer as a hexadecimal string value
  62. */
  63. void add(const char *k,uint16_t v);
  64. /**
  65. * Add an integer as a hexadecimal string value
  66. */
  67. void add(const char *k,uint32_t v);
  68. /**
  69. * Add an integer as a hexadecimal string value
  70. */
  71. void add(const char *k,uint64_t v);
  72. ZT_INLINE void add(const char *k,int16_t v) { add(k,(uint16_t)v); }
  73. ZT_INLINE void add(const char *k,int32_t v) { add(k,(uint32_t)v); }
  74. ZT_INLINE void add(const char *k,int64_t v) { add(k,(uint64_t)v); }
  75. /**
  76. * Add an address in 10-digit hex string format
  77. */
  78. void add(const char *k,const Address &v);
  79. /**
  80. * Add a C string as a value
  81. */
  82. void add(const char *k,const char *v);
  83. /**
  84. * Add a binary blob as a value
  85. */
  86. void add(const char *k,const void *data,unsigned int len);
  87. /**
  88. * Get a boolean
  89. *
  90. * @param k Key to look up
  91. * @param dfl Default value (default: false)
  92. * @return Value of key or default if not found
  93. */
  94. bool getB(const char *k,bool dfl = false) const;
  95. /**
  96. * Get an integer
  97. *
  98. * @param k Key to look up
  99. * @param dfl Default value (default: 0)
  100. * @return Value of key or default if not found
  101. */
  102. uint64_t getUI(const char *k,uint64_t dfl = 0) const;
  103. /**
  104. * Get a C string
  105. *
  106. * If the buffer is too small the string will be truncated, but the
  107. * buffer will always end in a terminating null no matter what.
  108. *
  109. * @param k Key to look up
  110. * @param v Buffer to hold string
  111. * @param cap Maximum size of string (including terminating null)
  112. */
  113. void getS(const char *k,char *v,unsigned int cap) const;
  114. /**
  115. * Erase all entries in dictionary
  116. */
  117. void clear();
  118. /**
  119. * @return Number of entries
  120. */
  121. ZT_INLINE unsigned int size() const noexcept { return _t.size(); }
  122. /**
  123. * @return True if dictionary is not empty
  124. */
  125. ZT_INLINE bool empty() const noexcept { return _t.empty(); }
  126. /**
  127. * Encode to a string in the supplied vector
  128. *
  129. * This does not add a terminating zero. This must be pushed afterwords
  130. * if the result is to be handled as a C string.
  131. *
  132. * @param out String encoded dictionary
  133. */
  134. void encode(std::vector<uint8_t> &out) const;
  135. /**
  136. * Decode a string encoded dictionary
  137. *
  138. * This will decode up to 'len' but will also abort if it finds a
  139. * null/zero as this could be a C string.
  140. *
  141. * @param data Data to decode
  142. * @param len Length of data
  143. * @return True if dictionary was formatted correctly and valid, false on error
  144. */
  145. bool decode(const void *data,unsigned int len);
  146. private:
  147. // This just packs up to 8 character bytes into a 64-bit word. There is no need
  148. // for this to be portable in terms of endian-ness. It's just for fast key lookup.
  149. static ZT_INLINE uint64_t _toKey(const char *k)
  150. {
  151. uint64_t key = 0;
  152. for(int i=0;i<8;++i) {
  153. if ((reinterpret_cast<uint8_t *>(&key)[i] = *(k++)) == 0)
  154. break;
  155. }
  156. return key;
  157. }
  158. std::map< uint64_t,std::vector<uint8_t> > _t;
  159. };
  160. } // namespace ZeroTier
  161. #endif