Topology.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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_TOPOLOGY_HPP
  14. #define ZT_TOPOLOGY_HPP
  15. #include "Constants.hpp"
  16. #include "Address.hpp"
  17. #include "Identity.hpp"
  18. #include "Peer.hpp"
  19. #include "Path.hpp"
  20. #include "Mutex.hpp"
  21. #include "InetAddress.hpp"
  22. #include "SharedPtr.hpp"
  23. #include "ScopedPtr.hpp"
  24. #include "Fingerprint.hpp"
  25. #include "Containers.hpp"
  26. namespace ZeroTier {
  27. class RuntimeEnvironment;
  28. /**
  29. * Database of network topology
  30. */
  31. class Topology
  32. {
  33. public:
  34. Topology(const RuntimeEnvironment *renv,void *tPtr);
  35. /**
  36. * Add peer to database
  37. *
  38. * This will not replace existing peers. In that case the existing peer
  39. * record is returned.
  40. *
  41. * @param peer Peer to add
  42. * @return New or existing peer (should replace 'peer')
  43. */
  44. SharedPtr<Peer> add(void *tPtr,const SharedPtr<Peer> &peer);
  45. /**
  46. * Get a peer from its address
  47. *
  48. * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
  49. * @param zta ZeroTier address of peer
  50. * @param loadFromCached If false do not load from cache if not in memory (default: true)
  51. * @return Peer or NULL if not found
  52. */
  53. ZT_INLINE SharedPtr<Peer> peer(void *tPtr,const Address &zta,const bool loadFromCached = true)
  54. {
  55. {
  56. RWMutex::RLock l(m_peers_l);
  57. const SharedPtr<Peer> *const ap = m_peers.get(zta);
  58. if (likely(ap != nullptr))
  59. return *ap;
  60. }
  61. {
  62. SharedPtr<Peer> p;
  63. if (loadFromCached) {
  64. m_loadCached(tPtr, zta, p);
  65. if (p) {
  66. RWMutex::Lock l(m_peers_l);
  67. SharedPtr<Peer> &hp = m_peers[zta];
  68. if (hp)
  69. return hp;
  70. hp = p;
  71. }
  72. }
  73. return p;
  74. }
  75. }
  76. /**
  77. * Get a Path object for a given local and remote physical address, creating if needed
  78. *
  79. * @param l Local socket
  80. * @param r Remote address
  81. * @return Pointer to canonicalized Path object or NULL on error
  82. */
  83. ZT_INLINE SharedPtr<Path> path(const int64_t l,const InetAddress &r)
  84. {
  85. const uint64_t k = s_getPathKey(l, r);
  86. {
  87. RWMutex::RLock lck(m_paths_l);
  88. SharedPtr<Path> *const p = m_paths.get(k);
  89. if (likely(p != nullptr))
  90. return *p;
  91. }
  92. {
  93. SharedPtr<Path> p(new Path(l,r));
  94. RWMutex::Lock lck(m_paths_l);
  95. SharedPtr<Path> &p2 = m_paths[k];
  96. if (p2)
  97. return p2;
  98. p2 = p;
  99. return p;
  100. }
  101. }
  102. /**
  103. * @return Current best root server
  104. */
  105. ZT_INLINE SharedPtr<Peer> root() const
  106. {
  107. RWMutex::RLock l(m_peers_l);
  108. if (unlikely(m_rootPeers.empty()))
  109. return SharedPtr<Peer>();
  110. return m_rootPeers.front();
  111. }
  112. /**
  113. * @param id Identity to check
  114. * @return True if this identity corresponds to a root
  115. */
  116. ZT_INLINE bool isRoot(const Identity &id) const
  117. {
  118. RWMutex::RLock l(m_peers_l);
  119. return (m_roots.find(id) != m_roots.end());
  120. }
  121. /**
  122. * Apply a function or function object to all peers
  123. *
  124. * This locks the peer map during execution, so calls to get() etc. during
  125. * eachPeer() will deadlock.
  126. *
  127. * @param f Function to apply
  128. * @tparam F Function or function object type
  129. */
  130. template<typename F>
  131. ZT_INLINE void eachPeer(F f) const
  132. {
  133. RWMutex::RLock l(m_peers_l);
  134. for(Map< Address,SharedPtr<Peer> >::const_iterator i(m_peers.begin());i != m_peers.end();++i)
  135. f(i->second);
  136. }
  137. /**
  138. * Apply a function or function object to all peers
  139. *
  140. * This locks the peer map during execution, so calls to get() etc. during
  141. * eachPeer() will deadlock.
  142. *
  143. * @param f Function to apply
  144. * @tparam F Function or function object type
  145. */
  146. template<typename F>
  147. ZT_INLINE void eachPeerWithRoot(F f) const
  148. {
  149. RWMutex::RLock l(m_peers_l);
  150. Vector<uintptr_t> rootPeerPtrs;
  151. rootPeerPtrs.reserve(m_rootPeers.size());
  152. for(Vector< SharedPtr<Peer> >::const_iterator rp(m_rootPeers.begin());rp != m_rootPeers.end();++rp)
  153. rootPeerPtrs.push_back((uintptr_t)rp->ptr());
  154. std::sort(rootPeerPtrs.begin(),rootPeerPtrs.end());
  155. for(Map< Address,SharedPtr<Peer> >::const_iterator i(m_peers.begin());i != m_peers.end();++i)
  156. f(i->second,std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)i->second.ptr()));
  157. }
  158. /**
  159. * @param allPeers vector to fill with all current peers
  160. */
  161. ZT_INLINE void getAllPeers(Vector< SharedPtr<Peer> > &allPeers) const
  162. {
  163. RWMutex::RLock l(m_peers_l);
  164. allPeers.clear();
  165. allPeers.reserve(m_peers.size());
  166. for(Map< Address,SharedPtr<Peer> >::const_iterator i(m_peers.begin());i != m_peers.end();++i)
  167. allPeers.push_back(i->second);
  168. }
  169. /**
  170. * Add or update a root server and its locator
  171. *
  172. * This also validates the identity and checks the locator signature,
  173. * returning false if either of these is not valid.
  174. *
  175. * @param tPtr Thread pointer
  176. * @param id Root identity
  177. * @param loc Root locator
  178. * @return True if identity and locator are valid and root was added / updated
  179. */
  180. bool addRoot(void *tPtr,const Identity &id,const SharedPtr<const Locator> &loc);
  181. /**
  182. * Remove a root server's identity from the root server set
  183. *
  184. * @param tPtr Thread pointer
  185. * @param address Root address
  186. * @return True if root found and removed, false if not found
  187. */
  188. bool removeRoot(void *tPtr, Address address);
  189. /**
  190. * Sort roots in ascending order of apparent latency
  191. *
  192. * @param now Current time
  193. */
  194. void rankRoots();
  195. /**
  196. * Do periodic tasks such as database cleanup
  197. */
  198. void doPeriodicTasks(void *tPtr,int64_t now);
  199. /**
  200. * Save all currently known peers to data store
  201. */
  202. void saveAll(void *tPtr);
  203. private:
  204. void m_loadCached(void *tPtr, const Address &zta, SharedPtr<Peer> &peer);
  205. void m_writeRootList(void *tPtr);
  206. void m_updateRootPeers(void *tPtr);
  207. // This gets an integer key from an InetAddress for looking up paths.
  208. static ZT_INLINE uint64_t s_getPathKey(const int64_t l,const InetAddress &r) noexcept
  209. {
  210. // SECURITY: these will be used as keys in a Map<> which uses its own hasher that
  211. // mixes in a per-invocation secret to work against hash collision attacks. See the
  212. // map hasher in Containers.hpp. Otherwise the point here is really really fast
  213. // path lookup by address. The number of paths is never likely to be high enough
  214. // for a collision to be something we worry about. That would require a minimum of
  215. // millions and millions of paths on a single node.
  216. if (r.family() == AF_INET) {
  217. return ((uint64_t)(r.as.sa_in.sin_addr.s_addr) << 32U) ^ ((uint64_t)r.as.sa_in.sin_port << 16U) ^ (uint64_t)l;
  218. } else if (r.family() == AF_INET6) {
  219. return Utils::loadAsIsEndian<uint64_t>(r.as.sa_in6.sin6_addr.s6_addr) + Utils::loadAsIsEndian<uint64_t>(r.as.sa_in6.sin6_addr.s6_addr + 8) + (uint64_t)r.as.sa_in6.sin6_port + (uint64_t)l;
  220. } else {
  221. // This should never really be used but it's here just in case.
  222. return (uint64_t)Utils::fnv1a32(reinterpret_cast<const void *>(&r),sizeof(InetAddress)) + (uint64_t)l;
  223. }
  224. }
  225. const RuntimeEnvironment *const RR;
  226. RWMutex m_paths_l; // locks m_paths
  227. RWMutex m_peers_l; // locks m_peers, m_roots, and m_rootPeers
  228. Map< uint64_t,SharedPtr<Path> > m_paths;
  229. Map< Address,SharedPtr<Peer> > m_peers;
  230. Map< Identity,SharedPtr<const Locator> > m_roots;
  231. Vector< SharedPtr<Peer> > m_rootPeers;
  232. };
  233. } // namespace ZeroTier
  234. #endif