Topology.hpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * Copyright (c)2019 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: 2023-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 <cstdio>
  16. #include <cstring>
  17. #include <vector>
  18. #include <algorithm>
  19. #include <utility>
  20. #include <set>
  21. #include "Constants.hpp"
  22. #include "../include/ZeroTierOne.h"
  23. #include "Address.hpp"
  24. #include "Identity.hpp"
  25. #include "Peer.hpp"
  26. #include "Path.hpp"
  27. #include "Mutex.hpp"
  28. #include "InetAddress.hpp"
  29. #include "Hashtable.hpp"
  30. #include "SharedPtr.hpp"
  31. #include "ScopedPtr.hpp"
  32. namespace ZeroTier {
  33. class RuntimeEnvironment;
  34. /**
  35. * Database of network topology
  36. */
  37. class Topology
  38. {
  39. public:
  40. Topology(const RuntimeEnvironment *renv,const Identity &myId);
  41. ~Topology();
  42. /**
  43. * Add peer to database
  44. *
  45. * This will not replace existing peers. In that case the existing peer
  46. * record is returned.
  47. *
  48. * @param peer Peer to add
  49. * @return New or existing peer (should replace 'peer')
  50. */
  51. SharedPtr<Peer> add(void *tPtr,const SharedPtr<Peer> &peer);
  52. /**
  53. * Get a peer from its address
  54. *
  55. * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
  56. * @param zta ZeroTier address of peer
  57. * @return Peer or NULL if not found
  58. */
  59. ZT_ALWAYS_INLINE SharedPtr<Peer> get(void *tPtr,const Address &zta)
  60. {
  61. {
  62. RWMutex::RLock _l(_peers_l);
  63. const SharedPtr<Peer> *const ap = _peers.get(zta);
  64. if (ap)
  65. return *ap;
  66. }
  67. SharedPtr<Peer> p;
  68. _loadCached(tPtr,zta,p);
  69. if (p) {
  70. RWMutex::Lock _l(_peers_l);
  71. SharedPtr<Peer> &hp = _peers[zta];
  72. if (!hp)
  73. hp = p;
  74. }
  75. return p;
  76. }
  77. /**
  78. * Get a Path object for a given local and remote physical address, creating if needed
  79. *
  80. * @param l Local socket
  81. * @param r Remote address
  82. * @return Pointer to canonicalized Path object or NULL on error
  83. */
  84. ZT_ALWAYS_INLINE SharedPtr<Path> getPath(const int64_t l,const InetAddress &r)
  85. {
  86. const Path::HashKey k(l,r);
  87. _paths_l.rlock();
  88. SharedPtr<Path> p(_paths[k]);
  89. _paths_l.runlock();
  90. if (p)
  91. return p;
  92. _paths_l.lock();
  93. SharedPtr<Path> &p2 = _paths[k];
  94. if (p2) {
  95. p = p2;
  96. } else {
  97. try {
  98. p.set(new Path(l,r));
  99. } catch ( ... ) {
  100. _paths_l.unlock();
  101. return SharedPtr<Path>();
  102. }
  103. p2 = p;
  104. }
  105. _paths_l.unlock();
  106. return p;
  107. }
  108. /**
  109. * @return Current best root server
  110. */
  111. ZT_ALWAYS_INLINE SharedPtr<Peer> root() const
  112. {
  113. RWMutex::RLock l(_peers_l);
  114. if (_rootPeers.empty())
  115. return SharedPtr<Peer>();
  116. return _rootPeers.front();
  117. }
  118. /**
  119. * @param id Identity to check
  120. * @return True if this identity corresponds to a root
  121. */
  122. ZT_ALWAYS_INLINE bool isRoot(const Identity &id) const
  123. {
  124. RWMutex::RLock l(_peers_l);
  125. return (_roots.count(id) > 0);
  126. }
  127. /**
  128. * Apply a function or function object to all peers
  129. *
  130. * This locks the peer map during execution, so calls to get() etc. during
  131. * eachPeer() will deadlock.
  132. *
  133. * @param f Function to apply
  134. * @tparam F Function or function object type
  135. */
  136. template<typename F>
  137. ZT_ALWAYS_INLINE void eachPeer(F f) const
  138. {
  139. RWMutex::RLock l(_peers_l);
  140. Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
  141. Address *a = (Address *)0;
  142. SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
  143. while (i.next(a,p)) {
  144. f(*((const SharedPtr<Peer> *)p));
  145. }
  146. }
  147. /**
  148. * Apply a function or function object to all peers
  149. *
  150. * This locks the peer map during execution, so calls to get() etc. during
  151. * eachPeer() will deadlock.
  152. *
  153. * @param f Function to apply
  154. * @tparam F Function or function object type
  155. */
  156. template<typename F>
  157. ZT_ALWAYS_INLINE void eachPeerWithRoot(F f) const
  158. {
  159. RWMutex::RLock l(_peers_l);
  160. const unsigned long rootPeerCnt = _rootPeers.size();
  161. uintptr_t *const rootPeerPtrs = (uintptr_t *)malloc(sizeof(uintptr_t) * rootPeerCnt);
  162. if (!rootPeerPtrs)
  163. throw std::bad_alloc();
  164. for(unsigned long i=0;i<rootPeerCnt;++i)
  165. rootPeerPtrs[i] = (uintptr_t)_rootPeers[i].ptr();
  166. std::sort(rootPeerPtrs,rootPeerPtrs + rootPeerCnt);
  167. uintptr_t *const rootPeerPtrsEnd = rootPeerPtrs + rootPeerCnt;
  168. try {
  169. Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
  170. Address *a = (Address *)0;
  171. SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
  172. while (i.next(a,p)) {
  173. f(*((const SharedPtr<Peer> *)p),std::binary_search(rootPeerPtrs,rootPeerPtrsEnd,(uintptr_t)p->ptr()));
  174. }
  175. } catch ( ... ) {} // should not throw
  176. free((void *)rootPeerPtrs);
  177. }
  178. /**
  179. * Iterate through all paths in the system
  180. *
  181. * @tparam F Function to call for each path
  182. * @param f
  183. */
  184. template<typename F>
  185. ZT_ALWAYS_INLINE void eachPath(F f) const
  186. {
  187. RWMutex::RLock l(_paths_l);
  188. Hashtable< Path::HashKey,SharedPtr<Path> >::Iterator i(const_cast<Topology *>(this)->_paths);
  189. Path::HashKey *k = (Path::HashKey *)0;
  190. SharedPtr<Path> *p = (SharedPtr<Path> *)0;
  191. while (i.next(k,p)) {
  192. f(*((const SharedPtr<Peer> *)p));
  193. }
  194. }
  195. /**
  196. * @param allPeers vector to fill with all current peers
  197. */
  198. void getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const;
  199. /**
  200. * Get info about a path
  201. *
  202. * The supplied result variables are not modified if no special config info is found.
  203. *
  204. * @param physicalAddress Physical endpoint address
  205. * @param mtu Variable set to MTU
  206. * @param trustedPathId Variable set to trusted path ID
  207. */
  208. ZT_ALWAYS_INLINE void getOutboundPathInfo(const InetAddress &physicalAddress,unsigned int &mtu,uint64_t &trustedPathId)
  209. {
  210. for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
  211. if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
  212. trustedPathId = _physicalPathConfig[i].second.trustedPathId;
  213. mtu = _physicalPathConfig[i].second.mtu;
  214. return;
  215. }
  216. }
  217. }
  218. /**
  219. * Get the outbound trusted path ID for a physical address, or 0 if none
  220. *
  221. * @param physicalAddress Physical address to which we are sending the packet
  222. * @return Trusted path ID or 0 if none (0 is not a valid trusted path ID)
  223. */
  224. ZT_ALWAYS_INLINE uint64_t getOutboundPathTrust(const InetAddress &physicalAddress)
  225. {
  226. for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
  227. if (_physicalPathConfig[i].first.containsAddress(physicalAddress))
  228. return _physicalPathConfig[i].second.trustedPathId;
  229. }
  230. return 0;
  231. }
  232. /**
  233. * Check whether in incoming trusted path marked packet is valid
  234. *
  235. * @param physicalAddress Originating physical address
  236. * @param trustedPathId Trusted path ID from packet (from MAC field)
  237. */
  238. ZT_ALWAYS_INLINE bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId)
  239. {
  240. for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
  241. if ((_physicalPathConfig[i].second.trustedPathId == trustedPathId)&&(_physicalPathConfig[i].first.containsAddress(physicalAddress)))
  242. return true;
  243. }
  244. return false;
  245. }
  246. /**
  247. * Set or clear physical path configuration (called via Node::setPhysicalPathConfiguration)
  248. */
  249. void setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
  250. /**
  251. * Add a root server's identity to the root server set
  252. *
  253. * @param id Root server identity
  254. */
  255. void addRoot(const Identity &id);
  256. /**
  257. * Remove a root server's identity from the root server set
  258. *
  259. * @param id Root server identity
  260. * @return True if root found and removed, false if not found
  261. */
  262. bool removeRoot(const Identity &id);
  263. /**
  264. * Sort roots in asecnding order of apparent latency
  265. *
  266. * @param now Current time
  267. */
  268. void rankRoots(int64_t now);
  269. /**
  270. * Do periodic tasks such as database cleanup
  271. */
  272. void doPeriodicTasks(void *tPtr,int64_t now);
  273. /**
  274. * Save all currently known peers to data store
  275. */
  276. void saveAll(void *tPtr);
  277. private:
  278. void _loadCached(void *tPtr,const Address &zta,SharedPtr<Peer> &peer);
  279. const RuntimeEnvironment *const RR;
  280. const Identity _myIdentity;
  281. RWMutex _peers_l;
  282. RWMutex _paths_l;
  283. std::pair< InetAddress,ZT_PhysicalPathConfiguration > _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
  284. unsigned int _numConfiguredPhysicalPaths;
  285. Hashtable< Address,SharedPtr<Peer> > _peers;
  286. Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
  287. std::set< Identity > _roots; // locked by _peers_l
  288. std::vector< SharedPtr<Peer> > _rootPeers; // locked by _peers_l
  289. };
  290. } // namespace ZeroTier
  291. #endif