()) / 4294967296.0;
if (skipThis <= skipWhatFraction) {
--numEntriesPermittedToSkip;
++channelMemberEntry;
continue;
}
}
// If it's not expired and it's from our random sample, add it to the set of peers
// to consider. Exclude immediate upstream and original submitter, since we know for
// a fact they've already seen this.
if ((channelMemberEntry->first != originalSubmitter)&&(channelMemberEntry->first != upstream)) {
P peer = topology.getPeer(channelMemberEntry->first);
if (peer) {
toConsider[sampleSize++] = peer;
if (sampleSize >= ZT_MULTICAST_PICK_MAX_SAMPLE_SIZE)
break; // abort if we have enough candidates
}
}
++channelMemberEntry;
}
// Auto-clean: erase whole map if there are no more LIKEs for this channel
if (channelMembers->second.empty())
_multicastMemberships.erase(channelMembers);
}
}
// Sort in descending order of most recent direct unicast frame, picking
// peers with whom we have recently communicated. This is "implicit social
// switching."
std::sort(&(toConsider[0]),&(toConsider[sampleSize]),PeerPropagationPrioritySortOrder());
// Decay a few random bits in bloom filter to probabilistically eliminate
// false positives as we go. The odds of decaying an already-set bit
// increases as the bloom filter saturates, so in the early hops of
// propagation this likely won't have any effect. This allows peers with
// bloom filter collisions to be reconsidered, but at positions on the
// network graph likely to be hops away from the original origin of the
// message.
for(unsigned int i=0;iaddress().sum()))
peers[picked++] = toConsider[i];
}
// Add a supernode if there's nowhere else to go. Supernodes know of all multicast
// LIKEs and so can act to bridge sparse multicast groups. We do not remember them
// in the bloom filter.
if (!picked) {
P peer = topology.getBestSupernode();
if (peer)
peers[picked++] = peer;
}
return picked;
}
private:
// Sort order for chosen propagation peers
template
struct PeerPropagationPrioritySortOrder
{
inline bool operator()(const P &p1,const P &p2) const
{
return (p1->lastUnicastFrame() >= p2->lastUnicastFrame());
}
};
static inline void _hashMulticastPacketForSig(uint64_t nwid,const MAC &from,const MulticastGroup &to,unsigned int etherType,const void *data,unsigned int len,unsigned char *digest)
throw()
{
unsigned char zero = 0;
SHA256_CTX sha;
SHA256_Init(&sha);
uint64_t _nwid = Utils::hton(nwid);
SHA256_Update(&sha,(unsigned char *)&_nwid,sizeof(_nwid));
SHA256_Update(&sha,&zero,1);
SHA256_Update(&sha,(unsigned char *)from.data,6);
SHA256_Update(&sha,&zero,1);
SHA256_Update(&sha,(unsigned char *)to.mac().data,6);
SHA256_Update(&sha,&zero,1);
uint32_t _adi = Utils::hton(to.adi());
SHA256_Update(&sha,(unsigned char *)&_adi,sizeof(_adi));
SHA256_Update(&sha,&zero,1);
uint16_t _etype = Utils::hton((uint16_t)etherType);
SHA256_Update(&sha,(unsigned char *)&_etype,sizeof(_etype));
SHA256_Update(&sha,&zero,1);
SHA256_Update(&sha,(unsigned char *)data,len);
SHA256_Final(digest,&sha);
}
// [0] - CRC, [1] - timestamp
uint64_t _multicastHistory[ZT_MULTICAST_DEDUP_HISTORY_LENGTH][2];
// A multicast channel, essentially a pub/sub channel. It consists of a
// network ID and a multicast group within that network.
typedef std::pair MulticastChannel;
// Address and time of last LIKE, by network ID and multicast group
std::map< MulticastChannel,std::map > _multicastMemberships;
Mutex _multicastMemberships_m;
};
} // namespace ZeroTier
#endif