Membership.hpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #ifndef ZT_MEMBERSHIP_HPP
  19. #define ZT_MEMBERSHIP_HPP
  20. #include <stdint.h>
  21. #include <map>
  22. #include "Constants.hpp"
  23. #include "../include/ZeroTierOne.h"
  24. #include "CertificateOfMembership.hpp"
  25. #include "Capability.hpp"
  26. #include "Tag.hpp"
  27. #include "Hashtable.hpp"
  28. #include "NetworkConfig.hpp"
  29. // Expiration time for capability and tag cache
  30. #define ZT_MEMBERSHIP_STATE_EXPIRATION_TIME 600000
  31. // Expiration time for Memberships (used in Peer::clean())
  32. #define ZT_MEMBERSHIP_EXPIRATION_TIME (ZT_MEMBERSHIP_STATE_EXPIRATION_TIME * 2)
  33. namespace ZeroTier {
  34. class RuntimeEnvironment;
  35. /**
  36. * A container for certificates of membership and other credentials for peer participation on networks
  37. */
  38. class Membership
  39. {
  40. private:
  41. // Tags and related state
  42. struct TState
  43. {
  44. TState() : lastPushed(0),lastReceived(0) {}
  45. // Last time we pushed OUR tag to this peer (with this ID)
  46. uint64_t lastPushed;
  47. // Last time we received THEIR tag (with this ID)
  48. uint64_t lastReceived;
  49. // THEIR tag
  50. Tag tag;
  51. };
  52. // Credentials and related state
  53. struct CState
  54. {
  55. CState() : lastPushed(0),lastReceived(0) {}
  56. // Last time we pushed OUR capability to this peer (with this ID)
  57. uint64_t lastPushed;
  58. // Last time we received THEIR capability (with this ID)
  59. uint64_t lastReceived;
  60. // THEIR capability
  61. Capability cap;
  62. };
  63. public:
  64. /**
  65. * A wrapper to iterate through capabilities in ascending order of capability ID
  66. */
  67. class CapabilityIterator
  68. {
  69. public:
  70. CapabilityIterator(const Membership &m) :
  71. _i(m._caps.begin()),
  72. _e(m._caps.end())
  73. {
  74. }
  75. inline const Capability *next(const NetworkConfig &nconf)
  76. {
  77. while (_i != _e) {
  78. if ((_i->second.lastReceived)&&(nconf.isCredentialTimestampValid(_i->second.cap)))
  79. return &((_i++)->second.cap);
  80. else ++_i;
  81. }
  82. return (const Capability *)0;
  83. }
  84. private:
  85. std::map<uint32_t,CState>::const_iterator _i,_e;
  86. };
  87. friend class CapabilityIterator;
  88. Membership() :
  89. _lastPushedCom(0),
  90. _com(),
  91. _caps(),
  92. _tags(8)
  93. {
  94. }
  95. /**
  96. * Send COM and other credentials to this peer if needed
  97. *
  98. * This checks last pushed times for our COM and for other credentials and
  99. * sends VERB_NETWORK_CREDENTIALS if the recipient might need them.
  100. *
  101. * @param RR Runtime environment
  102. * @param now Current time
  103. * @param peerAddress Address of member peer
  104. * @param com My network certificate of membership (if any) (not the one here, but ours -- in NetworkConfig)
  105. * @param cap Capability to send or 0 if none
  106. * @param tags Tags that this peer might need
  107. * @param tagCount Number of tag IDs
  108. * @return True if we pushed something
  109. */
  110. bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const CertificateOfMembership &com,const Capability *cap,const Tag **tags,const unsigned int tagCount);
  111. /**
  112. * @return This peer's COM if they have sent one
  113. */
  114. inline const CertificateOfMembership &com() const { return _com; }
  115. /**
  116. * @param nconf Network configuration
  117. * @param id Tag ID
  118. * @return Pointer to tag or NULL if not found
  119. */
  120. inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
  121. {
  122. const TState *t = _tags.get(id);
  123. return ((t) ? (((t->lastReceived != 0)&&(nconf.isCredentialTimestampValid(t->tag))) ? &(t->tag) : (const Tag *)0) : (const Tag *)0);
  124. }
  125. /**
  126. * @param nconf Network configuration
  127. * @param ids Array to store IDs into
  128. * @param values Array to store values into
  129. * @param maxTags Capacity of ids[] and values[]
  130. * @return Number of tags added to arrays
  131. */
  132. inline unsigned int getAllTags(const NetworkConfig &nconf,uint32_t *ids,uint32_t *values,unsigned int maxTags) const
  133. {
  134. unsigned int n = 0;
  135. uint32_t *id = (uint32_t *)0;
  136. TState *ts = (TState *)0;
  137. Hashtable<uint32_t,TState>::Iterator i(const_cast<Membership *>(this)->_tags);
  138. while (i.next(id,ts)) {
  139. if ((ts->lastReceived)&&(nconf.isCredentialTimestampValid(ts->tag))) {
  140. if (n >= maxTags)
  141. return n;
  142. ids[n] = *id;
  143. values[n] = ts->tag.value();
  144. }
  145. }
  146. return n;
  147. }
  148. /**
  149. * @param nconf Network configuration
  150. * @param id Capablity ID
  151. * @return Pointer to capability or NULL if not found
  152. */
  153. inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const
  154. {
  155. std::map<uint32_t,CState>::const_iterator c(_caps.find(id));
  156. return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(nconf.isCredentialTimestampValid(c->second.cap))) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0);
  157. }
  158. /**
  159. * Validate and add a credential if signature is okay and it's otherwise good
  160. *
  161. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  162. */
  163. int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com);
  164. /**
  165. * Validate and add a credential if signature is okay and it's otherwise good
  166. *
  167. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  168. */
  169. int addCredential(const RuntimeEnvironment *RR,const Tag &tag);
  170. /**
  171. * Validate and add a credential if signature is okay and it's otherwise good
  172. *
  173. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  174. */
  175. int addCredential(const RuntimeEnvironment *RR,const Capability &cap);
  176. /**
  177. * Clean up old or stale entries
  178. *
  179. * @return Time of most recent activity in this Membership
  180. */
  181. inline uint64_t clean(const uint64_t now)
  182. {
  183. uint64_t lastAct = _lastPushedCom;
  184. for(std::map<uint32_t,CState>::iterator i(_caps.begin());i!=_caps.end();) {
  185. const uint64_t la = std::max(i->second.lastPushed,i->second.lastReceived);
  186. if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) {
  187. _caps.erase(i++);
  188. } else {
  189. ++i;
  190. if (la > lastAct)
  191. lastAct = la;
  192. }
  193. }
  194. uint32_t *i = (uint32_t *)0;
  195. TState *ts = (TState *)0;
  196. Hashtable<uint32_t,TState>::Iterator tsi(_tags);
  197. while (tsi.next(i,ts)) {
  198. const uint64_t la = std::max(ts->lastPushed,ts->lastReceived);
  199. if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME)
  200. _tags.erase(*i);
  201. else if (la > lastAct)
  202. lastAct = la;
  203. }
  204. return lastAct;
  205. }
  206. private:
  207. // Last time we pushed our COM to this peer
  208. uint64_t _lastPushedCom;
  209. // COM from this peer
  210. CertificateOfMembership _com;
  211. // Capability-related state (we need an ordered container here, hence std::map)
  212. std::map<uint32_t,CState> _caps;
  213. // Tag-related state
  214. Hashtable<uint32_t,TState> _tags;
  215. };
  216. } // namespace ZeroTier
  217. #endif