Multicaster.hpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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_MULTICASTER_HPP
  14. #define ZT_MULTICASTER_HPP
  15. #include <stdint.h>
  16. #include <string.h>
  17. #include <map>
  18. #include <vector>
  19. #include "Constants.hpp"
  20. #include "Hashtable.hpp"
  21. #include "Address.hpp"
  22. #include "MAC.hpp"
  23. #include "MulticastGroup.hpp"
  24. #include "OutboundMulticast.hpp"
  25. #include "Utils.hpp"
  26. #include "Mutex.hpp"
  27. #include "SharedPtr.hpp"
  28. namespace ZeroTier {
  29. class RuntimeEnvironment;
  30. class CertificateOfMembership;
  31. class Packet;
  32. class Network;
  33. /**
  34. * Multicast database and outbound multicast logic
  35. */
  36. class Multicaster
  37. {
  38. public:
  39. Multicaster(const RuntimeEnvironment *renv);
  40. ~Multicaster();
  41. /**
  42. * Add or update a member in a multicast group
  43. *
  44. * @param now Current time
  45. * @param nwid Network ID
  46. * @param mg Multicast group
  47. * @param member New member address
  48. */
  49. inline void add(const int64_t now,const uint64_t nwid,const MulticastGroup &mg,const Address &member)
  50. {
  51. Mutex::Lock l(_groups_l);
  52. _groups[Multicaster::Key(nwid,mg)].set(member,now);
  53. }
  54. /**
  55. * Add multiple addresses from a binary array of 5-byte address fields
  56. *
  57. * It's up to the caller to check bounds on the array before calling this.
  58. *
  59. * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
  60. * @param now Current time
  61. * @param nwid Network ID
  62. * @param mg Multicast group
  63. * @param addresses Raw binary addresses in big-endian format, as a series of 5-byte fields
  64. * @param count Number of addresses
  65. * @param totalKnown Total number of known addresses as reported by peer
  66. */
  67. inline void addMultiple(const int64_t now,const uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,const unsigned int totalKnown)
  68. {
  69. Mutex::Lock l(_groups_l);
  70. const uint8_t *a = (const uint8_t *)addresses;
  71. Hashtable< Address,int64_t > &members = _groups[Multicaster::Key(nwid,mg)];
  72. while (count--) {
  73. members.set(Address(a,ZT_ADDRESS_LENGTH),now);
  74. a += ZT_ADDRESS_LENGTH;
  75. }
  76. }
  77. /**
  78. * Remove a multicast group member (if present)
  79. *
  80. * @param nwid Network ID
  81. * @param mg Multicast group
  82. * @param member Member to unsubscribe
  83. */
  84. inline void remove(const uint64_t nwid,const MulticastGroup &mg,const Address &member)
  85. {
  86. Mutex::Lock l(_groups_l);
  87. const Multicaster::Key gk(nwid,mg);
  88. Hashtable< Address,int64_t > *const members = _groups.get(gk);
  89. if (members) {
  90. members->erase(member);
  91. if (members->empty())
  92. _groups.erase(gk);
  93. }
  94. }
  95. /**
  96. * Iterate over members of a multicast group until function returns false
  97. *
  98. * Iteration order is in inverse order of most recent receipt of a LIKE
  99. * for a given membership.
  100. *
  101. * @param nwid Network ID
  102. * @param mg Multicast group
  103. * @param func f(Address)
  104. * @return Total number of known members (regardless of when function aborted)
  105. */
  106. template<typename F>
  107. inline unsigned long eachMember(const uint64_t nwid,const MulticastGroup &mg,F func) const
  108. {
  109. std::vector< std::pair<int64_t,Address> > sortedByTime;
  110. {
  111. Mutex::Lock l(_groups_l);
  112. const Multicaster::Key gk(nwid,mg);
  113. const Hashtable< Address,int64_t > *const members = _groups.get(gk);
  114. if (members) {
  115. totalKnown = members->size();
  116. sortedByTime.reserve(totalKnown);
  117. {
  118. Hashtable< Address,int64_t >::Iterator mi(*const_cast<Hashtable< Address,int64_t > *>(members));
  119. Address *mik = nullptr;
  120. int64_t *miv = nullptr;
  121. while (mi.next(mik,miv))
  122. sortedByTime.push_back(std::pair<int64_t,Address>(*miv,*mik));
  123. }
  124. std::sort(sortedByTime.begin(),sortedByTime.end());
  125. }
  126. }
  127. for(std::vector< std::pair<int64_t,Address> >::const_reverse_iterator i(sortedByTime.begin());i!=sortedByTime.end();++i) {
  128. if (!func(i->second))
  129. break;
  130. }
  131. return sortedByTime.size();
  132. }
  133. /**
  134. * Send a multicast
  135. *
  136. * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
  137. * @param now Current time
  138. * @param network Network
  139. * @param origin Origin of multicast (to not return to sender) or NULL if none
  140. * @param mg Multicast group
  141. * @param src Source Ethernet MAC address or NULL to skip in packet and compute from ZT address (non-bridged mode)
  142. * @param etherType Ethernet frame type
  143. * @param data Packet data
  144. * @param len Length of packet data
  145. */
  146. void send(
  147. void *tPtr,
  148. int64_t now,
  149. const SharedPtr<Network> &network,
  150. const Address &origin,
  151. const MulticastGroup &mg,
  152. const MAC &src,
  153. unsigned int etherType,
  154. const void *data,
  155. unsigned int len);
  156. /**
  157. * Clean up database
  158. *
  159. * @param RR Runtime environment
  160. * @param now Current time
  161. */
  162. void clean(int64_t now);
  163. private:
  164. struct Key
  165. {
  166. ZT_ALWAYS_INLINE Key() : nwid(0),mg() {}
  167. ZT_ALWAYS_INLINE Key(const uint64_t n,const MulticastGroup &g) : nwid(n),mg(g) {}
  168. uint64_t nwid;
  169. MulticastGroup mg;
  170. ZT_ALWAYS_INLINE bool operator==(const Key &k) const { return ((nwid == k.nwid)&&(mg == k.mg)); }
  171. ZT_ALWAYS_INLINE bool operator!=(const Key &k) const { return ((nwid != k.nwid)||(mg != k.mg)); }
  172. ZT_ALWAYS_INLINE unsigned long hashCode() const { return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); }
  173. };
  174. const RuntimeEnvironment *const RR;
  175. OutboundMulticast _txQueue[ZT_TX_QUEUE_SIZE];
  176. unsigned int _txQueuePtr;
  177. Mutex _txQueue_l;
  178. Hashtable< Multicaster::Key,Hashtable< Address,int64_t > > _groups;
  179. Mutex _groups_l;
  180. };
  181. } // namespace ZeroTier
  182. #endif