Browse Source

Just about everything refactored for new Protocol/Buf code except Switch.

Adam Ierymenko 5 years ago
parent
commit
7d11522768

+ 17 - 17
controller/EmbeddedNetworkController.cpp

@@ -522,7 +522,7 @@ void EmbeddedNetworkController::request(
 	const InetAddress &fromAddr,
 	uint64_t requestPacketId,
 	const Identity &identity,
-	const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData)
+	const Dictionary &metaData)
 {
 	if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender))
 		return;
@@ -1104,7 +1104,7 @@ void EmbeddedNetworkController::onNetworkUpdate(const void *db,uint64_t networkI
 	const int64_t now = OSUtils::now();
 	std::lock_guard<std::mutex> l(_memberStatus_l);
 	for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) {
-		if ((i->first.networkId == networkId)&&(i->second.online(now))&&(i->second.lastRequestMetaData))
+		if ((i->first.networkId == networkId)&&(i->second.online(now))&&(i->second.lastRequestMetaData.size() > 0))
 			request(networkId,InetAddress(),0,i->second.identity,i->second.lastRequestMetaData);
 	}
 }
@@ -1115,7 +1115,7 @@ void EmbeddedNetworkController::onNetworkMemberUpdate(const void *db,uint64_t ne
 	try {
 		std::lock_guard<std::mutex> l(_memberStatus_l);
 		_MemberStatus &ms = _memberStatus[_MemberStatusKey(networkId,memberId)];
-		if ((ms.online(OSUtils::now()))&&(ms.lastRequestMetaData))
+		if ((ms.online(OSUtils::now()))&&(ms.lastRequestMetaData.size() > 0))
 			request(networkId,InetAddress(),0,ms.identity,ms.lastRequestMetaData);
 	} catch ( ... ) {}
 }
@@ -1139,7 +1139,7 @@ void EmbeddedNetworkController::_request(
 	const InetAddress &fromAddr,
 	uint64_t requestPacketId,
 	const Identity &identity,
-	const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData)
+	const Dictionary &metaData)
 {
 	char nwids[24];
 	DB::NetworkSummaryInfo ns;
@@ -1212,19 +1212,18 @@ void EmbeddedNetworkController::_request(
 		autoAuthCredentialType = "public";
 	} else {
 		char presentedAuth[512];
-		if (metaData.get(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH,presentedAuth,sizeof(presentedAuth)) > 0) {
-			presentedAuth[511] = (char)0; // sanity check
-			if ((strlen(presentedAuth) > 6)&&(!strncmp(presentedAuth,"token:",6))) {
-				const char *const presentedToken = presentedAuth + 6;
-				json authTokens(network["authTokens"]);
-				json &tokenExpires = authTokens[presentedToken];
-				if (tokenExpires.is_number()) {
-					if ((tokenExpires == 0)||(tokenExpires > now)) {
-						authorized = true;
-						autoAuthorized = true;
-						autoAuthCredentialType = "token";
-						autoAuthCredential = presentedToken;
-					}
+		metaData.getS(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH,presentedAuth,sizeof(presentedAuth));
+		presentedAuth[511] = 0; // sanity check, make sure always terminated
+		if ((strlen(presentedAuth) > 6)&&(!strncmp(presentedAuth,"token:",6))) {
+			const char *const presentedToken = presentedAuth + 6;
+			json authTokens(network["authTokens"]);
+			json &tokenExpires = authTokens[presentedToken];
+			if (tokenExpires.is_number()) {
+				if ((tokenExpires == 0)||(tokenExpires > now)) {
+					authorized = true;
+					autoAuthorized = true;
+					autoAuthCredentialType = "token";
+					autoAuthCredential = presentedToken;
 				}
 			}
 		}
@@ -1296,6 +1295,7 @@ void EmbeddedNetworkController::_request(
 	nc->credentialTimeMaxDelta = credentialtmd;
 	nc->revision = OSUtils::jsonInt(network["revision"],0ULL);
 	nc->issuedTo = identity.address();
+	memcpy(nc->issuedToIdentityHash,identity.hash(),sizeof(nc->issuedToIdentityHash));
 	if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
 	Utils::scopy(nc->name,sizeof(nc->name),OSUtils::jsonString(network["name"],"").c_str());
 	nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU);

+ 11 - 8
controller/EmbeddedNetworkController.hpp

@@ -64,7 +64,7 @@ public:
 		const InetAddress &fromAddr,
 		uint64_t requestPacketId,
 		const Identity &identity,
-		const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
+		const Dictionary &metaData);
 
 	unsigned int handleControlPlaneHttpGET(
 		const std::vector<std::string> &path,
@@ -87,7 +87,7 @@ public:
 	virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId);
 
 private:
-	void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
+	void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary &metaData);
 	void _startThreads();
 
 	struct _RQEntry
@@ -96,31 +96,34 @@ private:
 		uint64_t requestPacketId;
 		InetAddress fromAddr;
 		Identity identity;
-		Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData;
+		Dictionary metaData;
 		enum {
 			RQENTRY_TYPE_REQUEST = 0
 		} type;
 	};
+
 	struct _MemberStatusKey
 	{
-		_MemberStatusKey() : networkId(0),nodeId(0) {}
-		_MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {}
+		ZT_ALWAYS_INLINE _MemberStatusKey() : networkId(0),nodeId(0) {}
+		ZT_ALWAYS_INLINE _MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {}
 		uint64_t networkId;
 		uint64_t nodeId;
 		inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); }
 	};
+
 	struct _MemberStatus
 	{
-		_MemberStatus() : lastRequestTime(0),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {}
+		ZT_ALWAYS_INLINE _MemberStatus() : lastRequestTime(0),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {}
 		uint64_t lastRequestTime;
 		int vMajor,vMinor,vRev,vProto;
-		Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData;
+		Dictionary lastRequestMetaData;
 		Identity identity;
 		inline bool online(const int64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); }
 	};
+
 	struct _MemberStatusHash
 	{
-		inline std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const
+		ZT_ALWAYS_INLINE std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const
 		{
 			return (std::size_t)(networkIdNodeId.networkId + networkIdNodeId.nodeId);
 		}

File diff suppressed because it is too large
+ 0 - 4
go/native/CoreTests.cpp


+ 7 - 8
node/AtomicCounter.hpp

@@ -15,23 +15,25 @@
 #define ZT_ATOMICCOUNTER_HPP
 
 #include "Constants.hpp"
+#include "TriviallyCopyable.hpp"
 
 #ifndef __GNUC__
-#include <atomic>
+#include <intrin.h>
 #endif
 
 namespace ZeroTier {
 
 /**
- * Simple atomic counter
+ * Simple atomic integer used for reference and other counters
  *
  * @tparam T Type of underlying integer (default: int)
  */
 template<typename T = int>
-class AtomicCounter
+class AtomicCounter : public TriviallyCopyable
 {
 public:
-	explicit ZT_ALWAYS_INLINE AtomicCounter(T iv = T(0)) : _v(iv) {}
+	ZT_ALWAYS_INLINE AtomicCounter() : _v(0) {}
+	explicit ZT_ALWAYS_INLINE AtomicCounter(T iv) : _v(iv) {}
 
 	ZT_ALWAYS_INLINE T load() const
 	{
@@ -42,10 +44,7 @@ public:
 #endif
 	}
 
-	ZT_ALWAYS_INLINE void zero()
-	{
-		_v = T(0);
-	}
+	ZT_ALWAYS_INLINE void zero() { _v = 0; }
 
 	ZT_ALWAYS_INLINE T operator++()
 	{

+ 2 - 1
node/Buf.hpp

@@ -19,6 +19,7 @@
 #include "Utils.hpp"
 #include "SharedPtr.hpp"
 #include "Mutex.hpp"
+#include "TriviallyCopyable.hpp"
 
 #include <cstdint>
 #include <cstring>
@@ -113,7 +114,7 @@ public:
 	/**
 	 * Slice is almost exactly like the built-in slice data structure in Go
 	 */
-	struct Slice
+	struct Slice : TriviallyCopyable
 	{
 		ZT_ALWAYS_INLINE Slice(const SharedPtr<Buf> &b_,const unsigned int s_,const unsigned int e_) : b(b_),s(s_),e(e_) {}
 		ZT_ALWAYS_INLINE Slice() : b(),s(0),e(0) {}

+ 1 - 1
node/CertificateOfOwnership.cpp

@@ -33,7 +33,7 @@ void CertificateOfOwnership::addThing(const MAC &mac)
 {
 	if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
 	_thingTypes[_thingCount] = THING_MAC_ADDRESS;
-	mac.copyTo(_thingValues[_thingCount],6);
+	mac.copyTo(_thingValues[_thingCount]);
 	++_thingCount;
 }
 

+ 16 - 33
node/Defragmenter.hpp

@@ -88,6 +88,7 @@ public:
 	struct Result
 	{
 		ZT_ALWAYS_INLINE Result() : message(),messageFragmentCount(0),error(Defragmenter::ERR_NONE) {}
+		explicit ZT_ALWAYS_INLINE Result(const Defragmenter::ErrorCode e) : message(),messageFragmentCount(0),error(e) {}
 
 		/**
 		 * Fully assembled message as a series of slices of fragments
@@ -186,25 +187,21 @@ public:
 		const unsigned long messageQueueSizeTarget,
 		const unsigned long messageQueueSizeGCTrigger)
 	{
-		Result r;
-
 		// Sanity checks for malformed fragments or invalid input parameters.
-		if ((fragmentNo >= totalFragmentsExpected)||(totalFragmentsExpected > MF)||(totalFragmentsExpected == 0)) {
-			r.error = ERR_INVALID_FRAGMENT;
-			return r;
-		}
+		if ((fragmentNo >= totalFragmentsExpected)||(totalFragmentsExpected > MF)||(totalFragmentsExpected == 0))
+			return Result(ERR_INVALID_FRAGMENT);
 
 		// If there is only one fragment just return that fragment and we are done.
 		if (totalFragmentsExpected < 2) {
 			if (fragmentNo == 0) {
+				Result r;
 				r.message[0].b.move(fragment);
 				r.message[0].s = fragmentDataIndex;
 				r.message[0].e = fragmentDataSize;
 				r.messageFragmentCount = 1;
 				return r;
 			} else {
-				r.error = ERR_INVALID_FRAGMENT;
-				return r;
+				return Result(ERR_INVALID_FRAGMENT);
 			}
 		}
 
@@ -246,8 +243,7 @@ public:
 					_messages_l.lock();
 					_messages.clear();
 					_messages_l.unlock();
-					r.error = ERR_OUT_OF_MEMORY;
-					return r;
+					return Result(ERR_OUT_OF_MEMORY);
 				}
 			}
 		}
@@ -260,8 +256,7 @@ public:
 				RWMutex::Lock ml(_messages_l);
 				e = &(_messages[messageId]);
 			} catch ( ... ) {
-				r.error = ERR_OUT_OF_MEMORY;
-				return r;
+				return Result(ERR_OUT_OF_MEMORY);
 			}
 			e->id = messageId;
 		}
@@ -292,8 +287,7 @@ public:
 			}
 			via->_inboundFragmentedMessages_l.unlock();
 			if (tooManyPerPath) {
-				r.error = ERR_TOO_MANY_FRAGMENTS_FOR_PATH;
-				return r;
+				return Result(ERR_TOO_MANY_FRAGMENTS_FOR_PATH);
 			}
 		}
 
@@ -305,11 +299,9 @@ public:
 		// data would just mean the transfer is corrupt and would be detected
 		// later e.g. by packet MAC check. Other use cases of this code like
 		// network configs check each fragment so this basically can't happen.
-		Buf<>::Slice &s = e->fragment[fragmentNo];
-		if (s.b) {
-			r.error = ERR_DUPLICATE_FRAGMENT;
-			return r;
-		}
+		Buf<>::Slice &s = e->result.message[fragmentNo];
+		if (s.b)
+			return Result(ERR_DUPLICATE_FRAGMENT);
 
 		// Take ownership of fragment, setting 'fragment' pointer to NULL. The simple
 		// transfer of the pointer avoids a synchronized increment/decrement of the object's
@@ -319,7 +311,7 @@ public:
 		s.e = fragmentDataIndex + fragmentDataSize;
 
 		// If we now have all fragments then assemble them.
-		if (++e->fragmentCount >= totalFragmentsExpected) {
+		if (++e->result.messageFragmentCount >= totalFragmentsExpected) {
 			// This message is done so de-register it with its path if one is associated.
 			if (e->via) {
 				e->via->_inboundFragmentedMessages_l.lock();
@@ -328,18 +320,10 @@ public:
 				e->via.zero();
 			}
 
-			// PERFORMANCE HACK: SharedPtr<> is introspective and only holds a pointer, so we
-			// can 'move' the pointers it holds very quickly by bulk copying the source
-			// slices and then zeroing the originals. This is only okay if the destination
-			// currently holds no pointers, which should always be the case. Don't try this
-			// at home kids.
-			unsigned int msize = e->fragmentCount * sizeof(Buf<>::Slice);
-			memcpy(reinterpret_cast<void *>(r.message),reinterpret_cast<const void *>(e->fragment),msize);
-			memset(reinterpret_cast<void *>(e->fragment),0,msize);
-			r.messageFragmentCount = e->fragmentCount;
+			return e->result;
 		}
 
-		return r;
+		return Result(ERR_NONE);
 	}
 
 	/**
@@ -354,7 +338,7 @@ public:
 private:
 	struct _E
 	{
-		ZT_ALWAYS_INLINE _E() : id(0),lastUsed(0),via(),fragmentCount(0) {}
+		ZT_ALWAYS_INLINE _E() : id(0),lastUsed(0),via() {}
 		ZT_ALWAYS_INLINE ~_E()
 		{
 			// Ensure that this entry is not in use while it is being deleted!
@@ -369,8 +353,7 @@ private:
 		uint64_t id;
 		volatile int64_t lastUsed;
 		SharedPtr<Path> via;
-		Buf<>::Slice fragment[MF];
-		unsigned int fragmentCount;
+		Result result;
 		Mutex lock;
 	};
 

+ 2 - 7
node/Endpoint.hpp

@@ -53,10 +53,7 @@ public:
 
 	ZT_ALWAYS_INLINE Endpoint() { memoryZero(this); }
 
-	explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa)
-	{
-		*this = sa;
-	}
+	explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) { *this = sa; }
 
 	ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) :
 		_t(ZEROTIER)
@@ -74,9 +71,7 @@ public:
 
 	explicit ZT_ALWAYS_INLINE Endpoint(const char *url) :
 		_t(URL)
-	{
-		Utils::scopy(_v.url,sizeof(_v.url),url);
-	}
+	{ Utils::scopy(_v.url,sizeof(_v.url),url); }
 
 	ZT_ALWAYS_INLINE Endpoint &operator=(const InetAddress &sa)
 	{

+ 1 - 1
node/Hashtable.hpp

@@ -358,7 +358,7 @@ private:
 	static ZT_ALWAYS_INLINE unsigned long _hc(const uint32_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
 	static ZT_ALWAYS_INLINE unsigned long _hc(const uint16_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
 	static ZT_ALWAYS_INLINE unsigned long _hc(const uint8_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
-	static ZT_ALWAYS_INLINE unsigned long _hc(const int64_t i) { return (unsigned long)(i ^ (i >> 32U)); }
+	static ZT_ALWAYS_INLINE unsigned long _hc(const int64_t i) { return (unsigned long)((unsigned long long)i ^ ((unsigned long long)i >> 32U)); }
 	static ZT_ALWAYS_INLINE unsigned long _hc(const int32_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
 	static ZT_ALWAYS_INLINE unsigned long _hc(const int16_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
 	static ZT_ALWAYS_INLINE unsigned long _hc(const int8_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }

+ 29 - 28
node/IncomingPacket.cpp

@@ -336,7 +336,7 @@ ZT_ALWAYS_INLINE bool _doOK(IncomingPacket &p,const RuntimeEnvironment *const RR
 			networkId = pkt.rI64(ptr);
 			const SharedPtr<Network> network(RR->node->network(networkId));
 			if (network)
-				network->handleConfigChunk(tPtr,p.idBE,peer->address(),pkt,sizeof(Protocol::OK::Header),(int)p.size);
+				network->handleConfigChunk(tPtr,p.idBE,peer,pkt,sizeof(Protocol::OK::Header),(int)p.size);
 		}	break;
 
 		case Protocol::VERB_MULTICAST_GATHER: {
@@ -782,33 +782,34 @@ ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG_REQUEST(IncomingPacket &p,const RuntimeE
 ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
 {
 	int ptr = sizeof(Protocol::Header);
-
 	const uint64_t nwid = p.pkt->rI64(ptr);
-	if (Buf<>::readOverflow(ptr,p.size)) {
-		RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CONFIG_REQUEST,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
+	if (ptr >= (int)p.size) {
+		RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CONFIG,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
 		return true;
 	}
 
 	const SharedPtr<Network> network(RR->node->network(nwid));
 	if (network) {
-	}
+		const uint64_t configUpdateId = network->handleConfigChunk(tPtr,p.idBE,peer,*p.pkt,ptr,(int)p.size - ptr);
+		if (configUpdateId != 0) {
+			ZT_GET_NEW_BUF(outp,Protocol::OK::NETWORK_CONFIG);
 
-	/*
-	const SharedPtr<Network> network(RR->node->network(pkt.at<uint64_t>(ZT_PACKET_IDX_PAYLOAD)));
-	if (network) {
-		const uint64_t configUpdateId = network->handleConfigChunk(tPtr,pkt.packetId(),pkt.source(),pkt,ZT_PACKET_IDX_PAYLOAD);
-		if (configUpdateId) {
-			Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
-			outp.append((uint8_t)Packet::VERB_ECHO);
-			outp.append((uint64_t)pkt.packetId());
-			outp.append((uint64_t)network->id());
-			outp.append((uint64_t)configUpdateId);
-			outp.armor(peer->key(),true);
-			path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
+			outp->data.fields.h.packetId = Protocol::getPacketId();
+			peer->address().copyTo(outp->data.fields.h.destination);
+			RR->identity.address().copyTo(outp->data.fields.h.source);
+			outp->data.fields.h.flags = 0;
+			outp->data.fields.h.verb = Protocol::VERB_OK;
+
+			outp->data.fields.oh.inReVerb = Protocol::VERB_NETWORK_CONFIG;
+			outp->data.fields.oh.inRePacketId = p.idBE;
+
+			outp->data.fields.networkId = Utils::hton(nwid);
+			outp->data.fields.configUpdateId = Utils::hton(configUpdateId);
+
+			Protocol::armor(*outp,sizeof(Protocol::OK::NETWORK_CONFIG),peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
+			p.path->send(RR,tPtr,outp->data.bytes,sizeof(Protocol::OK::NETWORK_CONFIG),RR->node->now());
 		}
 	}
-	peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,(network) ? network->id() : 0);
-	 */
 
 	peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_NETWORK_CONFIG,0,Protocol::VERB_NOP,nwid);
 	return true;
@@ -873,17 +874,17 @@ ZT_ALWAYS_INLINE bool _doPUSH_DIRECT_PATHS(IncomingPacket &p,const RuntimeEnviro
 
 ZT_ALWAYS_INLINE bool _doUSER_MESSAGE(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer)
 {
-	/*
-	if (likely(pkt.size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) {
-		ZT_UserMessage um;
-		um.id = (const ZT_Identity *)(&(peer->identity()));
-		um.typeId = pkt.at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
-		um.data = reinterpret_cast<const void *>(reinterpret_cast<const uint8_t *>(pkt.data()) + ZT_PACKET_IDX_PAYLOAD + 8);
-		um.length = pkt.size() - (ZT_PACKET_IDX_PAYLOAD + 8);
+	ZT_UserMessage um;
+	int ptr = sizeof(Protocol::Header);
+	um.id = reinterpret_cast<const ZT_Identity *>(&(peer->identity()));
+	um.typeId = p.pkt->rI64(ptr);
+	int ds = (int)p.size - ptr;
+	if (ds > 0) {
+		um.data = p.pkt->data.bytes + ptr;
+		um.length = (unsigned int)ds;
 		RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast<const void *>(&um));
 	}
-	peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,0);
-	 */
+	peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_USER_MESSAGE,0,Protocol::VERB_NOP,0);
 	return true;
 }
 

+ 6 - 3
node/Network.cpp

@@ -849,7 +849,7 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg)
 		_myMulticastGroups.erase(i);
 }
 
-uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const Address &source,const Buf<> &chunk,int ptr,int size)
+uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr<Peer> &source,const Buf<> &chunk,int ptr,int size)
 {
 	if (_destroyed)
 		return 0;
@@ -907,7 +907,7 @@ uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const Address &
 			Membership *m = nullptr;
 			Hashtable<Address,Membership>::Iterator i(_memberships);
 			while (i.next(a,m)) {
-				if ((*a != source)&&(*a != controller())) {
+				if ((*a != source->address())&&(*a != controller())) {
 					ZT_GET_NEW_BUF(outp,Protocol::Header);
 
 					outp->data.fields.packetId = Protocol::getPacketId();
@@ -926,7 +926,7 @@ uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const Address &
 				}
 			}
 		}
-	} else if ((source == controller())||(!source)) {
+	} else if ((!source)||(source->address() != this->controller())) {
 		// Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers that don't sign chunks and don't
 		// support multiple chunks. Since old controllers don't sign chunks we only accept the message if it comes
 		// directly from the controller.
@@ -990,6 +990,9 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
 	try {
 		if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id))
 			return 0; // invalid config that is not for us or not for this network
+		if ((!Utils::allZero(nconf.issuedToIdentityHash,ZT_IDENTITY_HASH_SIZE))&&(memcmp(nconf.issuedToIdentityHash,RR->identity.hash(),ZT_IDENTITY_HASH_SIZE) != 0))
+			return 0; // full identity hash is present and does not match
+
 		if (_config == nconf)
 			return 1; // OK config, but duplicate of what we already have
 

+ 4 - 4
node/Network.hpp

@@ -77,7 +77,7 @@ public:
 	~Network();
 
 	ZT_ALWAYS_INLINE uint64_t id() const { return _id; }
-	ZT_ALWAYS_INLINE Address controller() const { return Address(_id >> 24); }
+	ZT_ALWAYS_INLINE Address controller() const { return Address(_id >> 24U); }
 	ZT_ALWAYS_INLINE bool multicastEnabled() const { return (_config.multicastLimit > 0); }
 	ZT_ALWAYS_INLINE bool hasConfig() const { return (_config); }
 	ZT_ALWAYS_INLINE uint64_t lastConfigUpdate() const { return _lastConfigUpdate; }
@@ -190,13 +190,13 @@ public:
 	 *
 	 * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
 	 * @param packetId Packet ID or 0 if none (e.g. via cluster path)
-	 * @param source Address of sender of chunk or NULL if none (e.g. via cluster path)
+	 * @param source Peer that actually sent this chunk (probably controller)
 	 * @param chunk Buffer containing chunk
 	 * @param ptr Index of chunk and related fields in packet (starting with network ID)
 	 * @param size Size of data in chunk buffer (total, not relative to ptr)
 	 * @return Update ID if update was fully assembled and accepted or 0 otherwise
 	 */
-	uint64_t handleConfigChunk(void *tPtr,uint64_t packetId,const Address &source,const Buf<> &chunk,int ptr,int size);
+	uint64_t handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr<Peer> &source,const Buf<> &chunk,int ptr,int size);
 
 	/**
 	 * Set network configuration
@@ -403,7 +403,7 @@ private:
 	Mutex _config_l;
 	Mutex _memberships_l;
 
-	AtomicCounter __refCount;
+	AtomicCounter<int> __refCount;
 };
 
 } // namespace ZeroTier

+ 2 - 1
node/NetworkConfig.hpp

@@ -275,7 +275,8 @@ struct NetworkConfig : TriviallyCopyable
 	/**
 	 * Hash of identity public key(s) of node to whom this is issued
 	 *
-	 * TODO
+	 * If this field is all zero it is treated as undefined since old controllers
+	 * do not set it.
 	 */
 	uint8_t issuedToIdentityHash[ZT_IDENTITY_HASH_SIZE];
 

+ 0 - 1
node/Node.hpp

@@ -18,7 +18,6 @@
 #include <cstdlib>
 #include <cstring>
 
-#include <map>
 #include <vector>
 
 #include "Constants.hpp"

+ 0 - 31
node/Path.hpp

@@ -47,37 +47,6 @@ class Path
 	friend class Defragmenter;
 
 public:
-	/**
-	 * Efficient unique key for paths in a Hashtable
-	 */
-	class HashKey
-	{
-	public:
-		ZT_ALWAYS_INLINE HashKey() {}
-		ZT_ALWAYS_INLINE HashKey(const int64_t l,const InetAddress &r)
-		{
-			if (r.ss_family == AF_INET) {
-				_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr;
-				_k[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port;
-				_k[2] = (uint64_t)l;
-			} else if (r.ss_family == AF_INET6) {
-				memcpy(_k,reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
-				_k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port << 32) ^ (uint64_t)l;
-			} else {
-				memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress)));
-				_k[2] += (uint64_t)l;
-			}
-		}
-
-		ZT_ALWAYS_INLINE unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); }
-
-		ZT_ALWAYS_INLINE bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); }
-		ZT_ALWAYS_INLINE bool operator!=(const HashKey &k) const { return (!(*this == k)); }
-
-	private:
-		uint64_t _k[3];
-	};
-
 	ZT_ALWAYS_INLINE Path(const int64_t l,const InetAddress &r) :
 		_localSocket(l),
 		_lastIn(0),

+ 8 - 0
node/Protocol.hpp

@@ -855,6 +855,14 @@ ZT_PACKED_STRUCT(struct EXT_FRAME
 	uint16_t etherType;
 });
 
+ZT_PACKED_STRUCT(struct NETWORK_CONFIG
+{
+	Protocol::Header h;
+	OK::Header oh;
+	uint64_t networkId;
+	uint64_t configUpdateId;
+});
+
 } // namespace OK
 
 namespace ERROR {

+ 3 - 3
node/SHA512.cpp

@@ -250,9 +250,9 @@ void KBKDFHMACSHA384(const uint8_t key[32],const char label,const char context,c
 {
 	uint8_t kbkdfMsg[13];
 	uint8_t kbuf[48];
-	kbkdfMsg[0] = (uint8_t)(iter >> 24);
-	kbkdfMsg[1] = (uint8_t)(iter >> 16);
-	kbkdfMsg[2] = (uint8_t)(iter >> 8);
+	kbkdfMsg[0] = (uint8_t)(iter >> 24U);
+	kbkdfMsg[1] = (uint8_t)(iter >> 16U);
+	kbkdfMsg[2] = (uint8_t)(iter >> 8U);
 	kbkdfMsg[3] = (uint8_t)iter;
 	kbkdfMsg[4] = (uint8_t)'Z';
 	kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific

+ 1 - 0
node/SelfAwareness.hpp

@@ -80,6 +80,7 @@ private:
 		ZT_ALWAYS_INLINE bool operator==(const PhySurfaceKey &k) const { return ((reporter == k.reporter)&&(receivedOnLocalSocket == k.receivedOnLocalSocket)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); }
 		ZT_ALWAYS_INLINE bool operator!=(const PhySurfaceKey &k) const { return (!(*this == k)); }
 	};
+
 	struct PhySurfaceEntry
 	{
 		InetAddress mySurface;

+ 2 - 1
node/SharedPtr.hpp

@@ -15,6 +15,7 @@
 #define ZT_SHAREDPTR_HPP
 
 #include "AtomicCounter.hpp"
+#include "TriviallyCopyable.hpp"
 
 namespace ZeroTier {
 
@@ -26,7 +27,7 @@ namespace ZeroTier {
  * AtomicCounter called __refCount.
  */
 template<typename T>
-class SharedPtr
+class SharedPtr : public TriviallyCopyable
 {
 public:
 	ZT_ALWAYS_INLINE SharedPtr() : _ptr((T *)0) {}

+ 11 - 9
node/Topology.cpp

@@ -15,6 +15,8 @@
 
 namespace ZeroTier {
 
+const uint64_t Topology::s_pathHashSalt = Utils::getSecureRandomU64();
+
 // Sorts roots so as to put the lowest latency alive root first.
 struct _RootSortComparisonOperator
 {
@@ -89,8 +91,8 @@ void Topology::getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const
 	allPeers.clear();
 	allPeers.reserve(_peers.size());
 	Hashtable< Address,SharedPtr<Peer> >::Iterator i(*(const_cast<Hashtable< Address,SharedPtr<Peer> > *>(&_peers)));
-	Address *a = (Address *)0;
-	SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+	Address *a = nullptr;
+	SharedPtr<Peer> *p = nullptr;
 	while (i.next(a,p))
 		allPeers.push_back(*p);
 }
@@ -189,8 +191,8 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
 	{
 		RWMutex::Lock l1(_peers_l);
 		Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
-		Address *a = (Address *)0;
-		SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+		Address *a = nullptr;
+		SharedPtr<Peer> *p = nullptr;
 		while (i.next(a,p)) {
 			if ( (!(*p)->alive(now)) && (_roots.count((*p)->identity()) == 0) ) {
 				(*p)->save(tPtr);
@@ -200,9 +202,9 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
 	}
 	{
 		RWMutex::Lock l1(_paths_l);
-		Hashtable< Path::HashKey,SharedPtr<Path> >::Iterator i(_paths);
-		Path::HashKey *k = (Path::HashKey *)0;
-		SharedPtr<Path> *p = (SharedPtr<Path> *)0;
+		Hashtable< uint64_t,SharedPtr<Path> >::Iterator i(_paths);
+		uint64_t *k = nullptr;
+		SharedPtr<Path> *p = nullptr;
 		while (i.next(k,p)) {
 			if (p->references() <= 1)
 				_paths.erase(*k);
@@ -214,8 +216,8 @@ void Topology::saveAll(void *tPtr)
 {
 	RWMutex::RLock l(_peers_l);
 	Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
-	Address *a = (Address *)0;
-	SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+	Address *a = nullptr;
+	SharedPtr<Peer> *p = nullptr;
 	while (i.next(a,p)) {
 		if ( (!(*p)->alive(RR->node->now())) && (_roots.count((*p)->identity()) == 0) ) {
 			(*p)->save((void *)0);

+ 29 - 4
node/Topology.hpp

@@ -92,7 +92,7 @@ public:
 	 */
 	ZT_ALWAYS_INLINE SharedPtr<Path> getPath(const int64_t l,const InetAddress &r)
 	{
-		const Path::HashKey k(l,r);
+		const uint64_t k = _pathHash(l,r);
 
 		_paths_l.rlock();
 		SharedPtr<Path> p(_paths[k]);
@@ -205,8 +205,8 @@ public:
 	ZT_ALWAYS_INLINE void eachPath(F f) const
 	{
 		RWMutex::RLock l(_paths_l);
-		Hashtable< Path::HashKey,SharedPtr<Path> >::Iterator i(const_cast<Topology *>(this)->_paths);
-		Path::HashKey *k = nullptr;
+		Hashtable< uint64_t,SharedPtr<Path> >::Iterator i(const_cast<Topology *>(this)->_paths);
+		uint64_t *k = nullptr;
 		SharedPtr<Path> *p = nullptr;
 		while (i.next(k,p)) {
 			f(*((const SharedPtr<Path> *)p));
@@ -310,6 +310,31 @@ public:
 private:
 	void _loadCached(void *tPtr,const Address &zta,SharedPtr<Peer> &peer);
 
+	// This is a secure random integer created at startup to salt the calculation of path hash map keys
+	static const uint64_t s_pathHashSalt;
+
+	// Get a hash key for looking up paths by their local port and destination address
+	ZT_ALWAYS_INLINE uint64_t _pathHash(int64_t l,const InetAddress &r) const
+	{
+		if (r.ss_family == AF_INET) {
+			return Utils::hash64(s_pathHashSalt ^ (uint64_t)(reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr)) + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port) + (uint64_t)l;
+		} else if (r.ss_family == AF_INET6) {
+#ifdef ZT_NO_UNALIGNED_ACCESS
+			uint64_t h = s_pathHashSalt;
+			for(int i=0;i<16;++i) {
+				h += (uint64_t)((reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[i]);
+				h += (h << 10U);
+				h ^= (h >> 6U);
+			}
+#else
+			uint64_t h = Utils::hash64(s_pathHashSalt ^ (reinterpret_cast<const uint64_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[0] + reinterpret_cast<const uint64_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[1]));
+#endif
+			return h + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port) + (uint64_t)l;
+		} else {
+			return Utils::hashString(reinterpret_cast<const void *>(&r),sizeof(InetAddress)) + (uint64_t)l;
+		}
+	}
+
 	const RuntimeEnvironment *const RR;
 	const Identity _myIdentity;
 
@@ -320,7 +345,7 @@ private:
 	unsigned int _numConfiguredPhysicalPaths;
 
 	Hashtable< Address,SharedPtr<Peer> > _peers;
-	Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
+	Hashtable< uint64_t,SharedPtr<Path> > _paths;
 	std::set< Identity > _roots; // locked by _peers_l
 	std::vector< SharedPtr<Peer> > _rootPeers; // locked by _peers_l
 };

+ 11 - 11
node/Utils.cpp

@@ -321,6 +321,13 @@ void getSecureRandom(void *buf,unsigned int bytes)
 	}
 }
 
+uint64_t getSecureRandomU64()
+{
+	uint64_t tmp = 0;
+	getSecureRandom(&tmp,sizeof(tmp));
+	return tmp;
+}
+
 int b32e(const uint8_t *data,int length,char *result,int bufSize)
 {
   if (length < 0 || length > (1 << 28)) {
@@ -397,22 +404,15 @@ int b32d(const char *encoded,uint8_t *result,int bufSize)
   return count;
 }
 
-static uint64_t _secureRandom64()
-{
-	uint64_t tmp = 0;
-	getSecureRandom(&tmp,sizeof(tmp));
-	return tmp;
-}
-
 #define ROL64(x,k) (((x) << (k)) | ((x) >> (64 - (k))))
 uint64_t random()
 {
 	// https://en.wikipedia.org/wiki/Xorshift#xoshiro256**
 	static Mutex l;
-	static uint64_t s0 = _secureRandom64();
-	static uint64_t s1 = _secureRandom64();
-	static uint64_t s2 = _secureRandom64();
-	static uint64_t s3 = _secureRandom64();
+	static uint64_t s0 = getSecureRandomU64();
+	static uint64_t s1 = getSecureRandomU64();
+	static uint64_t s2 = getSecureRandomU64();
+	static uint64_t s3 = getSecureRandomU64();
 
 	l.lock();
 	const uint64_t result = ROL64(s1 * 5,7) * 9;

+ 40 - 0
node/Utils.hpp

@@ -139,6 +139,11 @@ unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen
  */
 void getSecureRandom(void *buf,unsigned int bytes);
 
+/**
+ * @return Secure random 64-bit integer
+ */
+uint64_t getSecureRandomU64();
+
 /**
  * Encode string to base32
  *
@@ -178,6 +183,41 @@ uint64_t random();
  */
 bool scopy(char *dest,unsigned int len,const char *src);
 
+/**
+ * Mix bits in a 64-bit integer
+ *
+ * https://nullprogram.com/blog/2018/07/31/
+ *
+ * @param x Integer to mix
+ * @return Hashed value
+ */
+static ZT_ALWAYS_INLINE uint64_t hash64(uint64_t x)
+{
+	x ^= x >> 30U;
+	x *= 0xbf58476d1ce4e5b9ULL;
+	x ^= x >> 27U;
+	x *= 0x94d049bb133111ebULL;
+	x ^= x >> 31U;
+	return x;
+}
+
+/**
+ * @param b Buffer to check
+ * @param l Length of buffer
+ * @return True if buffer is all zero
+ */
+static ZT_ALWAYS_INLINE bool allZero(const void *const b,const unsigned int l)
+{
+	const uint8_t *x = reinterpret_cast<const uint8_t *>(b);
+	const uint8_t *const y = x + l;
+	while (x != y) {
+		if (*x != 0)
+			return false;
+		++x;
+	}
+	return true;
+}
+
 /**
  * Wrapper around reentrant strtok functions, which differ in name by platform
  *

+ 4 - 4
osdep/Arp.cpp

@@ -57,11 +57,11 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
 			_ArpEntry *targetEntry = _cache.get(reinterpret_cast<const uint32_t *>(arp)[6]);
 			if ((targetEntry)&&(targetEntry->local)) {
 				memcpy(response,ARP_RESPONSE_HEADER,8);
-				targetEntry->mac.copyTo(reinterpret_cast<uint8_t *>(response) + 8,6);
+				targetEntry->mac.copyTo(reinterpret_cast<uint8_t *>(response) + 8);
 				memcpy(reinterpret_cast<uint8_t *>(response) + 14,reinterpret_cast<const uint8_t *>(arp) + 24,4);
 				memcpy(reinterpret_cast<uint8_t *>(response) + 18,reinterpret_cast<const uint8_t *>(arp) + 8,10);
 				responseLen = 28;
-				responseDest.setTo(reinterpret_cast<const uint8_t *>(arp) + 8,6);
+				responseDest.setTo(reinterpret_cast<const uint8_t *>(arp) + 8);
 			}
 		} else if (!memcmp(arp,ARP_RESPONSE_HEADER,8)) {
 			// Learn cache entries for remote IPs from relevant ARP replies
@@ -70,7 +70,7 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
 			_ArpEntry *queryEntry = _cache.get(responseIp);
 			if ((queryEntry)&&(!queryEntry->local)&&((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) {
 				queryEntry->lastResponseReceived = now;
-				queryEntry->mac.setTo(reinterpret_cast<const uint8_t *>(arp) + 8,6);
+				queryEntry->mac.setTo(reinterpret_cast<const uint8_t *>(arp) + 8);
 				ip = responseIp;
 			}
 		}
@@ -102,7 +102,7 @@ MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *quer
 
 		uint8_t *q = reinterpret_cast<uint8_t *>(query);
 		memcpy(q,ARP_REQUEST_HEADER,8); q += 8; // ARP request header information, always the same
-		localMac.copyTo(q,6); q += 6; // sending host MAC address
+		localMac.copyTo(q); q += 6; // sending host MAC address
         memcpy(q,&localIp,4); q += 4; // sending host IP (IP already in big-endian byte order)
 		memset(q,0,6); q += 6; // sending zeros for target MAC address as thats what we want to find
 		memcpy(q,&targetIp,4); // target IP address for resolution (IP already in big-endian byte order)

+ 3 - 4
osdep/ManagedRoute.hpp

@@ -14,9 +14,6 @@
 #ifndef ZT_MANAGEDROUTE_HPP
 #define ZT_MANAGEDROUTE_HPP
 
-#include <stdlib.h>
-#include <string.h>
-
 #include "../node/InetAddress.hpp"
 #include "../node/Utils.hpp"
 #include "../node/SharedPtr.hpp"
@@ -25,6 +22,8 @@
 #include <stdexcept>
 #include <vector>
 #include <map>
+#include <cstdlib>
+#include <cstring>
 
 namespace ZeroTier {
 
@@ -84,7 +83,7 @@ private:
 	char _device[128];
 	char _systemDevice[128]; // for route overrides
 
-	AtomicCounter __refCount;
+	AtomicCounter<int> __refCount;
 };
 
 } // namespace ZeroTier

Some files were not shown because too many files changed in this diff