Browse Source

Some optimization and raw memory access cleanup.

Adam Ierymenko 5 years ago
parent
commit
1f2e94a51d

+ 25 - 9
node/Buf.hpp

@@ -165,7 +165,7 @@ public:
 					r.e = 0;
 					r.e = 0;
 					break;
 					break;
 				}
 				}
-				memcpy(r.b->unsafeData + r.e,s->b->unsafeData + s->s,l);
+				Utils::copy(r.b->unsafeData + r.e,s->b->unsafeData + s->s,l);
 				s->b.zero(); // let go of buffer in vector as soon as possible
 				s->b.zero(); // let go of buffer in vector as soon as possible
 				r.e += l;
 				r.e += l;
 			}
 			}
@@ -182,14 +182,24 @@ public:
 	/**
 	/**
 	 * Create a new buffer and copy data into it
 	 * Create a new buffer and copy data into it
 	 */
 	 */
-	ZT_INLINE Buf(const void *const data,const unsigned int len) noexcept : __nextInPool(0),__refCount(0) { memcpy(unsafeData,data,len); }
+	ZT_INLINE Buf(const void *const data,const unsigned int len) noexcept :
+		__nextInPool(0),
+		__refCount(0)
+	{
+		Utils::copy(unsafeData,data,len);
+	}
 
 
-	ZT_INLINE Buf(const Buf &b2) noexcept : __nextInPool(0),__refCount(0) { memcpy(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE); }
+	ZT_INLINE Buf(const Buf &b2) noexcept :
+		__nextInPool(0),
+		__refCount(0)
+	{
+		Utils::copy<ZT_BUF_MEM_SIZE>(unsafeData,b2.unsafeData);
+	}
 
 
 	ZT_INLINE Buf &operator=(const Buf &b2) noexcept
 	ZT_INLINE Buf &operator=(const Buf &b2) noexcept
 	{
 	{
 		if (this != &b2)
 		if (this != &b2)
-			memcpy(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE);
+			Utils::copy<ZT_BUF_MEM_SIZE>(unsafeData,b2.unsafeData);
 		return *this;
 		return *this;
 	}
 	}
 
 
@@ -219,12 +229,18 @@ public:
 	/**
 	/**
 	 * Set all memory to zero
 	 * Set all memory to zero
 	 */
 	 */
-	ZT_INLINE void clear() noexcept { memset(unsafeData,0,ZT_BUF_MEM_SIZE); }
+	ZT_INLINE void clear() noexcept
+	{
+		Utils::zero<ZT_BUF_MEM_SIZE>(unsafeData);
+	}
 
 
 	/**
 	/**
 	 * Zero security critical data using Utils::burn() to ensure it's never optimized out.
 	 * Zero security critical data using Utils::burn() to ensure it's never optimized out.
 	 */
 	 */
-	ZT_INLINE void burn() noexcept { Utils::burn(unsafeData,ZT_BUF_MEM_SIZE); }
+	ZT_INLINE void burn() noexcept
+	{
+		Utils::burn(unsafeData,ZT_BUF_MEM_SIZE);
+	}
 
 
 	/**
 	/**
 	 * Read a byte
 	 * Read a byte
@@ -347,7 +363,7 @@ public:
 		const int sii = ii;
 		const int sii = ii;
 		while (ii < ZT_BUF_MEM_SIZE) {
 		while (ii < ZT_BUF_MEM_SIZE) {
 			if (unsafeData[ii++] == 0) {
 			if (unsafeData[ii++] == 0) {
-				memcpy(buf,s,ii - sii);
+				Utils::copy(buf,s,ii - sii);
 				return buf;
 				return buf;
 			}
 			}
 		}
 		}
@@ -391,7 +407,7 @@ public:
 	ZT_INLINE uint8_t *rB(int &ii,void *const bytes,const unsigned int len) const noexcept
 	ZT_INLINE uint8_t *rB(int &ii,void *const bytes,const unsigned int len) const noexcept
 	{
 	{
 		if ((ii += (int)len) <= ZT_BUF_MEM_SIZE) {
 		if ((ii += (int)len) <= ZT_BUF_MEM_SIZE) {
-			memcpy(bytes,unsafeData + ii,len);
+			Utils::copy(bytes,unsafeData + ii,len);
 			return reinterpret_cast<uint8_t *>(bytes);
 			return reinterpret_cast<uint8_t *>(bytes);
 		}
 		}
 		return nullptr;
 		return nullptr;
@@ -617,7 +633,7 @@ public:
 	{
 	{
 		const int s = ii;
 		const int s = ii;
 		if ((ii += (int)len) <= ZT_BUF_MEM_SIZE)
 		if ((ii += (int)len) <= ZT_BUF_MEM_SIZE)
-			memcpy(unsafeData + s,bytes,len);
+			Utils::copy(unsafeData + s,bytes,len);
 	}
 	}
 
 
 	/**
 	/**

File diff suppressed because it is too large
+ 595 - 592
node/C25519.cpp


+ 4 - 4
node/Capability.cpp

@@ -110,7 +110,7 @@ int Capability::unmarshal(const uint8_t *data,int len) noexcept
 		_custody[i].signatureLength = sl;
 		_custody[i].signatureLength = sl;
 		if ((sl > sizeof(_custody[i].signature))||((p + (int)sl) > len))
 		if ((sl > sizeof(_custody[i].signature))||((p + (int)sl) > len))
 			return -1;
 			return -1;
-		memcpy(_custody[i].signature,data + p,sl); p += (int)sl;
+		Utils::copy(_custody[i].signature,data + p,sl); p += (int)sl;
 	}
 	}
 
 
 	if ((p + 2) > len)
 	if ((p + 2) > len)
@@ -281,18 +281,18 @@ int Capability::unmarshalVirtualNetworkRules(const uint8_t *const data,const int
 			case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
 			case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
 			case ZT_NETWORK_RULE_MATCH_MAC_DEST:
 			case ZT_NETWORK_RULE_MATCH_MAC_DEST:
 				if ((p + 6) > len) return -1;
 				if ((p + 6) > len) return -1;
-				memcpy(rules[ruleCount].v.mac,data + p,6); p += 6;
+				Utils::copy<6>(rules[ruleCount].v.mac,data + p); p += 6;
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
 			case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
 			case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
 			case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
 				if ((p + 5) > len) return -1;
 				if ((p + 5) > len) return -1;
-				memcpy(&(rules[ruleCount].v.ipv4.ip),data + p,4); p += 4;
+				Utils::copy<4>(&(rules[ruleCount].v.ipv4.ip),data + p); p += 4;
 				rules[ruleCount].v.ipv4.mask = data[p++];
 				rules[ruleCount].v.ipv4.mask = data[p++];
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
 			case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
 			case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
 			case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
 				if ((p + 17) > len) return -1;
 				if ((p + 17) > len) return -1;
-				memcpy(rules[ruleCount].v.ipv6.ip,data + p,16); p += 16;
+				Utils::copy<16>(rules[ruleCount].v.ipv6.ip,data + p); p += 16;
 				rules[ruleCount].v.ipv6.mask = data[p++];
 				rules[ruleCount].v.ipv6.mask = data[p++];
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IP_TOS:
 			case ZT_NETWORK_RULE_MATCH_IP_TOS:

+ 1 - 1
node/Capability.hpp

@@ -82,7 +82,7 @@ public:
 		_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES)
 		_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES)
 	{
 	{
 		if (_ruleCount > 0)
 		if (_ruleCount > 0)
-			memcpy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount);
+			Utils::copy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount);
 	}
 	}
 
 
 	/**
 	/**

+ 7 - 7
node/CertificateOfMembership.cpp

@@ -57,7 +57,7 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) c
 		}
 		}
 	}
 	}
 
 
-	// them <> us
+	// them <> us (we need a second pass in case they have qualifiers we don't or vice versa)
 	for(FCV<_Qualifier,ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(other._additionalQualifiers.begin());i != other._additionalQualifiers.end();++i) {
 	for(FCV<_Qualifier,ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(other._additionalQualifiers.begin());i != other._additionalQualifiers.end();++i) {
 		if (i->delta != 0xffffffffffffffffULL) {
 		if (i->delta != 0xffffffffffffffffULL) {
 			const uint64_t *v2 = nullptr;
 			const uint64_t *v2 = nullptr;
@@ -113,7 +113,7 @@ int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MAR
 	if (v2) {
 	if (v2) {
 		// V2 marshal format will have three tuples followed by the fingerprint hash.
 		// V2 marshal format will have three tuples followed by the fingerprint hash.
 		Utils::storeBigEndian<uint16_t>(data + 1,3);
 		Utils::storeBigEndian<uint16_t>(data + 1,3);
-		memcpy(data + p,_issuedTo.hash(),48);
+		Utils::copy<48>(data + p,_issuedTo.hash());
 		p += 48;
 		p += 48;
 	} else {
 	} else {
 		// V1 marshal format must shove everything into tuples, resulting in nine.
 		// V1 marshal format must shove everything into tuples, resulting in nine.
@@ -130,11 +130,11 @@ int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MAR
 	if (v2) {
 	if (v2) {
 		// V2 marshal format prefixes signatures with a 16-bit length to support future signature types.
 		// V2 marshal format prefixes signatures with a 16-bit length to support future signature types.
 		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
 		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
-		memcpy(data + p,_signature,_signatureLength);
+		Utils::copy(data + p,_signature,_signatureLength);
 		p += (int)_signatureLength;
 		p += (int)_signatureLength;
 	} else {
 	} else {
 		// V1 only supports 96-byte signature fields.
 		// V1 only supports 96-byte signature fields.
-		memcpy(data + p,_signature,96);
+		Utils::copy<96>(data + p,_signature);
 		p += 96;
 		p += 96;
 	}
 	}
 
 
@@ -204,19 +204,19 @@ int CertificateOfMembership::unmarshal(const uint8_t *data,int len) noexcept
 		if ((p + 96) > len)
 		if ((p + 96) > len)
 			return -1;
 			return -1;
 		_signatureLength = 96;
 		_signatureLength = 96;
-		memcpy(_signature,data + p,96);
+		Utils::copy<96>(_signature,data + p);
 		return p + 96;
 		return p + 96;
 	} else if (data[0] == 2) {
 	} else if (data[0] == 2) {
 		if ((p + 48) > len)
 		if ((p + 48) > len)
 			return -1;
 			return -1;
-		memcpy(_issuedTo.apiFingerprint()->hash,data + p,48);
+		Utils::copy<48>(_issuedTo.apiFingerprint()->hash,data + p);
 		p += 48;
 		p += 48;
 		if ((p + 2) > len)
 		if ((p + 2) > len)
 			return -1;
 			return -1;
 		_signatureLength = Utils::loadBigEndian<uint16_t>(data + p);
 		_signatureLength = Utils::loadBigEndian<uint16_t>(data + p);
 		if ((_signatureLength > (unsigned int)sizeof(_signature))||((p + (int)_signatureLength) > len))
 		if ((_signatureLength > (unsigned int)sizeof(_signature))||((p + (int)_signatureLength) > len))
 			return -1;
 			return -1;
-		memcpy(_signature,data + p,_signatureLength);
+		Utils::copy(_signature,data + p,_signatureLength);
 		return p + (int)_signatureLength;
 		return p + (int)_signatureLength;
 	}
 	}
 
 

+ 9 - 7
node/CertificateOfOwnership.cpp

@@ -17,21 +17,23 @@ namespace ZeroTier {
 
 
 void CertificateOfOwnership::addThing(const InetAddress &ip)
 void CertificateOfOwnership::addThing(const InetAddress &ip)
 {
 {
-	if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
+	if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS)
+		return;
 	if (ip.family() == AF_INET) {
 	if (ip.family() == AF_INET) {
 		_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
 		_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
-		memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
+		Utils::copy<4>(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr));
 		++_thingCount;
 		++_thingCount;
 	} else if (ip.family() == AF_INET6) {
 	} else if (ip.family() == AF_INET6) {
 		_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
 		_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
-		memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
+		Utils::copy<16>(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr);
 		++_thingCount;
 		++_thingCount;
 	}
 	}
 }
 }
 
 
 void CertificateOfOwnership::addThing(const MAC &mac)
 void CertificateOfOwnership::addThing(const MAC &mac)
 {
 {
-	if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
+	if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS)
+		return;
 	_thingTypes[_thingCount] = THING_MAC_ADDRESS;
 	_thingTypes[_thingCount] = THING_MAC_ADDRESS;
 	mac.copyTo(_thingValues[_thingCount]);
 	mac.copyTo(_thingValues[_thingCount]);
 	++_thingCount;
 	++_thingCount;
@@ -63,7 +65,7 @@ int CertificateOfOwnership::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSH
 	p += 30;
 	p += 30;
 	for(unsigned int i=0,j=_thingCount;i<j;++i) {
 	for(unsigned int i=0,j=_thingCount;i<j;++i) {
 		data[p++] = _thingTypes[i];
 		data[p++] = _thingTypes[i];
-		memcpy(data + p,_thingValues[i],ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
+		Utils::copy<ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE>(data + p,_thingValues[i]);
 		p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
 		p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
 	}
 	}
 	_issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
 	_issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
@@ -71,7 +73,7 @@ int CertificateOfOwnership::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSH
 	if (!forSign) {
 	if (!forSign) {
 		data[p++] = 1;
 		data[p++] = 1;
 		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
 		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
-		memcpy(data + p,_signature,_signatureLength); p += (int)_signatureLength;
+		Utils::copy(data + p,_signature,_signatureLength); p += (int)_signatureLength;
 	}
 	}
 	data[p++] = 0;
 	data[p++] = 0;
 	data[p++] = 0;
 	data[p++] = 0;
@@ -100,7 +102,7 @@ int CertificateOfOwnership::unmarshal(const uint8_t *data,int len) noexcept
 		if ((p + 1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) > len)
 		if ((p + 1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) > len)
 			return -1;
 			return -1;
 		_thingTypes[i] = data[p++];
 		_thingTypes[i] = data[p++];
-		memcpy(_thingValues[i],data + p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
+		Utils::copy<ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE>(_thingValues[i],data + p);
 		p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
 		p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
 	}
 	}
 
 

+ 1 - 1
node/CertificateOfOwnership.hpp

@@ -64,7 +64,7 @@ public:
 
 
 	ZT_INLINE CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id) noexcept
 	ZT_INLINE CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id) noexcept
 	{
 	{
-		memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
+		memoryZero(this);
 		_networkId = nwid;
 		_networkId = nwid;
 		_ts = ts;
 		_ts = ts;
 		_id = id;
 		_id = id;

+ 1 - 1
node/Defragmenter.hpp

@@ -263,7 +263,7 @@ public:
 				e->via.zero();
 				e->via.zero();
 			}
 			}
 
 
-			// Slices are TriviallyCopyable and so may be memcpy'd from e->message to
+			// Slices are TriviallyCopyable and so may be raw copied from e->message to
 			// the result parameter. This is fast.
 			// the result parameter. This is fast.
 			e->message.unsafeMoveTo(message);
 			e->message.unsafeMoveTo(message);
 			e->lastUsed = -1; // mark as "done" and force GC to collect
 			e->lastUsed = -1; // mark as "done" and force GC to collect

+ 1 - 1
node/Dictionary.cpp

@@ -134,7 +134,7 @@ uint64_t Dictionary::getUI(const char *k,uint64_t dfl) const
 	if (!e.empty()) {
 	if (!e.empty()) {
 		if (e.back() != 0) {
 		if (e.back() != 0) {
 			const unsigned long sl = e.size();
 			const unsigned long sl = e.size();
-			memcpy(tmp,e.data(),(sl > 17) ? 17 : sl);
+			Utils::copy(tmp,e.data(),(sl > 17) ? 17 : sl);
 			tmp[17] = 0;
 			tmp[17] = 0;
 			return Utils::unhex((const char *)tmp);
 			return Utils::unhex((const char *)tmp);
 		}
 		}

+ 2 - 2
node/Endpoint.cpp

@@ -82,7 +82,7 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
 			data[9] = (uint8_t)(_v.zt.address >> 16U);
 			data[9] = (uint8_t)(_v.zt.address >> 16U);
 			data[10] = (uint8_t)(_v.zt.address >> 8U);
 			data[10] = (uint8_t)(_v.zt.address >> 8U);
 			data[11] = (uint8_t)_v.zt.address;
 			data[11] = (uint8_t)_v.zt.address;
-			memcpy(data + 12,_v.zt.hash,ZT_IDENTITY_HASH_SIZE);
+			Utils::copy<ZT_IDENTITY_HASH_SIZE>(data + 12,_v.zt.hash);
 			return ZT_IDENTITY_HASH_SIZE + 12;
 			return ZT_IDENTITY_HASH_SIZE + 12;
 		case TYPE_DNSNAME:
 		case TYPE_DNSNAME:
 			p = 7;
 			p = 7;
@@ -147,7 +147,7 @@ int Endpoint::unmarshal(const uint8_t *restrict data,const int len) noexcept
 		  _v.zt.address |= ((uint64_t)data[9]) << 16U;
 		  _v.zt.address |= ((uint64_t)data[9]) << 16U;
 		  _v.zt.address |= ((uint64_t)data[10]) << 8U;
 		  _v.zt.address |= ((uint64_t)data[10]) << 8U;
 		  _v.zt.address |= (uint64_t)data[11];
 		  _v.zt.address |= (uint64_t)data[11];
-		  memcpy(_v.zt.hash,data + 12,ZT_IDENTITY_HASH_SIZE);
+		  Utils::copy<ZT_IDENTITY_HASH_SIZE>(_v.zt.hash,data + 12);
 		  return 60;
 		  return 60;
 	  case TYPE_DNSNAME:
 	  case TYPE_DNSNAME:
 		  if (len < 10)
 		  if (len < 10)

+ 1 - 1
node/Endpoint.hpp

@@ -76,7 +76,7 @@ public:
 		_t(TYPE_ZEROTIER)
 		_t(TYPE_ZEROTIER)
 	{
 	{
 		_v.zt.address = zt.toInt();
 		_v.zt.address = zt.toInt();
-		memcpy(_v.zt.hash,identityHash,ZT_IDENTITY_HASH_SIZE);
+		Utils::copy<ZT_IDENTITY_HASH_SIZE>(_v.zt.hash,identityHash);
 	}
 	}
 
 
 	explicit ZT_INLINE Endpoint(const char *name,const int port) noexcept :
 	explicit ZT_INLINE Endpoint(const char *name,const int port) noexcept :

+ 2 - 10
node/FCV.hpp

@@ -87,11 +87,6 @@ public:
 	/**
 	/**
 	 * This does a straight copy of one vector's data to another
 	 * This does a straight copy of one vector's data to another
 	 *
 	 *
-	 * If the other vector is larger than this one's capacity the data is
-	 * silently truncated. This is unsafe in that it does not call any
-	 * constructors or destructors and copies data with memcpy, so it can
-	 * only be used with primitive types or TriviallyCopyable objects.
-	 *
 	 * @tparam C2 Inferred capacity of other vector
 	 * @tparam C2 Inferred capacity of other vector
 	 * @param v Other vector to copy to this one
 	 * @param v Other vector to copy to this one
 	 */
 	 */
@@ -99,20 +94,17 @@ public:
 	ZT_INLINE void unsafeAssign(const FCV<T,C2> &v) noexcept
 	ZT_INLINE void unsafeAssign(const FCV<T,C2> &v) noexcept
 	{
 	{
 		_s = ((C2 > C)&&(v._s > C)) ? C : v._s;
 		_s = ((C2 > C)&&(v._s > C)) ? C : v._s;
-		memcpy(_m,v._m,_s * sizeof(T));
+		Utils::copy(_m,v._m,_s * sizeof(T));
 	}
 	}
 
 
 	/**
 	/**
 	 * Move contents from this vector to another and clear this vector
 	 * Move contents from this vector to another and clear this vector
 	 *
 	 *
-	 * This uses a straight memcpy and so is only safe for primitive types or
-	 * types that are TriviallyCopyable.
-	 *
 	 * @param v Target vector
 	 * @param v Target vector
 	 */
 	 */
 	ZT_INLINE void unsafeMoveTo(FCV &v) noexcept
 	ZT_INLINE void unsafeMoveTo(FCV &v) noexcept
 	{
 	{
-		memcpy(v._m,_m,(v._s = _s) * sizeof(T));
+		Utils::copy(v._m,_m,(v._s = _s) * sizeof(T));
 		_s = 0;
 		_s = 0;
 	}
 	}
 
 

+ 2 - 2
node/Fingerprint.hpp

@@ -62,7 +62,7 @@ public:
 	{
 	{
 		uint8_t tmp[48 + 5];
 		uint8_t tmp[48 + 5];
 		address().copyTo(tmp);
 		address().copyTo(tmp);
-		memcpy(tmp + 5,_fp.hash,48);
+		Utils::copy<48>(tmp + 5,_fp.hash);
 		Utils::b32e(tmp,sizeof(tmp),s,ZT_FINGERPRINT_STRING_BUFFER_LENGTH);
 		Utils::b32e(tmp,sizeof(tmp),s,ZT_FINGERPRINT_STRING_BUFFER_LENGTH);
 		s[ZT_FINGERPRINT_STRING_BUFFER_LENGTH-1] = 0; // sanity check, ensure always zero terminated
 		s[ZT_FINGERPRINT_STRING_BUFFER_LENGTH-1] = 0; // sanity check, ensure always zero terminated
 	}
 	}
@@ -79,7 +79,7 @@ public:
 		if (Utils::b32d(s,tmp,sizeof(tmp)) != sizeof(tmp))
 		if (Utils::b32d(s,tmp,sizeof(tmp)) != sizeof(tmp))
 			return false;
 			return false;
 		_fp.address = Address(tmp).toInt();
 		_fp.address = Address(tmp).toInt();
-		memcpy(_fp.hash,tmp + 5,48);
+		Utils::copy<48>(_fp.hash,tmp + 5);
 		return true;
 		return true;
 	}
 	}
 
 

+ 3 - 2
node/Hashtable.hpp

@@ -15,6 +15,7 @@
 #define ZT_HASHTABLE_HPP
 #define ZT_HASHTABLE_HPP
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
+#include "Utils.hpp"
 
 
 #include <cstdlib>
 #include <cstdlib>
 #include <cstring>
 #include <cstring>
@@ -95,14 +96,14 @@ public:
 	/**
 	/**
 	 * @param bc Initial capacity in buckets (default: 32, must be nonzero)
 	 * @param bc Initial capacity in buckets (default: 32, must be nonzero)
 	 */
 	 */
-	explicit ZT_INLINE Hashtable(unsigned long bc = 32) :
+	explicit ZT_INLINE Hashtable(unsigned int bc = 32) :
 		_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))),
 		_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))),
 		_bc(bc),
 		_bc(bc),
 		_s(0)
 		_s(0)
 	{
 	{
 		if (!_t)
 		if (!_t)
 			throw std::bad_alloc();
 			throw std::bad_alloc();
-		memset(_t,0,sizeof(_Bucket *) * bc);
+		Utils::zero(_t,sizeof(uintptr_t) * bc);
 	}
 	}
 
 
 	ZT_INLINE Hashtable(const Hashtable<K,V> &ht) :
 	ZT_INLINE Hashtable(const Hashtable<K,V> &ht) :

+ 13 - 13
node/Identity.cpp

@@ -40,7 +40,7 @@ void identityV0ProofOfWorkFrankenhash(const void *const publicKey,unsigned int p
 	// Initialize genmem[] using Salsa20 in a CBC-like configuration since
 	// Initialize genmem[] using Salsa20 in a CBC-like configuration since
 	// ordinary Salsa20 is randomly seek-able. This is good for a cipher
 	// ordinary Salsa20 is randomly seek-able. This is good for a cipher
 	// but is not what we want for sequential memory-hardness.
 	// but is not what we want for sequential memory-hardness.
-	memset(genmem,0,ZT_V0_IDENTITY_GEN_MEMORY);
+	Utils::zero<ZT_V0_IDENTITY_GEN_MEMORY>(genmem);
 	Salsa20 s20(digest,(char *)digest + 32);
 	Salsa20 s20(digest,(char *)digest + 32);
 	s20.crypt20((char *)genmem,(char *)genmem,64);
 	s20.crypt20((char *)genmem,(char *)genmem,64);
 	for(unsigned long i=64;i<ZT_V0_IDENTITY_GEN_MEMORY;i+=64) {
 	for(unsigned long i=64;i<ZT_V0_IDENTITY_GEN_MEMORY;i+=64) {
@@ -261,7 +261,7 @@ void Identity::hashWithPrivate(uint8_t h[ZT_IDENTITY_HASH_SIZE]) const
 		}
 		}
 		return;
 		return;
 	}
 	}
-	memset(h,0,48);
+	Utils::zero<48>(h);
 }
 }
 
 
 unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
 unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
@@ -319,7 +319,7 @@ bool Identity::agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH])
 				// C25519 portion of a type 1 P-384 key.
 				// C25519 portion of a type 1 P-384 key.
 				C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
 				C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
 				SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
 				SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
-				memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
+				Utils::copy<ZT_PEER_SECRET_KEY_LENGTH>(key,h);
 				return true;
 				return true;
 			}
 			}
 
 
@@ -334,13 +334,13 @@ bool Identity::agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH])
 				C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
 				C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
 				ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN);
 				ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN);
 				SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
 				SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
-				memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
+				Utils::copy<ZT_PEER_SECRET_KEY_LENGTH>(key,h);
 				return true;
 				return true;
 			} else if (id._type == C25519) {
 			} else if (id._type == C25519) {
 				// If the other identity is a C25519 identity we can agree using only that type.
 				// If the other identity is a C25519 identity we can agree using only that type.
 				C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
 				C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
 				SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
 				SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
-				memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
+				Utils::copy<ZT_PEER_SECRET_KEY_LENGTH>(key,h);
 				return true;
 				return true;
 			}
 			}
 
 
@@ -502,10 +502,10 @@ int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool incl
 	switch(_type) {
 	switch(_type) {
 		case C25519:
 		case C25519:
 			data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
 			data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
-			memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
+			Utils::copy<ZT_C25519_PUBLIC_KEY_LEN>(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519);
 			if ((includePrivate)&&(_hasPrivate)) {
 			if ((includePrivate)&&(_hasPrivate)) {
 				data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = ZT_C25519_PRIVATE_KEY_LEN;
 				data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = ZT_C25519_PRIVATE_KEY_LEN;
-				memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
+				Utils::copy<ZT_C25519_PRIVATE_KEY_LEN>(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,_priv.c25519);
 				return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN;
 				return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN;
 			} else {
 			} else {
 				data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0;
 				data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0;
@@ -514,10 +514,10 @@ int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool incl
 
 
 		case P384:
 		case P384:
 			data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
 			data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
-			memcpy(data + ZT_ADDRESS_LENGTH + 1,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
+			Utils::copy<ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1,&_pub);
 			if ((includePrivate)&&(_hasPrivate)) {
 			if ((includePrivate)&&(_hasPrivate)) {
 				data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
 				data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
-				memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
+				Utils::copy<ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv);
 				return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
 				return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
 			} else {
 			} else {
 				data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
 				data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
@@ -544,7 +544,7 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
 			if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1))
 			if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1))
 				return -1;
 				return -1;
 
 
-			memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN);
+			Utils::copy<ZT_C25519_PUBLIC_KEY_LEN>(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1);
 			_computeHash();
 			_computeHash();
 
 
 			privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
 			privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
@@ -552,7 +552,7 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
 				if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN))
 				if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN))
 					return -1;
 					return -1;
 				_hasPrivate = true;
 				_hasPrivate = true;
-				memcpy(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,ZT_C25519_PRIVATE_KEY_LEN);
+				Utils::copy<ZT_C25519_PRIVATE_KEY_LEN>(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
 				return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN;
 				return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN;
 			} else if (privlen == 0) {
 			} else if (privlen == 0) {
 				_hasPrivate = false;
 				_hasPrivate = false;
@@ -564,7 +564,7 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
 			if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1))
 			if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1))
 				return -1;
 				return -1;
 
 
-			memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
+			Utils::copy<ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE>(&_pub,data + ZT_ADDRESS_LENGTH + 1);
 			_computeHash(); // this sets the address for P384
 			_computeHash(); // this sets the address for P384
 			if (_address != Address(_fp.hash())) // this sanity check is possible with V1 identities
 			if (_address != Address(_fp.hash())) // this sanity check is possible with V1 identities
 				return -1;
 				return -1;
@@ -574,7 +574,7 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
 				if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE))
 				if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE))
 					return -1;
 					return -1;
 				_hasPrivate = true;
 				_hasPrivate = true;
-				memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
+				Utils::copy<ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE>(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1);
 				return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
 				return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
 			} else if (privlen == 0) {
 			} else if (privlen == 0) {
 				_hasPrivate = false;
 				_hasPrivate = false;

+ 13 - 13
node/InetAddress.cpp

@@ -96,16 +96,16 @@ InetAddress::IpScope InetAddress::ipScope() const noexcept
 
 
 void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port) noexcept
 void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port) noexcept
 {
 {
-	memset(this,0,sizeof(InetAddress));
+	memoryZero(this);
 	if (ipLen == 4) {
 	if (ipLen == 4) {
 		uint32_t ipb[1];
 		uint32_t ipb[1];
-		memcpy(ipb,ipBytes,4);
+		Utils::copy<4>(ipb,ipBytes);
 		_data.ss_family = AF_INET;
 		_data.ss_family = AF_INET;
 		reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr = ipb[0];
 		reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr = ipb[0];
 		reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
 		reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
 	} else if (ipLen == 16) {
 	} else if (ipLen == 16) {
 		_data.ss_family = AF_INET6;
 		_data.ss_family = AF_INET6;
-		memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,ipBytes,16);
+		Utils::copy<16>(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,ipBytes);
 		reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port);
 		reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port);
 	}
 	}
 }
 }
@@ -164,7 +164,7 @@ bool InetAddress::fromString(const char *ipSlashPort) noexcept
 {
 {
 	char buf[64];
 	char buf[64];
 
 
-	memset(this,0,sizeof(InetAddress));
+	memoryZero(this);
 
 
 	if (!*ipSlashPort)
 	if (!*ipSlashPort)
 		return true;
 		return true;
@@ -214,7 +214,7 @@ InetAddress InetAddress::netmask() const noexcept
 				nm[0] = 0;
 				nm[0] = 0;
 				nm[1] = 0;
 				nm[1] = 0;
 			}
 			}
-			memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
+			Utils::copy<16>(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm);
 		}	break;
 		}	break;
 	}
 	}
 	return r;
 	return r;
@@ -240,10 +240,10 @@ InetAddress InetAddress::network() const noexcept
 		case AF_INET6: {
 		case AF_INET6: {
 			uint64_t nm[2];
 			uint64_t nm[2];
 			const unsigned int bits = netmaskBits();
 			const unsigned int bits = netmaskBits();
-			memcpy(nm,reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
+			Utils::copy<16>(nm,reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr);
 			nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
 			nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
 			nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
 			nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
-			memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
+			Utils::copy<16>(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm);
 		}	break;
 		}	break;
 	}
 	}
 	return r;
 	return r;
@@ -324,7 +324,7 @@ void InetAddress::forTrace(ZT_TraceEventPathAddress &ta) const noexcept
 	uint32_t tmp;
 	uint32_t tmp;
 	switch(_data.ss_family) {
 	switch(_data.ss_family) {
 		default:
 		default:
-			memset(&ta,0,sizeof(ZT_TraceEventPathAddress));
+			Utils::zero<sizeof(ZT_TraceEventPathAddress)>(&ta);
 			break;
 			break;
 		case AF_INET:
 		case AF_INET:
 			ta.type = ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V4;
 			ta.type = ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V4;
@@ -333,13 +333,13 @@ void InetAddress::forTrace(ZT_TraceEventPathAddress &ta) const noexcept
 			ta.address[1] = reinterpret_cast<const uint8_t *>(&tmp)[1];
 			ta.address[1] = reinterpret_cast<const uint8_t *>(&tmp)[1];
 			ta.address[2] = reinterpret_cast<const uint8_t *>(&tmp)[2];
 			ta.address[2] = reinterpret_cast<const uint8_t *>(&tmp)[2];
 			ta.address[3] = reinterpret_cast<const uint8_t *>(&tmp)[3];
 			ta.address[3] = reinterpret_cast<const uint8_t *>(&tmp)[3];
-			memset(ta.address + 4,0,sizeof(ta.address) - 4);
+			Utils::zero<sizeof(ta.address) - 4>(ta.address + 4);
 			ta.port = reinterpret_cast<const struct sockaddr_in *>(this)->sin_port;
 			ta.port = reinterpret_cast<const struct sockaddr_in *>(this)->sin_port;
 			break;
 			break;
 		case AF_INET6:
 		case AF_INET6:
 			ta.type = ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V6;
 			ta.type = ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V6;
-			memcpy(ta.address,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
-			memset(ta.address + 16,0,sizeof(ta.address) - 16);
+			Utils::copy<16>(ta.address,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
+			Utils::zero<sizeof(ta.address) - 16>(ta.address + 16);
 			ta.port = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port;
 			ta.port = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port;
 			break;
 			break;
 	}
 	}
@@ -415,7 +415,7 @@ int InetAddress::unmarshal(const uint8_t *restrict data,const int len) noexcept
 		case 4:
 		case 4:
 			if (len < 7)
 			if (len < 7)
 				return -1;
 				return -1;
-			memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
+			memoryZero(this);
 			reinterpret_cast<sockaddr_in *>(this)->sin_family = AF_INET;
 			reinterpret_cast<sockaddr_in *>(this)->sin_family = AF_INET;
 			reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[0] = data[1];
 			reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[0] = data[1];
 			reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[1] = data[2];
 			reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[1] = data[2];
@@ -427,7 +427,7 @@ int InetAddress::unmarshal(const uint8_t *restrict data,const int len) noexcept
 		case 6:
 		case 6:
 			if (len < 19)
 			if (len < 19)
 				return -1;
 				return -1;
-			memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
+			memoryZero(this);
 			reinterpret_cast<sockaddr_in6 *>(this)->sin6_family = AF_INET6;
 			reinterpret_cast<sockaddr_in6 *>(this)->sin6_family = AF_INET6;
 			for(int i=0;i<16;i++)
 			for(int i=0;i<16;i++)
 				(reinterpret_cast<sockaddr_in6 *>(this)->sin6_addr.s6_addr)[i] = data[i+1];
 				(reinterpret_cast<sockaddr_in6 *>(this)->sin6_addr.s6_addr)[i] = data[i+1];

+ 13 - 8
node/InetAddress.hpp

@@ -43,9 +43,9 @@ private:
 	template<typename SA>
 	template<typename SA>
 	ZT_INLINE void copySockaddrToThis(const SA *sa) noexcept
 	ZT_INLINE void copySockaddrToThis(const SA *sa) noexcept
 	{
 	{
-		memcpy(reinterpret_cast<void *>(this),sa,sizeof(SA));
+		Utils::copy<sizeof(SA)>(reinterpret_cast<void *>(this),sa);
 		if (sizeof(SA) < sizeof(InetAddress))
 		if (sizeof(SA) < sizeof(InetAddress))
-			memset(reinterpret_cast<uint8_t *>(this) + sizeof(SA),0,sizeof(InetAddress) - sizeof(SA));
+			Utils::zero<sizeof(InetAddress) - sizeof(SA)>(reinterpret_cast<uint8_t *>(this) + sizeof(SA));
 	}
 	}
 
 
 public:
 public:
@@ -100,8 +100,11 @@ public:
 	ZT_INLINE InetAddress(const uint32_t ipv4,unsigned int port) noexcept { this->set(&ipv4,4,port); }
 	ZT_INLINE InetAddress(const uint32_t ipv4,unsigned int port) noexcept { this->set(&ipv4,4,port); }
 	explicit ZT_INLINE InetAddress(const char *ipSlashPort) noexcept { this->fromString(ipSlashPort); }
 	explicit ZT_INLINE InetAddress(const char *ipSlashPort) noexcept { this->fromString(ipSlashPort); }
 
 
-	ZT_INLINE void clear() noexcept { memoryZero(this); }
-
+	ZT_INLINE InetAddress &operator=(const InetAddress &a) noexcept
+	{
+		memoryCopy(this,a);
+		return *this;
+	}
 	ZT_INLINE InetAddress &operator=(const sockaddr_storage &ss) noexcept
 	ZT_INLINE InetAddress &operator=(const sockaddr_storage &ss) noexcept
 	{
 	{
 		memoryCopyUnsafe(this,&ss);
 		memoryCopyUnsafe(this,&ss);
@@ -123,7 +126,7 @@ public:
 	{
 	{
 		if (sa)
 		if (sa)
 			copySockaddrToThis(sa);
 			copySockaddrToThis(sa);
-		else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
+		else memoryZero(this);
 		return *this;
 		return *this;
 	}
 	}
 	ZT_INLINE InetAddress &operator=(const sockaddr_in6 &sa) noexcept
 	ZT_INLINE InetAddress &operator=(const sockaddr_in6 &sa) noexcept
@@ -135,7 +138,7 @@ public:
 	{
 	{
 		if (sa)
 		if (sa)
 			copySockaddrToThis(sa);
 			copySockaddrToThis(sa);
-		else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
+		else memoryZero(this);
 		return *this;
 		return *this;
 	}
 	}
 	ZT_INLINE InetAddress &operator=(const sockaddr &sa) noexcept
 	ZT_INLINE InetAddress &operator=(const sockaddr &sa) noexcept
@@ -144,7 +147,7 @@ public:
 			copySockaddrToThis(reinterpret_cast<const sockaddr_in *>(&sa));
 			copySockaddrToThis(reinterpret_cast<const sockaddr_in *>(&sa));
 		else if (sa.sa_family == AF_INET6)
 		else if (sa.sa_family == AF_INET6)
 			copySockaddrToThis(reinterpret_cast<const sockaddr_in6 *>(&sa));
 			copySockaddrToThis(reinterpret_cast<const sockaddr_in6 *>(&sa));
-		else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
+		else memoryZero(this);
 		return *this;
 		return *this;
 	}
 	}
 	ZT_INLINE InetAddress &operator=(const sockaddr *sa) noexcept
 	ZT_INLINE InetAddress &operator=(const sockaddr *sa) noexcept
@@ -161,6 +164,8 @@ public:
 		return *this;
 		return *this;
 	}
 	}
 
 
+	ZT_INLINE void clear() noexcept { memoryZero(this); }
+
 	/**
 	/**
 	 * @return Address family (ss_family in sockaddr_storage)
 	 * @return Address family (ss_family in sockaddr_storage)
 	 */
 	 */
@@ -339,7 +344,7 @@ public:
 				break;
 				break;
 			case AF_INET6:
 			case AF_INET6:
 				reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_family = AF_INET;
 				reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_family = AF_INET;
-				memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
+				Utils::copy<16>(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
 				break;
 				break;
 		}
 		}
 		return r;
 		return r;

+ 14 - 14
node/LZ4.cpp

@@ -37,6 +37,7 @@
 // original LZ4 license.
 // original LZ4 license.
 
 
 #include "LZ4.hpp"
 #include "LZ4.hpp"
+#include "Utils.hpp"
 
 
 #include <cstring>
 #include <cstring>
 #include <cstdlib>
 #include <cstdlib>
@@ -113,7 +114,6 @@ union LZ4_streamDecode_u {
 
 
 #define ALLOCATOR(n,s) calloc(n,s)
 #define ALLOCATOR(n,s) calloc(n,s)
 #define FREEMEM		free
 #define FREEMEM		free
-#define MEM_INIT	   memset
 
 
 typedef  uint8_t BYTE;
 typedef  uint8_t BYTE;
 typedef uint16_t U16;
 typedef uint16_t U16;
@@ -142,26 +142,26 @@ FORCE_INLINE U32 LZ4_read32(const void* ptr) { return ((const unalign*)ptr)->u32
 FORCE_INLINE reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; }
 FORCE_INLINE reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; }
 FORCE_INLINE void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
 FORCE_INLINE void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
 FORCE_INLINE void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
 FORCE_INLINE void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
-#else  /* safe and portable access through memcpy() */
+#else  /* safe and portable */
 FORCE_INLINE U16 LZ4_read16(const void* memPtr)
 FORCE_INLINE U16 LZ4_read16(const void* memPtr)
 {
 {
-	U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
+	U16 val; Utils::copy(&val, memPtr, sizeof(val)); return val;
 }
 }
 FORCE_INLINE U32 LZ4_read32(const void* memPtr)
 FORCE_INLINE U32 LZ4_read32(const void* memPtr)
 {
 {
-	U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
+	U32 val; Utils::copy(&val, memPtr, sizeof(val)); return val;
 }
 }
 FORCE_INLINE reg_t LZ4_read_ARCH(const void* memPtr)
 FORCE_INLINE reg_t LZ4_read_ARCH(const void* memPtr)
 {
 {
-	reg_t val; memcpy(&val, memPtr, sizeof(val)); return val;
+	reg_t val; Utils::copy(&val, memPtr, sizeof(val)); return val;
 }
 }
 FORCE_INLINE void LZ4_write16(void* memPtr, U16 value)
 FORCE_INLINE void LZ4_write16(void* memPtr, U16 value)
 {
 {
-	memcpy(memPtr, &value, sizeof(value));
+	Utils::copy(memPtr, &value, sizeof(value));
 }
 }
 FORCE_INLINE void LZ4_write32(void* memPtr, U32 value)
 FORCE_INLINE void LZ4_write32(void* memPtr, U32 value)
 {
 {
-	memcpy(memPtr, &value, sizeof(value));
+	Utils::copy(memPtr, &value, sizeof(value));
 }
 }
 #endif /* LZ4_FORCE_MEMORY_ACCESS */
 #endif /* LZ4_FORCE_MEMORY_ACCESS */
 
 
@@ -188,7 +188,7 @@ FORCE_INLINE void LZ4_writeLE16(void* memPtr, U16 value)
 
 
 FORCE_INLINE void LZ4_copy8(void* dst, const void* src)
 FORCE_INLINE void LZ4_copy8(void* dst, const void* src)
 {
 {
-	memcpy(dst,src,8);
+	Utils::copy<8>(dst,src);
 }
 }
 
 
 FORCE_INLINE void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
 FORCE_INLINE void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
@@ -555,7 +555,7 @@ FORCE_INLINE int LZ4_compress_generic(
 		} else {
 		} else {
 			*op++ = (BYTE)(lastRun<<ML_BITS);
 			*op++ = (BYTE)(lastRun<<ML_BITS);
 		}
 		}
-		memcpy(op, anchor, lastRun);
+		Utils::copy(op, anchor, lastRun);
 		op += lastRun;
 		op += lastRun;
 	}
 	}
 
 
@@ -584,7 +584,7 @@ ZT_INLINE int LZ4_compress_fast_extState(void* state,const char* source,char* de
 
 
 FORCE_INLINE void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
 FORCE_INLINE void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
 {
 {
-	MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));
+	Utils::zero<sizeof(LZ4_stream_t)>(LZ4_stream);
 }
 }
 
 
 FORCE_INLINE int LZ4_decompress_generic(
 FORCE_INLINE int LZ4_decompress_generic(
@@ -655,7 +655,7 @@ FORCE_INLINE int LZ4_decompress_generic(
 				if ((!endOnInput) && (cpy != oend)) goto _output_error;	   /* Error : block decoding must stop exactly there */
 				if ((!endOnInput) && (cpy != oend)) goto _output_error;	   /* Error : block decoding must stop exactly there */
 				if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error;   /* Error : input must be consumed */
 				if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error;   /* Error : input must be consumed */
 			}
 			}
-			memcpy(op, ip, length);
+			Utils::copy(op, ip, length);
 			ip += length;
 			ip += length;
 			op += length;
 			op += length;
 			break;	 /* Necessarily EOF, due to parsing restrictions */
 			break;	 /* Necessarily EOF, due to parsing restrictions */
@@ -694,14 +694,14 @@ FORCE_INLINE int LZ4_decompress_generic(
 				/* match encompass external dictionary and current block */
 				/* match encompass external dictionary and current block */
 				size_t const copySize = (size_t)(lowPrefix-match);
 				size_t const copySize = (size_t)(lowPrefix-match);
 				size_t const restSize = length - copySize;
 				size_t const restSize = length - copySize;
-				memcpy(op, dictEnd - copySize, copySize);
+				Utils::copy(op, dictEnd - copySize, copySize);
 				op += copySize;
 				op += copySize;
 				if (restSize > (size_t)(op-lowPrefix)) {  /* overlap copy */
 				if (restSize > (size_t)(op-lowPrefix)) {  /* overlap copy */
 					BYTE* const endOfMatch = op + restSize;
 					BYTE* const endOfMatch = op + restSize;
 					const BYTE* copyFrom = lowPrefix;
 					const BYTE* copyFrom = lowPrefix;
 					while (op < endOfMatch) *op++ = *copyFrom++;
 					while (op < endOfMatch) *op++ = *copyFrom++;
 				} else {
 				} else {
-					memcpy(op, lowPrefix, restSize);
+					Utils::copy(op, lowPrefix, restSize);
 					op += restSize;
 					op += restSize;
 				}   }
 				}   }
 			continue;
 			continue;
@@ -716,7 +716,7 @@ FORCE_INLINE int LZ4_decompress_generic(
 			op[2] = match[2];
 			op[2] = match[2];
 			op[3] = match[3];
 			op[3] = match[3];
 			match += dec32table[offset];
 			match += dec32table[offset];
-			memcpy(op+4, match, 4);
+			Utils::copy<4>(op+4, match);
 			match -= dec64;
 			match -= dec64;
 		} else { LZ4_copy8(op, match); match+=8; }
 		} else { LZ4_copy8(op, match); match+=8; }
 		op += 8;
 		op += 8;

+ 2 - 2
node/Locator.cpp

@@ -59,7 +59,7 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud
 		if (!excludeSignature) {
 		if (!excludeSignature) {
 			Utils::storeBigEndian(data + p,(uint16_t)_signatureLength);
 			Utils::storeBigEndian(data + p,(uint16_t)_signatureLength);
 			p += 2;
 			p += 2;
-			memcpy(data + p,_signature,_signatureLength);
+			Utils::copy(data + p,_signature,_signatureLength);
 			p += (int)_signatureLength;
 			p += (int)_signatureLength;
 		}
 		}
 
 
@@ -102,7 +102,7 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len) noexcept
 		_signatureLength = sl;
 		_signatureLength = sl;
 		if ((p + (int)sl) > len)
 		if ((p + (int)sl) > len)
 			return -1;
 			return -1;
-		memcpy(_signature,data + p,sl);
+		Utils::copy(_signature,data + p,sl);
 		p += (int)sl;
 		p += (int)sl;
 
 
 		if ((p + 2) > len)
 		if ((p + 2) > len)

+ 4 - 4
node/Network.cpp

@@ -1458,20 +1458,20 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
 	ec->assignedAddressCount = 0;
 	ec->assignedAddressCount = 0;
 	for(unsigned int i=0;i<ZT_MAX_ZT_ASSIGNED_ADDRESSES;++i) {
 	for(unsigned int i=0;i<ZT_MAX_ZT_ASSIGNED_ADDRESSES;++i) {
 		if (i < _config.staticIpCount) {
 		if (i < _config.staticIpCount) {
-			memcpy(&(ec->assignedAddresses[i]),&(_config.staticIps[i]),sizeof(struct sockaddr_storage));
+			Utils::copy<sizeof(struct sockaddr_storage)>(&(ec->assignedAddresses[i]),&(_config.staticIps[i]));
 			++ec->assignedAddressCount;
 			++ec->assignedAddressCount;
 		} else {
 		} else {
-			memset(&(ec->assignedAddresses[i]),0,sizeof(struct sockaddr_storage));
+			Utils::zero<sizeof(struct sockaddr_storage)>(&(ec->assignedAddresses[i]));
 		}
 		}
 	}
 	}
 
 
 	ec->routeCount = 0;
 	ec->routeCount = 0;
 	for(unsigned int i=0;i<ZT_MAX_NETWORK_ROUTES;++i) {
 	for(unsigned int i=0;i<ZT_MAX_NETWORK_ROUTES;++i) {
 		if (i < _config.routeCount) {
 		if (i < _config.routeCount) {
-			memcpy(&(ec->routes[i]),&(_config.routes[i]),sizeof(ZT_VirtualNetworkRoute));
+			Utils::copy<sizeof(ZT_VirtualNetworkRoute)>(&(ec->routes[i]),&(_config.routes[i]));
 			++ec->routeCount;
 			++ec->routeCount;
 		} else {
 		} else {
-			memset(&(ec->routes[i]),0,sizeof(ZT_VirtualNetworkRoute));
+			Utils::zero<sizeof(ZT_VirtualNetworkRoute)>(&(ec->routes[i]));
 		}
 		}
 	}
 	}
 }
 }

+ 2 - 2
node/NetworkConfig.cpp

@@ -123,9 +123,9 @@ bool NetworkConfig::fromDictionary(const Dictionary &d)
 		this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0);
 		this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0);
 		const std::vector<uint8_t> *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH]);
 		const std::vector<uint8_t> *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH]);
 		if (blob->size() == ZT_IDENTITY_HASH_SIZE) {
 		if (blob->size() == ZT_IDENTITY_HASH_SIZE) {
-			memcpy(this->issuedToFingerprintHash,blob->data(),ZT_IDENTITY_HASH_SIZE);
+			Utils::copy<ZT_IDENTITY_HASH_SIZE>(this->issuedToFingerprintHash,blob->data());
 		} else {
 		} else {
-			memset(this->issuedToFingerprintHash,0,ZT_IDENTITY_HASH_SIZE);
+			Utils::zero<ZT_IDENTITY_HASH_SIZE>(this->issuedToFingerprintHash);
 		}
 		}
 		if (!this->issuedTo)
 		if (!this->issuedTo)
 			return false;
 			return false;

+ 0 - 3
node/NetworkConfig.hpp

@@ -157,9 +157,6 @@ namespace ZeroTier {
 
 
 /**
 /**
  * Network configuration received from network controller nodes
  * Network configuration received from network controller nodes
- *
- * This is a memcpy()'able structure and is safe (in a crash sense) to modify
- * without locks.
  */
  */
 struct NetworkConfig : TriviallyCopyable
 struct NetworkConfig : TriviallyCopyable
 {
 {

+ 3 - 3
node/Node.cpp

@@ -493,7 +493,7 @@ ZT_PeerList *Node::peers() const
 		identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted
 		identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted
 		p->identity = &identities[pl->peerCount];
 		p->identity = &identities[pl->peerCount];
 		p->fingerprint.address = p->address;
 		p->fingerprint.address = p->address;
-		memcpy(p->fingerprint.hash,(*pi)->identity().fingerprint().hash(),ZT_IDENTITY_HASH_SIZE);
+		Utils::copy<ZT_IDENTITY_HASH_SIZE>(p->fingerprint.hash,(*pi)->identity().fingerprint().hash());
 		if ((*pi)->remoteVersionKnown()) {
 		if ((*pi)->remoteVersionKnown()) {
 			p->versionMajor = (int)(*pi)->remoteVersionMajor();
 			p->versionMajor = (int)(*pi)->remoteVersionMajor();
 			p->versionMinor = (int)(*pi)->remoteVersionMinor();
 			p->versionMinor = (int)(*pi)->remoteVersionMinor();
@@ -507,13 +507,13 @@ ZT_PeerList *Node::peers() const
 		if (p->latency >= 0xffff)
 		if (p->latency >= 0xffff)
 			p->latency = -1;
 			p->latency = -1;
 		p->root = RR->topology->isRoot((*pi)->identity()) ? 1 : 0;
 		p->root = RR->topology->isRoot((*pi)->identity()) ? 1 : 0;
-		memcpy(&p->bootstrap,&((*pi)->bootstrap()),sizeof(sockaddr_storage));
+		Utils::copy<sizeof(sockaddr_storage)>(&p->bootstrap,&((*pi)->bootstrap()));
 
 
 		std::vector< SharedPtr<Path> > paths;
 		std::vector< SharedPtr<Path> > paths;
 		(*pi)->getAllPaths(paths);
 		(*pi)->getAllPaths(paths);
 		p->pathCount = 0;
 		p->pathCount = 0;
 		for(std::vector< SharedPtr<Path> >::iterator path(paths.begin());path!=paths.end();++path) {
 		for(std::vector< SharedPtr<Path> >::iterator path(paths.begin());path!=paths.end();++path) {
-			memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage));
+			Utils::copy<sizeof(sockaddr_storage)>(&(p->paths[p->pathCount].address),&((*path)->address()));
 			p->paths[p->pathCount].lastSend = (*path)->lastOut();
 			p->paths[p->pathCount].lastSend = (*path)->lastOut();
 			p->paths[p->pathCount].lastReceive = (*path)->lastIn();
 			p->paths[p->pathCount].lastReceive = (*path)->lastIn();
 			p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address());
 			p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address());

+ 3 - 3
node/Protocol.cpp

@@ -33,8 +33,8 @@ std::atomic<uint64_t> _s_packetIdCtr((uint64_t)time(nullptr) << 32U);
 uint64_t createProbe(const Identity &sender,const Identity &recipient,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) noexcept
 uint64_t createProbe(const Identity &sender,const Identity &recipient,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) noexcept
 {
 {
 	uint8_t tmp[ZT_IDENTITY_HASH_SIZE + ZT_IDENTITY_HASH_SIZE];
 	uint8_t tmp[ZT_IDENTITY_HASH_SIZE + ZT_IDENTITY_HASH_SIZE];
-	memcpy(tmp,sender.fingerprint().hash(),ZT_IDENTITY_HASH_SIZE);
-	memcpy(tmp + ZT_IDENTITY_HASH_SIZE,recipient.fingerprint().hash(),ZT_IDENTITY_HASH_SIZE);
+	Utils::copy<ZT_IDENTITY_HASH_SIZE>(tmp,sender.fingerprint().hash());
+	Utils::copy<ZT_IDENTITY_HASH_SIZE>(tmp + ZT_IDENTITY_HASH_SIZE,recipient.fingerprint().hash());
 	uint64_t hash[6];
 	uint64_t hash[6];
 	SHA384(hash,tmp,sizeof(tmp),key,ZT_PEER_SECRET_KEY_LENGTH);
 	SHA384(hash,tmp,sizeof(tmp),key,ZT_PEER_SECRET_KEY_LENGTH);
 	return hash[0];
 	return hash[0];
@@ -93,7 +93,7 @@ int compress(SharedPtr<Buf> &pkt,int packetSize) noexcept
 	const int uncompressedLen = packetSize - ZT_PROTO_PACKET_PAYLOAD_START;
 	const int uncompressedLen = packetSize - ZT_PROTO_PACKET_PAYLOAD_START;
 	const int compressedLen = LZ4_compress_fast(reinterpret_cast<const char *>(pkt->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),reinterpret_cast<char *>(pkt2->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),uncompressedLen,ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START);
 	const int compressedLen = LZ4_compress_fast(reinterpret_cast<const char *>(pkt->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),reinterpret_cast<char *>(pkt2->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),uncompressedLen,ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START);
 	if ((compressedLen > 0)&&(compressedLen < uncompressedLen)) {
 	if ((compressedLen > 0)&&(compressedLen < uncompressedLen)) {
-		memcpy(pkt2->unsafeData,pkt->unsafeData,ZT_PROTO_PACKET_PAYLOAD_START);
+		Utils::copy<ZT_PROTO_PACKET_PAYLOAD_START>(pkt2->unsafeData,pkt->unsafeData);
 		pkt.swap(pkt2);
 		pkt.swap(pkt2);
 		pkt->as<Protocol::Header>().verb |= ZT_PROTO_VERB_FLAG_COMPRESSED;
 		pkt->as<Protocol::Header>().verb |= ZT_PROTO_VERB_FLAG_COMPRESSED;
 		return compressedLen + ZT_PROTO_PACKET_PAYLOAD_START;
 		return compressedLen + ZT_PROTO_PACKET_PAYLOAD_START;

+ 2 - 2
node/Revocation.cpp

@@ -46,7 +46,7 @@ int Revocation::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX],bool forSig
 	if (!forSign) {
 	if (!forSign) {
 		data[p++] = 1;
 		data[p++] = 1;
 		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength);
 		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength);
-		memcpy(data + p,_signature,_signatureLength);
+		Utils::copy(data + p,_signature,_signatureLength);
 		p += (int)_signatureLength;
 		p += (int)_signatureLength;
 	}
 	}
 	data[p++] = 0;
 	data[p++] = 0;
@@ -77,7 +77,7 @@ int Revocation::unmarshal(const uint8_t *restrict data,const int len) noexcept
 	int p = 54 + (int)_signatureLength;
 	int p = 54 + (int)_signatureLength;
 	if ((_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)||(p > len))
 	if ((_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)||(p > len))
 		return -1;
 		return -1;
-	memcpy(_signature,data + 54,_signatureLength);
+	Utils::copy(_signature,data + 54,_signatureLength);
 	if ((p + 2) > len)
 	if ((p + 2) > len)
 		return -1;
 		return -1;
 	p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
 	p += 2 + Utils::loadBigEndian<uint16_t>(data + p);

+ 1 - 1
node/SHA512.cpp

@@ -265,7 +265,7 @@ void KBKDFHMACSHA384(const uint8_t key[32],const char label,const char context,c
 	kbkdfMsg[11] = 1;
 	kbkdfMsg[11] = 1;
 	kbkdfMsg[12] = 0; // key length: 256 bits as big-endian 32-bit value
 	kbkdfMsg[12] = 0; // key length: 256 bits as big-endian 32-bit value
 	HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),kbuf);
 	HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),kbuf);
-	memcpy(out,kbuf,32);
+	Utils::copy<32>(out,kbuf);
 }
 }
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 0 - 4
node/SharedPtr.hpp

@@ -25,10 +25,6 @@ namespace ZeroTier {
  * This is an introspective shared pointer. Classes that need to be reference
  * This is an introspective shared pointer. Classes that need to be reference
  * counted must list this as a 'friend' and must have a private instance of
  * counted must list this as a 'friend' and must have a private instance of
  * atomic<int> called __refCount.
  * atomic<int> called __refCount.
- *
- * This is technically TriviallyCopyable but extreme care must be taken if
- * one wishes to handle it in this manner. A memcpy must be followed by a
- * memset of the source to 0 so as to achieve 'move' semantics.
  */
  */
 template<typename T>
 template<typename T>
 class SharedPtr : public TriviallyCopyable
 class SharedPtr : public TriviallyCopyable

+ 2 - 2
node/Tag.cpp

@@ -42,7 +42,7 @@ int Tag::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX],bool forSign) const noexc
 	if (!forSign) {
 	if (!forSign) {
 		data[p++] = 1;
 		data[p++] = 1;
 		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
 		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
-		memcpy(data + p,_signature,_signatureLength);
+		Utils::copy(data + p,_signature,_signatureLength);
 		p += (int)_signatureLength;
 		p += (int)_signatureLength;
 	}
 	}
 	data[p++] = 0;
 	data[p++] = 0;
@@ -69,7 +69,7 @@ int Tag::unmarshal(const uint8_t *data,int len) noexcept
 	int p = 37 + (int)_signatureLength;
 	int p = 37 + (int)_signatureLength;
 	if ((_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)||(p > len))
 	if ((_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)||(p > len))
 		return -1;
 		return -1;
-	memcpy(_signature,data + p,_signatureLength);
+	Utils::copy(_signature,data + p,_signatureLength);
 	if ((p + 2) > len)
 	if ((p + 2) > len)
 		return -1;
 		return -1;
 	p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
 	p += 2 + Utils::loadBigEndian<uint16_t>(data + p);

+ 12 - 12
node/Tests.cpp

@@ -338,19 +338,19 @@ extern "C" const char *ZTT_general()
 				ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
 				return "Utils::loadAsIsEndian() broken";
 				return "Utils::loadAsIsEndian() broken";
 			}
 			}
-			memset(t,0,sizeof(t));
+			Utils::zero<sizeof(t)>(t);
 			Utils::storeAsIsEndian<uint64_t>(t,0x0807060504030201ULL);
 			Utils::storeAsIsEndian<uint64_t>(t,0x0807060504030201ULL);
 			if (t[0] != 1) {
 			if (t[0] != 1) {
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				return "Utils::storeAsIsEndian() broken";
 				return "Utils::storeAsIsEndian() broken";
 			}
 			}
-			memset(t,0,sizeof(t));
+			Utils::zero<sizeof(t)>(t);
 			Utils::storeAsIsEndian<uint32_t>(t,0x04030201);
 			Utils::storeAsIsEndian<uint32_t>(t,0x04030201);
 			if (t[0] != 1) {
 			if (t[0] != 1) {
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				return "Utils::storeAsIsEndian() broken";
 				return "Utils::storeAsIsEndian() broken";
 			}
 			}
-			memset(t,0,sizeof(t));
+			Utils::zero<sizeof(t)>(t);
 			Utils::storeAsIsEndian<uint16_t>(t,0x0201);
 			Utils::storeAsIsEndian<uint16_t>(t,0x0201);
 			if (t[0] != 1) {
 			if (t[0] != 1) {
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
@@ -369,19 +369,19 @@ extern "C" const char *ZTT_general()
 				ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
 				return "Utils::loadAsIsEndian() broken";
 				return "Utils::loadAsIsEndian() broken";
 			}
 			}
-			memset(t,0,sizeof(t));
+			Utils::zero<sizeof(t)>(t);
 			Utils::storeAsIsEndian<uint64_t>(t,0x0807060504030201ULL);
 			Utils::storeAsIsEndian<uint64_t>(t,0x0807060504030201ULL);
 			if (t[0] != 8) {
 			if (t[0] != 8) {
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				return "Utils::storeAsIsEndian() broken";
 				return "Utils::storeAsIsEndian() broken";
 			}
 			}
-			memset(t,0,sizeof(t));
+			Utils::zero<sizeof(t)>(t);
 			Utils::storeAsIsEndian<uint32_t>(t,0x04030201);
 			Utils::storeAsIsEndian<uint32_t>(t,0x04030201);
 			if (t[0] != 4) {
 			if (t[0] != 4) {
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				return "Utils::storeAsIsEndian() broken";
 				return "Utils::storeAsIsEndian() broken";
 			}
 			}
-			memset(t,0,sizeof(t));
+			Utils::zero<sizeof(t)>(t);
 			Utils::storeAsIsEndian<uint16_t>(t,0x0201);
 			Utils::storeAsIsEndian<uint16_t>(t,0x0201);
 			if (t[0] != 2) {
 			if (t[0] != 2) {
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (storeAsIsEndian)" ZT_EOL_S);
@@ -831,14 +831,14 @@ extern "C" const char *ZTT_crypto()
 			ZT_T_PRINTF("[crypto] Testing Salsa20... ");
 			ZT_T_PRINTF("[crypto] Testing Salsa20... ");
 			Salsa20 s20;
 			Salsa20 s20;
 			s20.init(SALSA20_TV0_KEY,SALSA20_TV0_IV);
 			s20.init(SALSA20_TV0_KEY,SALSA20_TV0_IV);
-			memset(ks,0,sizeof(ks));
+			Utils::zero<sizeof(ks)>(ks);
 			s20.crypt20(ks,ks,sizeof(ks));
 			s20.crypt20(ks,ks,sizeof(ks));
 			if (memcmp(ks,SALSA20_TV0_KS,64) != 0) {
 			if (memcmp(ks,SALSA20_TV0_KS,64) != 0) {
 				ZT_T_PRINTF("FAILED (Salsa20 test vector)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (Salsa20 test vector)" ZT_EOL_S);
 				return "Salsa20 test vector failed";
 				return "Salsa20 test vector failed";
 			}
 			}
 			s20.init(SALSA12_TV0_KEY,SALSA12_TV0_IV);
 			s20.init(SALSA12_TV0_KEY,SALSA12_TV0_IV);
-			memset(ks,0,sizeof(ks));
+			Utils::zero<sizeof(ks)>(ks);
 			s20.crypt12(ks,ks,sizeof(ks));
 			s20.crypt12(ks,ks,sizeof(ks));
 			if (memcmp(ks,SALSA12_TV0_KS,64) != 0) {
 			if (memcmp(ks,SALSA12_TV0_KS,64) != 0) {
 				ZT_T_PRINTF("FAILED (Salsa12 test vector)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (Salsa12 test vector)" ZT_EOL_S);
@@ -994,8 +994,8 @@ extern "C" const char *ZTT_benchmarkCrypto()
 {
 {
 	try {
 	try {
 		uint8_t tmp[16384],tag[16];
 		uint8_t tmp[16384],tag[16];
-		memset(tmp,0,sizeof(tmp));
-		memset(tag,0,sizeof(tag));
+		Utils::zero<sizeof(tmp)>(tmp);
+		Utils::zero<sizeof(tag)>(tag);
 
 
 		{
 		{
 			ZT_T_PRINTF("[crypto] Benchmarking SHA384... ");
 			ZT_T_PRINTF("[crypto] Benchmarking SHA384... ");
@@ -1094,7 +1094,7 @@ extern "C" const char *ZTT_benchmarkCrypto()
 
 
 		{
 		{
 			uint8_t sig[ZT_C25519_SIGNATURE_LEN];
 			uint8_t sig[ZT_C25519_SIGNATURE_LEN];
-			memset(sig,0,sizeof(sig));
+			Utils::zero<sizeof(sig)>(sig);
 			ZT_T_PRINTF("[crypto] Benchmarking Ed25519 signature... ");
 			ZT_T_PRINTF("[crypto] Benchmarking Ed25519 signature... ");
 			int64_t start = now();
 			int64_t start = now();
 			for(int i=0;i<150;++i) {
 			for(int i=0;i<150;++i) {
@@ -1169,7 +1169,7 @@ extern "C" const char *ZTT_benchmarkCrypto()
 			for(long i=0;i<10;++i)
 			for(long i=0;i<10;++i)
 				foo = (uint8_t)id.locallyValidate();
 				foo = (uint8_t)id.locallyValidate();
 			end = now();
 			end = now();
-			ZT_T_PRINTF("%.4f ms/validation" ZT_EOL_S,(double)(end - start) / 10.0);
+			ZT_T_PRINTF(" %.4f ms/validation" ZT_EOL_S,(double)(end - start) / 10.0);
 			ZT_T_PRINTF("[crypto] Benchmarking V1 Identity generation...");
 			ZT_T_PRINTF("[crypto] Benchmarking V1 Identity generation...");
 			start = now();
 			start = now();
 			for(long i=0;i<10;++i) {
 			for(long i=0;i<10;++i) {

+ 17 - 17
node/Trace.cpp

@@ -74,7 +74,7 @@ void Trace::unexpectedError(
 	ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev));
 	ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev));
 	ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_UNEXPECTED_ERROR);
 	ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_UNEXPECTED_ERROR);
 	ev.codeLocation = codeLocation;
 	ev.codeLocation = codeLocation;
-	memset(ev.message,0,sizeof(ev.message));
+	Utils::zero<sizeof(ev.message)>(ev.message);
 	va_start(ap,message);
 	va_start(ap,message);
 	vsnprintf(ev.message,sizeof(ev.message),message,ap);
 	vsnprintf(ev.message,sizeof(ev.message),message,ap);
 	va_end(ap);
 	va_end(ap);
@@ -116,12 +116,12 @@ void Trace::_tryingNewPath(
 	ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev));
 	ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev));
 	ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_TRYING_NEW_PATH);
 	ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_TRYING_NEW_PATH);
 	ev.codeLocation = Utils::hton(codeLocation);
 	ev.codeLocation = Utils::hton(codeLocation);
-	memcpy(&ev.peer,trying.fingerprint().apiFingerprint(),sizeof(ev.peer));
+	Utils::copy<sizeof(ev.peer)>(&ev.peer,trying.fingerprint().apiFingerprint());
 	physicalAddress.forTrace(ev.physicalAddress);
 	physicalAddress.forTrace(ev.physicalAddress);
 	triggerAddress.forTrace(ev.triggerAddress);
 	triggerAddress.forTrace(ev.triggerAddress);
 	ev.triggeringPacketId = triggeringPacketId;
 	ev.triggeringPacketId = triggeringPacketId;
 	ev.triggeringPacketVerb = triggeringPacketVerb;
 	ev.triggeringPacketVerb = triggeringPacketVerb;
-	memcpy(&ev.triggeringPeer,triggeringPeer.fingerprint().apiFingerprint(),sizeof(ev.triggeringPeer));
+	Utils::copy<sizeof(ev.triggeringPeer)>(&ev.triggeringPeer,triggeringPeer.fingerprint().apiFingerprint());
 	ev.reason = (uint8_t)reason;
 	ev.reason = (uint8_t)reason;
 	RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
 	RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
 }
 }
@@ -139,7 +139,7 @@ void Trace::_learnedNewPath(
 	ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_LEARNED_NEW_PATH);
 	ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_LEARNED_NEW_PATH);
 	ev.codeLocation = Utils::hton(codeLocation);
 	ev.codeLocation = Utils::hton(codeLocation);
 	ev.packetId = packetId; // packet IDs are kept in big-endian
 	ev.packetId = packetId; // packet IDs are kept in big-endian
-	memcpy(&ev.peer,peerIdentity.fingerprint().apiFingerprint(),sizeof(ev.peer));
+	Utils::copy<sizeof(ev.peer)>(&ev.peer,peerIdentity.fingerprint().apiFingerprint());
 	physicalAddress.forTrace(ev.physicalAddress);
 	physicalAddress.forTrace(ev.physicalAddress);
 	replaced.forTrace(ev.replaced);
 	replaced.forTrace(ev.replaced);
 
 
@@ -163,7 +163,7 @@ void Trace::_incomingPacketDropped(
 	ev.codeLocation = Utils::hton(codeLocation);
 	ev.codeLocation = Utils::hton(codeLocation);
 	ev.packetId = packetId; // packet IDs are kept in big-endian
 	ev.packetId = packetId; // packet IDs are kept in big-endian
 	ev.networkId = Utils::hton(networkId);
 	ev.networkId = Utils::hton(networkId);
-	memcpy(&ev.peer,peerIdentity.fingerprint().apiFingerprint(),sizeof(ev.peer));
+	Utils::copy<sizeof(ev.peer)>(&ev.peer,peerIdentity.fingerprint().apiFingerprint());
 	physicalAddress.forTrace(ev.physicalAddress);
 	physicalAddress.forTrace(ev.physicalAddress);
 	ev.hops = hops;
 	ev.hops = hops;
 	ev.verb = verb;
 	ev.verb = verb;
@@ -196,8 +196,8 @@ void Trace::_outgoingNetworkFrameDropped(
 		unsigned int l = frameLength;
 		unsigned int l = frameLength;
 		if (l > sizeof(ev.frameHead))
 		if (l > sizeof(ev.frameHead))
 			l = sizeof(ev.frameHead);
 			l = sizeof(ev.frameHead);
-		memcpy(ev.frameHead,frameData,l);
-		memset(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
+		Utils::copy(ev.frameHead,frameData,l);
+		Utils::copy(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
 	}
 	}
 	ev.reason = (uint8_t)reason;
 	ev.reason = (uint8_t)reason;
 
 
@@ -226,7 +226,7 @@ void Trace::_incomingNetworkFrameDropped(
 	ev.networkId = Utils::hton(networkId);
 	ev.networkId = Utils::hton(networkId);
 	ev.sourceMac = Utils::hton(sourceMac.toInt());
 	ev.sourceMac = Utils::hton(sourceMac.toInt());
 	ev.destMac = Utils::hton(destMac.toInt());
 	ev.destMac = Utils::hton(destMac.toInt());
-	memcpy(&ev.sender,peerIdentity.fingerprint().apiFingerprint(),sizeof(ev.sender));
+	Utils::copy<sizeof(ev.sender)>(&ev.sender,peerIdentity.fingerprint().apiFingerprint());
 	physicalAddress.forTrace(ev.physicalAddress);
 	physicalAddress.forTrace(ev.physicalAddress);
 	ev.hops = hops;
 	ev.hops = hops;
 	ev.frameLength = Utils::hton(frameLength);
 	ev.frameLength = Utils::hton(frameLength);
@@ -234,8 +234,8 @@ void Trace::_incomingNetworkFrameDropped(
 		unsigned int l = frameLength;
 		unsigned int l = frameLength;
 		if (l > sizeof(ev.frameHead))
 		if (l > sizeof(ev.frameHead))
 			l = sizeof(ev.frameHead);
 			l = sizeof(ev.frameHead);
-		memcpy(ev.frameHead,frameData,l);
-		memset(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
+		Utils::copy(ev.frameHead,frameData,l);
+		Utils::copy(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
 	}
 	}
 	ev.verb = verb;
 	ev.verb = verb;
 	ev.credentialRequestSent = (uint8_t)credentialRequestSent;
 	ev.credentialRequestSent = (uint8_t)credentialRequestSent;
@@ -282,10 +282,10 @@ void Trace::_networkFilter(
 	ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER);
 	ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER);
 	ev.codeLocation = Utils::hton(codeLocation);
 	ev.codeLocation = Utils::hton(codeLocation);
 	ev.networkId = Utils::hton(networkId);
 	ev.networkId = Utils::hton(networkId);
-	memcpy(ev.primaryRuleSetLog,primaryRuleSetLog,sizeof(ev.primaryRuleSetLog));
+	Utils::copy<sizeof(ev.primaryRuleSetLog)>(ev.primaryRuleSetLog,primaryRuleSetLog);
 	if (matchingCapabilityRuleSetLog)
 	if (matchingCapabilityRuleSetLog)
-		memcpy(ev.matchingCapabilityRuleSetLog,matchingCapabilityRuleSetLog,sizeof(ev.matchingCapabilityRuleSetLog));
-	else memset(ev.matchingCapabilityRuleSetLog,0,sizeof(ev.matchingCapabilityRuleSetLog));
+		Utils::copy<sizeof(ev.matchingCapabilityRuleSetLog)>(ev.matchingCapabilityRuleSetLog,matchingCapabilityRuleSetLog);
+	else Utils::zero<sizeof(ev.matchingCapabilityRuleSetLog)>(ev.matchingCapabilityRuleSetLog);
 	ev.matchingCapabilityId = Utils::hton(matchingCapabilityId);
 	ev.matchingCapabilityId = Utils::hton(matchingCapabilityId);
 	ev.matchingCapabilityTimestamp = Utils::hton(matchingCapabilityTimestamp);
 	ev.matchingCapabilityTimestamp = Utils::hton(matchingCapabilityTimestamp);
 	ev.source = Utils::hton(source.toInt());
 	ev.source = Utils::hton(source.toInt());
@@ -297,8 +297,8 @@ void Trace::_networkFilter(
 		unsigned int l = frameLength;
 		unsigned int l = frameLength;
 		if (l > sizeof(ev.frameHead))
 		if (l > sizeof(ev.frameHead))
 			l = sizeof(ev.frameHead);
 			l = sizeof(ev.frameHead);
-		memcpy(ev.frameHead,frameData,l);
-		memset(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
+		Utils::copy(ev.frameHead,frameData,l);
+		Utils::copy(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
 	}
 	}
 	ev.etherType = Utils::hton(etherType);
 	ev.etherType = Utils::hton(etherType);
 	ev.vlanId = Utils::hton(vlanId);
 	ev.vlanId = Utils::hton(vlanId);
@@ -325,10 +325,10 @@ void Trace::_credentialRejected(
 	ev.codeLocation = Utils::hton(codeLocation);
 	ev.codeLocation = Utils::hton(codeLocation);
 	ev.networkId = Utils::hton(networkId);
 	ev.networkId = Utils::hton(networkId);
 	if (identity) {
 	if (identity) {
-		memcpy(&ev.peer,identity.fingerprint().apiFingerprint(),sizeof(ev.peer));
+		Utils::copy<sizeof(ev.peer)>(&ev.peer,identity.fingerprint().apiFingerprint());
 	} else {
 	} else {
 		ev.peer.address = address.toInt();
 		ev.peer.address = address.toInt();
-		memset(ev.peer.hash,0,sizeof(ev.peer.hash));
+		Utils::zero<sizeof(ev.peer.hash)>(ev.peer.hash);
 	}
 	}
 	ev.credentialId = Utils::hton(credentialId);
 	ev.credentialId = Utils::hton(credentialId);
 	ev.credentialTimestamp = Utils::hton(credentialTimestamp);
 	ev.credentialTimestamp = Utils::hton(credentialTimestamp);

+ 2 - 2
node/Trace.hpp

@@ -70,7 +70,7 @@ public:
 		}
 		}
 		ZT_INLINE void clear()
 		ZT_INLINE void clear()
 		{
 		{
-			memset(l,0,sizeof(l));
+			Utils::zero<sizeof(l)>(l);
 		}
 		}
 	};
 	};
 
 
@@ -82,7 +82,7 @@ public:
 	template<unsigned int C>
 	template<unsigned int C>
 	struct Str
 	struct Str
 	{
 	{
-		ZT_INLINE Str() { memset(s,0,sizeof(s)); }
+		ZT_INLINE Str() { Utils::zero<sizeof(s)>(s); }
 		constexpr static unsigned int capacity() { return C; }
 		constexpr static unsigned int capacity() { return C; }
 		char s[C];
 		char s[C];
 	};
 	};

+ 9 - 9
node/TriviallyCopyable.hpp

@@ -23,7 +23,7 @@
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 /**
 /**
- * Classes inheriting from this base class are safe to abuse in C-like ways: memcpy, memset, etc.
+ * Classes inheriting from this base class are safe to abuse in C-like ways.
  *
  *
  * It also includes some static methods to do this conveniently.
  * It also includes some static methods to do this conveniently.
  */
  */
@@ -65,7 +65,7 @@ ZT_PACKED_STRUCT(struct TriviallyCopyable
 	static ZT_INLINE void memoryZero(T *obj) noexcept
 	static ZT_INLINE void memoryZero(T *obj) noexcept
 	{
 	{
 		TriviallyCopyable *const tmp = obj;
 		TriviallyCopyable *const tmp = obj;
-		memset(tmp,0,sizeof(T));
+		Utils::zero<sizeof(T)>(tmp);
 	}
 	}
 
 
 	/**
 	/**
@@ -78,7 +78,7 @@ ZT_PACKED_STRUCT(struct TriviallyCopyable
 	static ZT_INLINE void memoryZero(T &obj) noexcept
 	static ZT_INLINE void memoryZero(T &obj) noexcept
 	{
 	{
 		TriviallyCopyable *const tmp = &obj;
 		TriviallyCopyable *const tmp = &obj;
-		memset(tmp,0,sizeof(T));
+		Utils::zero<sizeof(T)>(tmp);
 	}
 	}
 
 
 	/**
 	/**
@@ -92,7 +92,7 @@ ZT_PACKED_STRUCT(struct TriviallyCopyable
 	static ZT_INLINE void memoryCopyUnsafe(T *dest,const void *src) noexcept
 	static ZT_INLINE void memoryCopyUnsafe(T *dest,const void *src) noexcept
 	{
 	{
 		TriviallyCopyable *const tmp = dest;
 		TriviallyCopyable *const tmp = dest;
-		memcpy(tmp,src,sizeof(T));
+		Utils::copy<sizeof(T)>(tmp,src);
 	}
 	}
 
 
 	/**
 	/**
@@ -106,7 +106,7 @@ ZT_PACKED_STRUCT(struct TriviallyCopyable
 	static ZT_INLINE void memoryCopyUnsafe(T &dest,const void *src) noexcept
 	static ZT_INLINE void memoryCopyUnsafe(T &dest,const void *src) noexcept
 	{
 	{
 		TriviallyCopyable *const tmp = &dest;
 		TriviallyCopyable *const tmp = &dest;
-		memcpy(tmp,src,sizeof(T));
+		Utils::copy<sizeof(T)>(tmp,src);
 	}
 	}
 
 
 	/**
 	/**
@@ -120,7 +120,7 @@ ZT_PACKED_STRUCT(struct TriviallyCopyable
 	static ZT_INLINE void memoryCopy(T *dest,const T *src) noexcept
 	static ZT_INLINE void memoryCopy(T *dest,const T *src) noexcept
 	{
 	{
 		TriviallyCopyable *const tmp = dest;
 		TriviallyCopyable *const tmp = dest;
-		memcpy(tmp,src,sizeof(T));
+		Utils::copy<sizeof(T)>(tmp,src);
 	}
 	}
 
 
 	/**
 	/**
@@ -134,7 +134,7 @@ ZT_PACKED_STRUCT(struct TriviallyCopyable
 	static ZT_INLINE void memoryCopy(T *dest,const T &src) noexcept
 	static ZT_INLINE void memoryCopy(T *dest,const T &src) noexcept
 	{
 	{
 		TriviallyCopyable *const tmp = dest;
 		TriviallyCopyable *const tmp = dest;
-		memcpy(tmp,&src,sizeof(T));
+		Utils::copy<sizeof(T)>(tmp,&src);
 	}
 	}
 
 
 	/**
 	/**
@@ -148,7 +148,7 @@ ZT_PACKED_STRUCT(struct TriviallyCopyable
 	static ZT_INLINE void memoryCopy(T &dest,const T *src) noexcept
 	static ZT_INLINE void memoryCopy(T &dest,const T *src) noexcept
 	{
 	{
 		TriviallyCopyable *const tmp = &dest;
 		TriviallyCopyable *const tmp = &dest;
-		memcpy(tmp,src,sizeof(T));
+		Utils::copy<sizeof(T)>(tmp,src);
 	}
 	}
 
 
 	/**
 	/**
@@ -162,7 +162,7 @@ ZT_PACKED_STRUCT(struct TriviallyCopyable
 	static ZT_INLINE void memoryCopy(T &dest,const T &src) noexcept
 	static ZT_INLINE void memoryCopy(T &dest,const T &src) noexcept
 	{
 	{
 		TriviallyCopyable *const tmp = &dest;
 		TriviallyCopyable *const tmp = &dest;
-		memcpy(tmp,&src,sizeof(T));
+		Utils::copy<sizeof(T)>(tmp,&src);
 	}
 	}
 });
 });
 
 

+ 260 - 0
node/Utils.hpp

@@ -16,6 +16,12 @@
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
 
 
+#ifdef ZT_ARCH_X64
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <immintrin.h>
+#endif
+
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 namespace Utils {
 namespace Utils {
@@ -577,6 +583,260 @@ static ZT_INLINE void storeLittleEndian(void *const p,const I i) noexcept
 #endif
 #endif
 }
 }
 
 
+template<unsigned int L>
+static ZT_INLINE void copy(void *dest,const void *src) noexcept;
+template<>
+ZT_INLINE void copy<64>(void *const dest,const void *const src) noexcept
+{
+#ifdef ZT_ARCH_X64
+	__m128i a = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src));
+	__m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src) + 1);
+	__m128i c = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src) + 2);
+	__m128i d = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src) + 3);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest),a);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest) + 1,b);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest) + 2,c);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest) + 3,d);
+#else
+	uint64_t a = reinterpret_cast<const uint64_t *>(src)[0];
+	uint64_t b = reinterpret_cast<const uint64_t *>(src)[1];
+	uint64_t c = reinterpret_cast<const uint64_t *>(src)[2];
+	uint64_t d = reinterpret_cast<const uint64_t *>(src)[3];
+	uint64_t e = reinterpret_cast<const uint64_t *>(src)[4];
+	uint64_t f = reinterpret_cast<const uint64_t *>(src)[5];
+	uint64_t g = reinterpret_cast<const uint64_t *>(src)[6];
+	uint64_t h = reinterpret_cast<const uint64_t *>(src)[7];
+	reinterpret_cast<uint64_t *>(dest)[0] = a;
+	reinterpret_cast<uint64_t *>(dest)[1] = b;
+	reinterpret_cast<uint64_t *>(dest)[2] = c;
+	reinterpret_cast<uint64_t *>(dest)[3] = d;
+	reinterpret_cast<uint64_t *>(dest)[4] = e;
+	reinterpret_cast<uint64_t *>(dest)[5] = f;
+	reinterpret_cast<uint64_t *>(dest)[6] = g;
+	reinterpret_cast<uint64_t *>(dest)[7] = h;
+#endif
+}
+template<>
+ZT_INLINE void copy<32>(void *const dest,const void *const src) noexcept
+{
+#ifdef ZT_ARCH_X64
+	__m128i a = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src));
+	__m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src) + 1);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest),a);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest) + 1,b);
+#else
+	uint64_t a = reinterpret_cast<const uint64_t *>(src)[0];
+	uint64_t b = reinterpret_cast<const uint64_t *>(src)[1];
+	uint64_t c = reinterpret_cast<const uint64_t *>(src)[2];
+	uint64_t d = reinterpret_cast<const uint64_t *>(src)[3];
+	reinterpret_cast<uint64_t *>(dest)[0] = a;
+	reinterpret_cast<uint64_t *>(dest)[1] = b;
+	reinterpret_cast<uint64_t *>(dest)[2] = c;
+	reinterpret_cast<uint64_t *>(dest)[3] = d;
+#endif
+}
+template<>
+ZT_INLINE void copy<16>(void *const dest,const void *const src) noexcept
+{
+#ifdef ZT_ARCH_X64
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest),_mm_loadu_si128(reinterpret_cast<const __m128i *>(src)));
+#else
+	uint64_t a = reinterpret_cast<const uint64_t *>(src)[0];
+	uint64_t b = reinterpret_cast<const uint64_t *>(src)[1];
+	reinterpret_cast<uint64_t *>(dest)[0] = a;
+	reinterpret_cast<uint64_t *>(dest)[1] = b;
+#endif
+}
+template<>
+ZT_INLINE void copy<8>(void *const dest,const void *const src) noexcept
+{
+	*reinterpret_cast<uint64_t *>(dest) = *reinterpret_cast<const uint64_t *>(src);
+}
+template<>
+ZT_INLINE void copy<4>(void *const dest,const void *const src) noexcept
+{
+	*reinterpret_cast<uint32_t *>(dest) = *reinterpret_cast<const uint32_t *>(src);
+}
+template<>
+ZT_INLINE void copy<2>(void *const dest,const void *const src) noexcept
+{
+	*reinterpret_cast<uint16_t *>(dest) = *reinterpret_cast<const uint16_t *>(src);
+}
+template<>
+ZT_INLINE void copy<1>(void *const dest,const void *const src) noexcept
+{
+	*reinterpret_cast<uint8_t *>(dest) = *reinterpret_cast<const uint8_t *>(src);
+}
+template<>
+ZT_INLINE void copy<0>(void *const dest,const void *const src) noexcept
+{
+}
+template<unsigned int L>
+static ZT_INLINE void copy(void *const dest,const void *const src) noexcept
+{
+#ifdef ZT_NO_UNALIGNED_ACCESS
+	if ((((uintptr_t)dest | (uintptr_t)src) & 7U) != 0) {
+		memcpy(dest,src,L);
+		return;
+	}
+#endif
+
+	uint8_t *d = reinterpret_cast<uint8_t *>(dest);
+	const uint8_t *s = reinterpret_cast<const uint8_t *>(src);
+
+	for(unsigned int i=0;i<(L / 64U);++i) {
+		copy<64>(d,s);
+		d += 64;
+		s += 64;
+	}
+	if ((L & 63U) >= 32U) {
+		copy<32>(d,s);
+		d += 32;
+		s += 32;
+	}
+	if ((L & 31U) >= 16U) {
+		copy<16>(d,s);
+		d += 16;
+		s += 16;
+	}
+	if ((L & 15U) >= 8U) {
+		copy<8>(d,s);
+		d += 8;
+		s += 8;
+	}
+	if ((L & 7U) >= 4U) {
+		copy<4>(d,s);
+		d += 4;
+		s += 4;
+	}
+	if ((L & 3U) >= 2U) {
+		copy<2>(d,s);
+		d += 2;
+		s += 2;
+	}
+	if ((L & 1U) != 0U) {
+		copy<1>(d,s);
+	}
+}
+static ZT_INLINE void copy(void *const dest,const void *const src,const unsigned int len) noexcept
+{
+	memcpy(dest,src,len);
+}
+
+template<unsigned int L>
+static ZT_INLINE void zero(void *dest) noexcept;
+template<>
+ZT_INLINE void zero<64>(void *const dest) noexcept
+{
+#ifdef ZT_ARCH_X64
+	const __m128i z = _mm_setzero_si128();
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest),z);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest) + 1,z);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest) + 2,z);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest) + 3,z);
+#else
+	const uint64_t z = 0;
+	reinterpret_cast<uint64_t *>(dest)[0] = z;
+	reinterpret_cast<uint64_t *>(dest)[1] = z;
+	reinterpret_cast<uint64_t *>(dest)[2] = z;
+	reinterpret_cast<uint64_t *>(dest)[3] = z;
+	reinterpret_cast<uint64_t *>(dest)[4] = z;
+	reinterpret_cast<uint64_t *>(dest)[5] = z;
+	reinterpret_cast<uint64_t *>(dest)[6] = z;
+	reinterpret_cast<uint64_t *>(dest)[7] = z;
+#endif
+}
+template<>
+ZT_INLINE void zero<32>(void *const dest) noexcept
+{
+#ifdef ZT_ARCH_X64
+	const __m128i z = _mm_setzero_si128();
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest),z);
+	_mm_storeu_si128(reinterpret_cast<__m128i *>(dest) + 1,z);
+#else
+	const uint64_t z = 0;
+	reinterpret_cast<uint64_t *>(dest)[0] = z;
+	reinterpret_cast<uint64_t *>(dest)[1] = z;
+	reinterpret_cast<uint64_t *>(dest)[2] = z;
+	reinterpret_cast<uint64_t *>(dest)[3] = z;
+#endif
+}
+template<>
+ZT_INLINE void zero<16>(void *const dest) noexcept
+{
+	const uint64_t z = 0;
+	reinterpret_cast<uint64_t *>(dest)[0] = z;
+	reinterpret_cast<uint64_t *>(dest)[1] = z;
+}
+template<>
+ZT_INLINE void zero<8>(void *const dest) noexcept
+{
+	*reinterpret_cast<uint64_t *>(dest) = 0;
+}
+template<>
+ZT_INLINE void zero<4>(void *const dest) noexcept
+{
+	*reinterpret_cast<uint32_t *>(dest) = 0;
+}
+template<>
+ZT_INLINE void zero<2>(void *const dest) noexcept
+{
+	*reinterpret_cast<uint16_t *>(dest) = 0;
+}
+template<>
+ZT_INLINE void zero<1>(void *const dest) noexcept
+{
+	*reinterpret_cast<uint8_t *>(dest) = 0;
+}
+template<>
+ZT_INLINE void zero<0>(void *const dest) noexcept
+{
+}
+template<unsigned int L>
+static ZT_INLINE void zero(void *const dest) noexcept
+{
+#ifdef ZT_NO_UNALIGNED_ACCESS
+	if ((((uintptr_t)dest | (uintptr_t)src) & 7U) != 0) {
+		memset(dest,0,L);
+		return;
+	}
+#endif
+
+	uint8_t *d = reinterpret_cast<uint8_t *>(dest);
+
+	for(unsigned int i=0;i<(L / 64U);++i) {
+		zero<64>(d);
+		d += 64;
+	}
+	if ((L & 63U) >= 32U) {
+		zero<32>(d);
+		d += 32;
+	}
+	if ((L & 31U) >= 16U) {
+		zero<16>(d);
+		d += 16;
+	}
+	if ((L & 15U) >= 8U) {
+		zero<8>(d);
+		d += 8;
+	}
+	if ((L & 7U) >= 4U) {
+		zero<4>(d);
+		d += 4;
+	}
+	if ((L & 3U) >= 2U) {
+		zero<2>(d);
+		d += 2;
+	}
+	if ((L & 1U) != 0U) {
+		zero<1>(d);
+	}
+}
+static ZT_INLINE void zero(void *const dest,const unsigned int len) noexcept
+{
+	memset(dest,0,len);
+}
+
 } // namespace Utils
 } // namespace Utils
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 2 - 2
node/VL1.cpp

@@ -275,7 +275,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 					// Simultaneously decrypt and assemble packet into a contiguous buffer.
 					// Simultaneously decrypt and assemble packet into a contiguous buffer.
 					// Since we moved data around above all slices will have sizes that are
 					// Since we moved data around above all slices will have sizes that are
 					// multiples of 64.
 					// multiples of 64.
-					memcpy(pkt.b->unsafeData,ph,sizeof(Protocol::Header));
+					Utils::copy<sizeof(Protocol::Header)>(pkt.b->unsafeData,ph);
 					pkt.e = sizeof(Protocol::Header);
 					pkt.e = sizeof(Protocol::Header);
 					for(FCV<Buf::Slice,ZT_MAX_PACKET_FRAGMENTS>::iterator s(pktv.begin());s!=pktv.end();++s) {
 					for(FCV<Buf::Slice,ZT_MAX_PACKET_FRAGMENTS>::iterator s(pktv.begin());s!=pktv.end();++s) {
 						const unsigned int sliceSize = s->e - s->s;
 						const unsigned int sliceSize = s->e - s->s;
@@ -508,7 +508,7 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Bu
 
 
 	uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
 	uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
 	if ((peer) && (id == peer->identity())) {
 	if ((peer) && (id == peer->identity())) {
-		memcpy(key,peer->key(),ZT_PEER_SECRET_KEY_LENGTH);
+		Utils::copy<ZT_PEER_SECRET_KEY_LENGTH>(key,peer->key());
 	} else {
 	} else {
 		peer.zero();
 		peer.zero();
 		if (!RR->identity.agree(id,key)) {
 		if (!RR->identity.agree(id,key)) {

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