/* * 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 . * * -- * * 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_MULTICASTER_HPP #define ZT_MULTICASTER_HPP #include #include #include #include #include #include #include #include "Constants.hpp" #include "Mutex.hpp" #include "MulticastGroup.hpp" #include "Address.hpp" #include "Buffer.hpp" namespace ZeroTier { /** * Multicast propagation algorithm core and database */ class Multicaster { public: Multicaster(); ~Multicaster(); /** * Add or renew a peer's subscription to a multicast group * * @param nwid Network ID * @param a Address that LIKEd * @param mg Multicast group * @param now Current time */ void likesGroup(uint64_t nwid,const Address &a,const MulticastGroup &mg,uint64_t now); /** * Bring a peer closer in terms of propagation priority * * This gets called from PacketDecoder when a unicast frame is received. * * @param nwid Network ID * @param a Address to bring closer (e.g. due to unicast message) * @param now Current time */ void bringCloser(uint64_t nwid,const Address &a); /** * Erase entries for expired LIKEs and GOT records */ void clean(); /** * Multicast deduplicator * * This checks to see if a multicast GUID has been seen before. If not, it * adds it to the history and returns false. * * @param nwid Network ID * @param mcGuid Multicast GUID (sender address + sender unique ID) * @return True if multicast IS a duplicate, false otherwise */ inline bool deduplicate(uint64_t nwid,uint64_t mcGuid) throw() { Mutex::Lock _l(_lock); _NetInfo &n = _nets[nwid]; for(unsigned int i=0;i inline void getNextHops(uint64_t nwid,const MulticastGroup &mg,F nextHopFunc) { Mutex::Lock _l(_lock); std::map< uint64_t,_NetInfo >::iterator n(_nets.find(nwid)); if (n == _nets.end()) return; std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(mg)); if (p == n->second.proximity.end()) return; for(std::list< Address >::iterator a(p->second.begin());a!=p->second.end();++a) { if (!nextHopFunc(*a)) break; } } /** * Functor to add addresses to multicast frame propagation queues * * This function object checks the origin, bloom filter, and restriction * prefix for each address and if all these pass it adds the address and * increments the pointer pointed to by ptr. It stops (returns false) when * *ptr reaches end. It's used in PacketDecoder and Switch with getNextHops() * to compose multicast frame headers. */ class AddToPropagationQueue { public: /** * @param ptr Pointer to pointer to current position in queue * @param end End of queue * @param bloom Bloom filter field (must be 1024 bytes in length) * @param bloomNonce Random nonce for bloom filter randomization * @param origin Originating address * @param prefixBits Number of bits in propagation restriction prefix * @param prefix Propagation restrition prefix */ AddToPropagationQueue(unsigned char **ptr,unsigned char *end,unsigned char *bloom,uint16_t bloomNonce,const Address &origin,unsigned int prefixBits,unsigned int prefix) throw() : _origin(origin), _bloomNonce((uint64_t)bloomNonce), _prefixMask(0xffffffffffffffffULL >> (64 - prefixBits)), _prefix((uint64_t)prefix & _prefixMask), _ptr(ptr), _end(end), _bloom(bloom) {} inline bool operator()(const Address &a) throw() { // Exclude original sender -- obviously they've already seen it if (a == _origin) return true; // Exclude addresses not in this prefix domain if ((a.toInt() & _prefixMask) != _prefix) return true; // Exclude addresses remembered in bloom filter -- or else remember them uint64_t aint = a.toInt() + _bloomNonce; const unsigned int bit = (unsigned int)(aint ^ (aint >> 13) ^ (aint >> 26) ^ (aint >> 39)) & 0x1fff; unsigned char *const bbyte = _bloom + (bit >> 3); // note: bloom filter size == 1024 is hard-coded here const unsigned char bmask = 1 << (bit & 7); if ((*bbyte & bmask)) return true; else *bbyte |= bmask; a.copyTo(*_ptr,ZT_ADDRESS_LENGTH); return ((*_ptr += ZT_ADDRESS_LENGTH) != _end); } private: const Address _origin; const uint64_t _bloomNonce; const uint64_t _prefixMask; const uint64_t _prefix; unsigned char **const _ptr; unsigned char *const _end; unsigned char *const _bloom; }; private: // Information about a subscription struct _SubInfo { _SubInfo() : lastLike(0), proximitySlot() {} // Time of last MULTICAST_LIKE for this group uint64_t lastLike; // Slot in corresponding list in _proximity std::list< Address >::iterator proximitySlot; }; // An address and multicast group tuple typedef std::pair< Address,MulticastGroup > _Subscription; // Multicast info for a given network struct _NetInfo { _NetInfo() throw() { memset(multicastHistory,0,sizeof(multicastHistory)); multicastHistoryPtr = 0; } // Ring buffer of most recently injected multicast packet GUIDs uint64_t multicastHistory[ZT_MULTICAST_DEDUP_HISTORY_LENGTH]; unsigned int multicastHistoryPtr; // Peer proximity ordering for peers subscribed to each group std::map< MulticastGroup,std::list< Address > > proximity; // Peer subscriptions to multicast groups std::map< _Subscription,_SubInfo > subscriptions; }; std::map< uint64_t,_NetInfo > _nets; Mutex _lock; }; } // namespace ZeroTier #endif