Browse Source

Compile fixes, integration of fast PRNG.

Adam Ierymenko 12 năm trước cách đây
mục cha
commit
97cbd98bc5
11 tập tin đã thay đổi với 154 bổ sung66 xóa
  1. 10 0
      node/CMWC4096.hpp
  2. 2 2
      node/Demarc.cpp
  3. 1 1
      node/Http.cpp
  4. 2 3
      node/Multicaster.hpp
  5. 4 0
      node/Node.cpp
  6. 1 0
      node/PacketDecoder.cpp
  7. 31 11
      node/Peer.cpp
  8. 66 22
      node/Peer.hpp
  9. 3 4
      node/RuntimeEnvironment.hpp
  10. 32 22
      node/Switch.cpp
  11. 2 1
      node/Topology.cpp

+ 10 - 0
node/CMWC4096.hpp

@@ -31,6 +31,8 @@
 #include <stdint.h>
 #include "Utils.hpp"
 
+namespace ZeroTier {
+
 /** 
  * Complement Multiply With Carry random number generator
  *
@@ -72,10 +74,18 @@ public:
 		return ((((uint64_t)next32()) << 32) ^ (uint64_t)next32());
 	}
 
+	inline double nextDouble()
+		throw()
+	{
+		return ((double)(next32()) / 4294967296.0);
+	}
+
 private:
 	uint32_t Q[4096];
 	uint32_t c;
 	uint32_t i;
 };
 
+} // namespace ZeroTier
+
 #endif

+ 2 - 2
node/Demarc.cpp

@@ -143,7 +143,7 @@ Demarc::Port Demarc::pick(const InetAddress &to) const
 			}
 		}
 		if (possibilities.size())
-			return possibilities[_r->prng.next32() % possibilities.size()]->first;
+			return possibilities[_r->prng->next32() % possibilities.size()]->first;
 		else return NULL_PORT;
 	} catch ( ... ) {
 		return NULL_PORT;
@@ -174,7 +174,7 @@ Demarc::Port Demarc::send(Demarc::Port fromPort,const InetAddress &to,const void
 				}
 			}
 			if (possibilities.size())
-				pe = possibilities[_r->prng.next32() % possibilities.size()];
+				pe = possibilities[_r->prng->next32() % possibilities.size()];
 			else {
 				_ports_m.unlock();
 				return NULL_PORT;

+ 1 - 1
node/Http.cpp

@@ -173,7 +173,7 @@ void Http::Request::main()
 				addrList->sort();
 				addrList->unique();
 				unsigned int i = 0,k = 0;
-				k = _r->prng.next32() % addrList->size();
+				k = rand() % addrList->size();
 				std::list<InetAddress>::iterator a(addrList->begin());
 				while (i++ != k) ++a;
 				addr = &(*a);

+ 2 - 3
node/Multicaster.hpp

@@ -234,7 +234,7 @@ public:
 		// network graph likely to be hops away from the original origin of the
 		// message.
 		for(unsigned int i=0;i<ZT_MULTICAST_BLOOM_FILTER_DECAY_RATE;++i)
-			bf.decay();
+			bf.decay((unsigned int)prng.next32());
 
 		{
 			Mutex::Lock _l(_multicastMemberships_m);
@@ -261,8 +261,7 @@ public:
 					// Skip some fraction of entries so that our sampling will be randomly distributed,
 					// since there is no other good way to sample randomly from a map.
 					if (numEntriesPermittedToSkip) {
-						double skipThis = (double)(Utils::randomInt<uint32_t>()) / 4294967296.0;
-						if (skipThis <= skipWhatFraction) {
+						if (prng.nextDouble() <= skipWhatFraction) {
 							--numEntriesPermittedToSkip;
 							++channelMemberEntry;
 							continue;

+ 4 - 0
node/Node.cpp

@@ -65,6 +65,7 @@
 #include "MulticastGroup.hpp"
 #include "Mutex.hpp"
 #include "Multicaster.hpp"
+#include "CMWC4096.hpp"
 
 #include "../version.h"
 
@@ -120,6 +121,7 @@ Node::~Node()
 	delete impl->renv.multicaster;
 	delete impl->renv.demarc;
 	delete impl->renv.nc;
+	delete impl->renv.prng;
 	delete impl->renv.log;
 
 	delete impl;
@@ -153,6 +155,8 @@ Node::ReasonForTermination Node::run()
 
 		TRACE("initializing...");
 
+		_r->prng = new CMWC4096();
+
 		if (!_r->configAuthority.fromString(_r->configAuthorityIdentityStr))
 			return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"configuration authority identity is not valid");
 

+ 1 - 0
node/PacketDecoder.cpp

@@ -472,6 +472,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 								Multicaster::MulticastBloomFilter bloom(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_BLOOM_FILTER,ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BYTES));
 								SharedPtr<Peer> propPeers[ZT_MULTICAST_PROPAGATION_BREADTH];
 								unsigned int np = _r->multicaster->pickNextPropagationPeers(
+									*(_r->prng),
 									*(_r->topology),
 									network->id(),
 									mg,

+ 31 - 11
node/Peer.cpp

@@ -30,6 +30,11 @@
 namespace ZeroTier {
 
 Peer::Peer() :
+	_id(),
+	_ipv4p(),
+	_ipv6p(),
+	_lastUnicastFrame(0),
+	_lastMulticastFrame(0),
 	_vMajor(0),
 	_vMinor(0),
 	_vRevision(0),
@@ -40,6 +45,10 @@ Peer::Peer() :
 Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
 	throw(std::runtime_error) :
 	_id(peerIdentity),
+	_ipv4p(),
+	_ipv6p(),
+	_lastUnicastFrame(0),
+	_lastMulticastFrame(0),
 	_vMajor(0),
 	_vMinor(0),
 	_vRevision(0),
@@ -49,29 +58,31 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
 		throw std::runtime_error("new peer identity key agreement failed");
 }
 
-void Peer::onReceive(const RuntimeEnvironment *_r,Demarc::Port localPort,const InetAddress &fromAddr,unsigned int hops,Packet::Verb verb,uint64_t now)
+void Peer::onReceive(const RuntimeEnvironment *_r,Demarc::Port localPort,const InetAddress &remoteAddr,unsigned int hops,Packet::Verb verb,uint64_t now)
 {
 	if (!hops) { // direct packet
-		WanPath *wp = (fromAddr.isV4() ? &_ipv4p : &_ipv6p);
-
+		WanPath *wp = (remoteAddr.isV4() ? &_ipv4p : &_ipv6p);
 		wp->lastReceive = now;
-		if (verb == Packet::VERB_FRAME)
-			wp->lastUnicastFrame = now;
 		wp->localPort = localPort;
 		if (!wp->fixed)
-			wp->addr = fromAddr;
+			wp->addr = remoteAddr;
+		_dirty = true;
+	}
 
+	if (verb == Packet::VERB_FRAME) {
+		_lastUnicastFrame = now;
+		_dirty = true;
+	} else if (verb == Packet::VERB_MULTICAST_FRAME) {
+		_lastMulticastFrame = now;
 		_dirty = true;
 	}
 }
 
-bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,bool relay,Packet::Verb verb,uint64_t now)
+bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now)
 {
 	if ((_ipv6p.isActive(now))||((!(_ipv4p.addr))&&(_ipv6p.addr))) {
 		if (_r->demarc->send(_ipv6p.localPort,_ipv6p.addr,data,len,-1)) {
 			_ipv6p.lastSend = now;
-			if (verb == Packet::VERB_FRAME)
-				_ipv6p.lastUnicastFrame = now;
 			_dirty = true;
 			return true;
 		}
@@ -80,8 +91,6 @@ bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,b
 	if (_ipv4p.addr) {
 		if (_r->demarc->send(_ipv4p.localPort,_ipv4p.addr,data,len,-1)) {
 			_ipv4p.lastSend = now;
-			if (verb == Packet::VERB_FRAME)
-				_ipv4p.lastUnicastFrame = now;
 			_dirty = true;
 			return true;
 		}
@@ -90,6 +99,17 @@ bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,b
 	return false;
 }
 
+void Peer::onSent(const RuntimeEnvironment *_r,bool relay,Packet::Verb verb,uint64_t now)
+{
+	if (verb == Packet::VERB_FRAME) {
+		_lastUnicastFrame = now;
+		_dirty = true;
+	} else if (verb == Packet::VERB_MULTICAST_FRAME) {
+		_lastMulticastFrame = now;
+		_dirty = true;
+	}
+}
+
 bool Peer::sendFirewallOpener(const RuntimeEnvironment *_r,uint64_t now)
 {
 	bool sent = false;

+ 66 - 22
node/Peer.hpp

@@ -53,15 +53,16 @@
 #define ZT_PEER_MAX_SERIALIZED_LENGTH ( \
 	64 + \
 	IDENTITY_MAX_BINARY_SERIALIZED_LENGTH + \
-	(( \
-		(sizeof(uint64_t) * 5) + \
+	( ( \
+		(sizeof(uint64_t) * 4) + \
 		sizeof(uint16_t) + \
 		1 + \
 		sizeof(uint16_t) + \
 		16 + \
 		1 \
 	) * 2) + \
-	64 \
+	sizeof(uint64_t) + \
+	sizeof(uint64_t) \
 )
 
 namespace ZeroTier {
@@ -110,32 +111,42 @@ public:
 	/**
 	 * Must be called on authenticated packet receive from this peer
 	 * 
+	 * This must be called only after a packet has passed authentication
+	 * checking. Packets that fail are silently discarded.
+	 *
 	 * @param _r Runtime environment
 	 * @param localPort Local port on which packet was received
-	 * @param fromAddr Internet address of sender
+	 * @param remoteAddr Internet address of sender
 	 * @param hops ZeroTier (not IP) hops
 	 * @param verb Packet verb
 	 * @param now Current time
 	 */
-	void onReceive(const RuntimeEnvironment *_r,Demarc::Port localPort,const InetAddress &fromAddr,unsigned int hops,Packet::Verb verb,uint64_t now);
+	void onReceive(const RuntimeEnvironment *_r,Demarc::Port localPort,const InetAddress &remoteAddr,unsigned int hops,Packet::Verb verb,uint64_t now);
 
 	/**
-	 * Send a UDP packet to this peer
-	 * 
-	 * If the active link is timed out (no receives for ping timeout ms), then
-	 * the active link number is incremented after send. This causes sends to
-	 * cycle through links if there is no clear active link. This also happens
-	 * if the send fails for some reason.
+	 * Send a packet to this peer
 	 * 
 	 * @param _r Runtime environment
 	 * @param data Data to send
 	 * @param len Length of packet
-	 * @param relay This is a relay on behalf of another peer (verb is ignored)
-	 * @param verb Packet verb (if not relay)
 	 * @param now Current time
 	 * @return True if packet appears to have been sent, false on local failure
 	 */
-	bool send(const RuntimeEnvironment *_r,const void *data,unsigned int len,bool relay,Packet::Verb verb,uint64_t now);
+	bool send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now);
+
+	/**
+	 * Must be called after a packet is successfully sent to this peer
+	 *
+	 * Note that 'relay' means we've sent a packet *from* this node to this
+	 * peer by relaying it, not that we have relayed a packet from somewhere
+	 * else to this peer. In the latter case this is not called.
+	 *
+	 * @param _r Runtime environment
+	 * @param relay If true, packet was sent indirectly via a relay
+	 * @param verb Packet verb
+	 * @param now Current time
+	 */
+	void onSent(const RuntimeEnvironment *_r,bool relay,Packet::Verb verb,uint64_t now);
 
 	/**
 	 * Send firewall opener to active link
@@ -194,7 +205,25 @@ public:
 	uint64_t lastUnicastFrame() const
 		throw()
 	{
-		return std::max(_ipv4p.lastUnicastFrame,_ipv6p.lastUnicastFrame);
+		return _lastUnicastFrame;
+	}
+
+	/**
+	 * @return Time of most recent multicast frame
+	 */
+	uint64_t lastMulticastFrame() const
+		throw()
+	{
+		return _lastMulticastFrame;
+	}
+
+	/**
+	 * @return Time of most recent frame of any kind (unicast or multicast)
+	 */
+	uint64_t lastFrame() const
+		throw()
+	{
+		return std::max(_lastUnicastFrame,_lastMulticastFrame);
 	}
 
 	/**
@@ -340,11 +369,13 @@ public:
 	inline void serialize(Buffer<C> &b)
 		throw(std::out_of_range)
 	{
-		b.append((unsigned char)1); // version
+		b.append((unsigned char)2); // version
 		b.append(_keys,sizeof(_keys));
 		_id.serialize(b,false);
 		_ipv4p.serialize(b);
 		_ipv6p.serialize(b);
+		b.append(_lastUnicastFrame);
+		b.append(_lastMulticastFrame);
 	}
 
 	template<unsigned int C>
@@ -353,14 +384,19 @@ public:
 	{
 		unsigned int p = startAt;
 
-		if (b[p++] != 1)
+		if (b[p++] != 2)
 			throw std::invalid_argument("Peer: deserialize(): version mismatch");
 
 		memcpy(_keys,b.field(p,sizeof(_keys)),sizeof(_keys)); p += sizeof(_keys);
 		p += _id.deserialize(b,p);
 		p += _ipv4p.deserialize(b,p);
 		p += _ipv6p.deserialize(b,p);
+		_lastUnicastFrame = b.template at<uint64_t>(p); p += sizeof(uint64_t);
+		_lastMulticastFrame = b.template at<uint64_t>(p); p += sizeof(uint64_t);
 
+		_vMajor = 0;
+		_vMinor = 0;
+		_vRevision = 0;
 		_dirty = false;
 
 		return (p - startAt);
@@ -400,7 +436,6 @@ private:
 		WanPath() :
 			lastSend(0),
 			lastReceive(0),
-			lastUnicastFrame(0),
 			lastFirewallOpener(0),
 			localPort(Demarc::ANY_PORT),
 			latency(0),
@@ -421,7 +456,6 @@ private:
 		{
 			b.append(lastSend);
 			b.append(lastReceive);
-			b.append(lastUnicastFrame);
 			b.append(lastFirewallOpener);
 			b.append(Demarc::portToInt(localPort));
 			b.append((uint16_t)latency);
@@ -451,7 +485,6 @@ private:
 
 			lastSend = b.template at<uint64_t>(p); p += sizeof(uint64_t);
 			lastReceive = b.template at<uint64_t>(p); p += sizeof(uint64_t);
-			lastUnicastFrame = b.template at<uint64_t>(p); p += sizeof(uint64_t);
 			lastFirewallOpener = b.template at<uint64_t>(p); p += sizeof(uint64_t);
 			localPort = Demarc::intToPort(b.template at<uint64_t>(p)); p += sizeof(uint64_t);
 			latency = b.template at<uint16_t>(p); p += sizeof(uint16_t);
@@ -477,9 +510,8 @@ private:
 
 		uint64_t lastSend;
 		uint64_t lastReceive;
-		uint64_t lastUnicastFrame;
 		uint64_t lastFirewallOpener;
-		Demarc::Port localPort; // ANY_PORT if not defined
+		Demarc::Port localPort; // ANY_PORT if not defined (size: uint64_t)
 		unsigned int latency; // 0 if never determined
 		InetAddress addr; // null InetAddress if path is undefined
 		bool fixed; // do not learn address from received packets
@@ -491,6 +523,9 @@ private:
 	WanPath _ipv4p;
 	WanPath _ipv6p;
 
+	uint64_t _lastUnicastFrame;
+	uint64_t _lastMulticastFrame;
+
 	// Fields below this line are not persisted with serialize()
 
 	unsigned int _vMajor,_vMinor,_vRevision;
@@ -501,4 +536,13 @@ private:
 
 } // namespace ZeroTier
 
+// Add a swap() for shared ptr's to peers to speed up peer sorts
+namespace std {
+	template<>
+	inline void swap(ZeroTier::SharedPtr<ZeroTier::Peer> &a,ZeroTier::SharedPtr<ZeroTier::Peer> &b)
+	{
+		a.swap(b);
+	}
+}
+
 #endif

+ 3 - 4
node/RuntimeEnvironment.hpp

@@ -31,7 +31,6 @@
 #include <string>
 #include "Identity.hpp"
 #include "Condition.hpp"
-#include "CMWC4096.hpp"
 
 namespace ZeroTier {
 
@@ -42,6 +41,7 @@ class Switch;
 class Topology;
 class SysEnv;
 class Multicaster;
+class CMWC4096;
 
 /**
  * Holds global state for an instance of ZeroTier::Node
@@ -61,6 +61,7 @@ public:
 	RuntimeEnvironment() :
 		identity(),
 		log((Logger *)0),
+		prng((CMWC4096 *)0),
 		nc((NodeConfig *)0),
 		demarc((Demarc *)0),
 		multicaster((Multicaster *)0),
@@ -78,13 +79,11 @@ public:
 	// signal() to prematurely interrupt main loop wait
 	Condition mainLoopWaitCondition;
 
-	// non-cryptographic fast PRNG
-	CMWC4096 prng;
-
 	Identity configAuthority;
 	Identity identity;
 
 	Logger *log; // may be null
+	CMWC4096 *prng;
 	NodeConfig *nc;
 	Demarc *demarc;
 	Multicaster *multicaster;

+ 32 - 22
node/Switch.cpp

@@ -101,6 +101,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 		Multicaster::MulticastBloomFilter bloom;
 		SharedPtr<Peer> propPeers[ZT_MULTICAST_PROPAGATION_BREADTH];
 		unsigned int np = _r->multicaster->pickNextPropagationPeers(
+			*(_r->prng),
 			*(_r->topology),
 			network->id(),
 			mg,
@@ -187,15 +188,20 @@ void Switch::sendHELLO(const Address &dest)
 
 bool Switch::sendHELLO(const SharedPtr<Peer> &dest,Demarc::Port localPort,const InetAddress &addr)
 {
+	uint64_t now = Utils::now();
 	Packet outp(dest->address(),_r->identity.address(),Packet::VERB_HELLO);
 	outp.append((unsigned char)ZT_PROTO_VERSION);
 	outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
 	outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
 	outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
-	outp.append(Utils::now());
+	outp.append(now);
 	_r->identity.serialize(outp,false);
 	outp.hmacSet(dest->macKey());
-	return _r->demarc->send(localPort,addr,outp.data(),outp.size(),-1);
+	if (_r->demarc->send(localPort,addr,outp.data(),outp.size(),-1)) {
+		dest->onSent(_r,false,Packet::VERB_HELLO,now);
+		return true;
+	}
+	return false;
 }
 
 bool Switch::unite(const Address &p1,const Address &p2,bool force)
@@ -249,7 +255,8 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
 		}
 		outp.encrypt(p1p->cryptKey());
 		outp.hmacSet(p1p->macKey());
-		p1p->send(_r,outp.data(),outp.size(),false,Packet::VERB_RENDEZVOUS,now);
+		if (p1p->send(_r,outp.data(),outp.size(),now))
+			p1p->onSent(_r,false,Packet::VERB_RENDEZVOUS,now);
 	}
 	{	// tell p2 where to find p1
 		Packet outp(p2,_r->identity.address(),Packet::VERB_RENDEZVOUS);
@@ -264,7 +271,8 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
 		}
 		outp.encrypt(p2p->cryptKey());
 		outp.hmacSet(p2p->macKey());
-		p2p->send(_r,outp.data(),outp.size(),false,Packet::VERB_RENDEZVOUS,now);
+		if (p2p->send(_r,outp.data(),outp.size(),now))
+			p2p->onSent(_r,false,Packet::VERB_RENDEZVOUS,now);
 	}
 
 	return true;
@@ -443,12 +451,11 @@ void Switch::_handleRemotePacketFragment(Demarc::Port localPort,const InetAddres
 		// Fragment is not for us, so try to relay it
 		if (fragment.hops() < ZT_RELAY_MAX_HOPS) {
 			fragment.incrementHops();
-
 			SharedPtr<Peer> relayTo = _r->topology->getPeer(destination);
-			if ((!relayTo)||(!relayTo->send(_r,fragment.data(),fragment.size(),true,Packet::VERB_NOP,Utils::now()))) {
+			if ((!relayTo)||(!relayTo->send(_r,fragment.data(),fragment.size(),Utils::now()))) {
 				relayTo = _r->topology->getBestSupernode();
 				if (relayTo)
-					relayTo->send(_r,fragment.data(),fragment.size(),true,Packet::VERB_NOP,Utils::now());
+					relayTo->send(_r,fragment.data(),fragment.size(),Utils::now());
 			}
 		} else {
 			TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str());
@@ -516,18 +523,19 @@ void Switch::_handleRemotePacketHead(Demarc::Port localPort,const InetAddress &f
 			packet->incrementHops();
 
 			SharedPtr<Peer> relayTo = _r->topology->getPeer(destination);
-			if ((relayTo)&&(relayTo->send(_r,packet->data(),packet->size(),true,Packet::VERB_NOP,Utils::now()))) {
-				unite(source,destination,false); // periodically try to get them to talk directly
+			if ((relayTo)&&(relayTo->send(_r,packet->data(),packet->size(),Utils::now()))) {
+				// If we've relayed, this periodically tries to get them to
+				// talk directly to save our bandwidth.
+				unite(source,destination,false);
 			} else {
-				// Relay via a supernode if there's no direct path, but pass
-				// source to getBestSupernode() to avoid just in case this is
-				// being passed from another supernode so that we don't just
-				// pass it back to where it came from. This can happen if a
-				// supernode for some reason lacks a direct path to a peer that
-				// it wants to talk to, such as because of Internet weather.
+				// If we've received a packet not for us and we don't have
+				// a direct path to its recipient, pass it to (another)
+				// supernode. This can happen due to Internet weather -- the
+				// most direct supernode may not be reachable, yet another
+				// further away may be.
 				relayTo = _r->topology->getBestSupernode(&source,1,true);
 				if (relayTo)
-					relayTo->send(_r,packet->data(),packet->size(),true,Packet::VERB_NOP,Utils::now());
+					relayTo->send(_r,packet->data(),packet->size(),Utils::now());
 			}
 		} else {
 			TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet->source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str());
@@ -584,8 +592,11 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread
 		outp.append(addr.data(),ZT_ADDRESS_LENGTH);
 		outp.encrypt(supernode->cryptKey());
 		outp.hmacSet(supernode->macKey());
-		supernode->send(_r,outp.data(),outp.size(),false,Packet::VERB_WHOIS,Utils::now());
-		return supernode->address();
+		uint64_t now = Utils::now();
+		if (supernode->send(_r,outp.data(),outp.size(),now)) {
+			supernode->onSent(_r,false,Packet::VERB_WHOIS,now);
+			return supernode->address();
+		}
 	}
 	return Address();
 }
@@ -618,8 +629,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
 			tmp.encrypt(peer->cryptKey());
 		tmp.hmacSet(peer->macKey());
 
-		Packet::Verb verb = packet.verb();
-		if (via->send(_r,tmp.data(),chunkSize,isRelay,verb,now)) {
+		if (via->send(_r,tmp.data(),chunkSize,now)) {
 			if (chunkSize < tmp.size()) {
 				// Too big for one bite, fragment the rest
 				unsigned int fragStart = chunkSize;
@@ -632,15 +642,15 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
 				for(unsigned int f=0;f<fragsRemaining;++f) {
 					chunkSize = std::min(remaining,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH));
 					Packet::Fragment frag(tmp,fragStart,chunkSize,f + 1,totalFragments);
-					if (!via->send(_r,frag.data(),frag.size(),isRelay,verb,now)) {
+					if (!via->send(_r,frag.data(),frag.size(),now)) {
 						TRACE("WARNING: packet send to %s failed on later fragment #%u (check IP layer buffer sizes?)",via->address().toString().c_str(),f + 1);
-						return false;
 					}
 					fragStart += chunkSize;
 					remaining -= chunkSize;
 				}
 			}
 
+			via->onSent(_r,isRelay,packet.verb(),now);
 			return true;
 		}
 		return false;

+ 2 - 1
node/Topology.cpp

@@ -28,6 +28,7 @@
 #include <algorithm>
 #include "Topology.hpp"
 #include "NodeConfig.hpp"
+#include "CMWC4096.hpp"
 
 namespace ZeroTier {
 
@@ -201,7 +202,7 @@ skip_and_try_next_supernode:
 	if (bestSupernode)
 		return bestSupernode;
 
-	return _supernodePeers[_r->prng.next32() % _supernodePeers.size()];
+	return _supernodePeers[_r->prng->next32() % _supernodePeers.size()];
 }
 
 void Topology::clean()