summaryrefslogtreecommitdiff
path: root/node/MulticastTopology.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/MulticastTopology.hpp')
-rw-r--r--node/MulticastTopology.hpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/node/MulticastTopology.hpp b/node/MulticastTopology.hpp
new file mode 100644
index 00000000..fc49dbd3
--- /dev/null
+++ b/node/MulticastTopology.hpp
@@ -0,0 +1,162 @@
+/*
+ * ZeroTier One - Global Peer to Peer Ethernet
+ * Copyright (C) 2011-2014 ZeroTier Networks LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_MULTICASTTOPOLOGY_HPP
+#define ZT_MULTICASTTOPOLOGY_HPP
+
+#include <stdint.h>
+#include <string.h>
+
+#include <map>
+#include <vector>
+
+#include "Constants.hpp"
+#include "Address.hpp"
+#include "MulticastGroup.hpp"
+#include "Mutex.hpp"
+#include "Utils.hpp"
+
+namespace ZeroTier {
+
+class Topology;
+
+/**
+ * Database of known multicast peers within a network
+ */
+class MulticastTopology
+{
+private:
+ struct MulticastGroupMember
+ {
+ MulticastGroupMember() {}
+ MulticastGroupMember(const Address &a,const Address &lf,uint64_t ts) : address(a),learnedFrom(lf),timestamp(ts) {}
+
+ Address address;
+ Address learnedFrom; // NULL/0 for addresses directly learned from LIKE
+ uint64_t timestamp; // time of last LIKE or OK response to MULTICAST_LONELY
+ uint64_t rank; // used by sorting algorithm in clean()
+
+ // for sorting in ascending order of rank
+ inline bool operator<(const MulticastGroupMember &m) const throw() { return (rank < m.rank); }
+ };
+
+public:
+ MulticastTopology();
+ ~MulticastTopology();
+
+ /**
+ * Add or update a member in a multicast group
+ *
+ * @param mg Multicast group
+ * @param member Member to add/update
+ * @param learnedFrom Address from which we learned this member or NULL/0 Address if direct
+ */
+ inline void add(const MulticastGroup &mg,const Address &member,const Address &learnedFrom)
+ {
+ Mutex::Lock _l(_members_m);
+ std::vector<MulticastGroupMember> &mv = _members[mg];
+ for(std::vector<MulticastGroupMember>::iterator m(mv.begin());m!=mv.end();++m) {
+ if (m->address == member) {
+ if (m->learnedFrom) // once a member has been seen directly, we keep its status as direct
+ m->learnedFrom = learnedFrom;
+ m->timestamp = Utils::now();
+ return;
+ }
+ }
+ mv.push_back(MulticastGroupMember(member,learnedFrom,Utils::now()));
+ }
+
+ /**
+ * Erase a member from a multicast group (if present)
+ *
+ * @param mg Multicast group
+ * @param member Member to erase
+ */
+ inline void erase(const MulticastGroup &mg,const Address &member)
+ {
+ Mutex::Lock _l(_members_m);
+ std::map< MulticastGroup,std::vector<MulticastGroupMember> >::iterator r(_members.find(mg));
+ if (r != _members.end()) {
+ for(std::vector<MulticastGroupMember>::iterator m(r->second.begin());m!=r->second.end();++m) {
+ if (m->address == member) {
+ r->second.erase(m);
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param mg Multicast group
+ * @return Number of known peers in group
+ */
+ inline unsigned int memberCount(const MulticastGroup &mg) const
+ {
+ Mutex::Lock _l(_members_m);
+ std::map< MulticastGroup,std::vector<MulticastGroupMember> >::const_iterator r(_members.find(mg));
+ return ((r != _members.end()) ? (unsigned int)r->second.size() : (unsigned int)0);
+ }
+
+ /**
+ * Iterate over the known members of a multicast group
+ *
+ * @param mg Multicast group
+ * @param func Function to be called with multicast group and address of member
+ * @tparam F Function type (explicitly template on "FuncObj &" if reference instead of copy should be passed)
+ * @return Number of members in multicast group for which function was called
+ */
+ template<typename F>
+ inline unsigned int eachMember(const MulticastGroup &mg,F func) const
+ {
+ Mutex::Lock _l(_members_m);
+ std::map< MulticastGroup,std::vector<MulticastGroupMember> >::const_iterator r(_members.find(mg));
+ if (r != _members.end()) {
+ // We go in reverse order because most recently learned members are pushed to the end
+ // of the vector. The priority resort algorithm in clean() sorts in ascending order
+ // of propagation priority too.
+ for(std::vector<MulticastGroupMember>::const_reverse_iterator m(r->second.rbegin());m!=r->second.rend();++m) {
+ func(mg,m->address);
+ }
+ return (unsigned int)r->second.size();
+ } else return 0;
+ }
+
+ /**
+ * Clean up and resort database
+ *
+ * @param topology Global peer topology
+ */
+ void clean(const Topology &topology);
+
+private:
+ std::map< MulticastGroup,std::vector<MulticastGroupMember> > _members;
+ Mutex _members_m;
+};
+
+} // namespace ZeroTier
+
+#endif