summaryrefslogtreecommitdiff
path: root/node/Multicaster.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/Multicaster.cpp')
-rw-r--r--node/Multicaster.cpp116
1 files changed, 116 insertions, 0 deletions
diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp
new file mode 100644
index 00000000..be5daf43
--- /dev/null
+++ b/node/Multicaster.cpp
@@ -0,0 +1,116 @@
+/*
+ * ZeroTier One - Global Peer to Peer Ethernet
+ * Copyright (C) 2012-2013 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/
+ */
+
+#include "Constants.hpp"
+#include "Multicaster.hpp"
+#include "Utils.hpp"
+
+namespace ZeroTier {
+
+Multicaster::Multicaster()
+{
+}
+
+Multicaster::~Multicaster()
+{
+}
+
+void Multicaster::likesGroup(uint64_t nwid,const Address &a,const MulticastGroup &mg,uint64_t now)
+{
+ Mutex::Lock _l(_lock);
+ _NetInfo &n = _nets[nwid];
+ _SubInfo &si = n.subscriptions[_Subscription(a,mg)];
+ if (!si.lastLike) { // on first LIKE, we must add to _proximity[mg]
+ std::list< Address > &p = n.proximity[mg];
+ p.push_front(a);
+ si.proximitySlot = p.begin(); // list's iterators remain valid until erase()
+ }
+ si.lastLike = now;
+}
+
+void Multicaster::bringCloser(uint64_t nwid,const Address &a)
+{
+ Mutex::Lock _l(_lock);
+
+ std::map< uint64_t,_NetInfo >::iterator n(_nets.find(nwid));
+ if (n == _nets.end())
+ return;
+
+ /* _subscriptions contains pairs of <Address,MulticastGroup>, so we can
+ * easily iterate through all subscriptions for a given address by
+ * starting with the default all-zero MulticastGroup() as lower bound
+ * and stopping when we're not looking at the right address anymore.
+ * Then we can look up _proximity and rapidly splice() the list using
+ * the saved iterator in _SubInfo. */
+
+ std::map< _Subscription,_SubInfo >::iterator s(n->second.subscriptions.lower_bound(_Subscription(a,MulticastGroup())));
+ while ((s != n->second.subscriptions.end())&&(s->first.first == a)) {
+ std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(s->first.second));
+ if (s->second.proximitySlot != p->second.begin())
+ p->second.splice(p->second.begin(),p->second,s->second.proximitySlot);
+ ++s;
+ }
+}
+
+void Multicaster::got(uint64_t nwid,const Address &peer,uint64_t mcGuid,uint64_t now)
+{
+ Mutex::Lock _l(_lock);
+ _NetInfo &n = _nets[nwid];
+ std::pair< uint64_t,std::set<Address> > &g = n.got[mcGuid];
+ g.first = now;
+ g.second.insert(peer);
+}
+
+void Multicaster::clean(uint64_t now)
+{
+ Mutex::Lock _l(_lock);
+
+ for(std::map< uint64_t,_NetInfo >::iterator n(_nets.begin());n!=_nets.end();) {
+ for(std::map< uint64_t,std::pair< uint64_t,std::set<Address> > >::iterator g(n->second.got.begin());g!=n->second.got.end();) {
+ if ((now - g->second.first) > ZT_MULTICAST_MAGNET_STATE_EXPIRE)
+ n->second.got.erase(g++);
+ else ++g;
+ }
+
+ for(std::map< _Subscription,_SubInfo >::iterator s(n->second.subscriptions.begin());s!=n->second.subscriptions.end();) {
+ if ((now - s->second.lastLike) > ZT_MULTICAST_LIKE_EXPIRE) {
+ std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(s->first.second));
+ p->second.erase(s->second.proximitySlot);
+ if (p->second.empty())
+ n->second.proximity.erase(p);
+ n->second.subscriptions.erase(s++);
+ } else ++s;
+ }
+
+ if (n->second.got.empty()&&n->second.proximity.empty()&&n->second.subscriptions.empty())
+ _nets.erase(n++);
+ else ++n;
+ }
+}
+
+} // namespace ZeroTier
+