Adam Ierymenko 5 lat temu
rodzic
commit
c1b2c7903c
10 zmienionych plików z 373 dodań i 412 usunięć
  1. 3 179
      node/Constants.hpp
  2. 1 1
      node/Endpoint.hpp
  3. 83 81
      node/Identity.hpp
  4. 2 0
      node/InetAddress.hpp
  5. 19 54
      node/Locator.hpp
  6. 20 20
      node/Mutex.hpp
  7. 176 0
      node/OS.hpp
  8. 2 14
      node/Packet.hpp
  9. 26 0
      node/Utils.cpp
  10. 41 63
      node/Utils.hpp

+ 3 - 179
node/Constants.hpp

@@ -14,11 +14,8 @@
 #ifndef ZT_CONSTANTS_HPP
 #define ZT_CONSTANTS_HPP
 
-/****************************************************************************/
-/* Core includes and OS/platform setup stuff                                */
-/****************************************************************************/
-
 #include "../include/ZeroTierCore.h"
+#include "OS.hpp"
 
 #if __has_include("version.h")
 #include "version.h"
@@ -29,165 +26,6 @@
 #define ZEROTIER_ONE_VERSION_BUILD 255
 #endif
 
-//
-// This include file also auto-detects and canonicalizes some environment
-// information defines:
-//
-// __LINUX__
-// __APPLE__
-// __BSD__ (OSX also defines this)
-// __UNIX_LIKE__ (Linux, BSD, etc.)
-// __WINDOWS__
-//
-// Also makes sure __BYTE_ORDER is defined reasonably.
-//
-
-// Hack: make sure __GCC__ is defined on old GCC compilers
-#ifndef __GCC__
-#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
-#define __GCC__
-#endif
-#endif
-
-#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
-#ifndef __LINUX__
-#define __LINUX__
-#endif
-#ifndef __UNIX_LIKE__
-#define __UNIX_LIKE__
-#endif
-#include <endian.h>
-#endif
-
-#ifdef __APPLE__
-#include <TargetConditionals.h>
-#ifndef __UNIX_LIKE__
-#define __UNIX_LIKE__
-#endif
-#ifndef __BSD__
-#define __BSD__
-#endif
-#include <machine/endian.h>
-#endif
-
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
-#ifndef __UNIX_LIKE__
-#define __UNIX_LIKE__
-#endif
-#ifndef __BSD__
-#define __BSD__
-#endif
-#include <sys/endian.h>
-#ifndef __BYTE_ORDER
-#define __BYTE_ORDER _BYTE_ORDER
-#define __LITTLE_ENDIAN _LITTLE_ENDIAN
-#define __BIG_ENDIAN _BIG_ENDIAN
-#endif
-#endif
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef __WINDOWS__
-#define __WINDOWS__
-#endif
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#pragma warning(disable : 4290)
-#pragma warning(disable : 4996)
-#pragma warning(disable : 4101)
-#undef __UNIX_LIKE__
-#undef __BSD__
-#include <WinSock2.h>
-#include <Windows.h>
-#endif
-
-#ifdef __NetBSD__
-#ifndef RTF_MULTICAST
-#define RTF_MULTICAST 0x20000000
-#endif
-#endif
-
-// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86 and x86_64.
-#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
-#ifndef ZT_NO_TYPE_PUNNING
-#define ZT_NO_TYPE_PUNNING
-#endif
-#endif
-
-// Assume little endian if not defined on Mac and Windows as these don't run on any BE architectures.
-#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER))
-#undef __BYTE_ORDER
-#undef __LITTLE_ENDIAN
-#undef __BIG_ENDIAN
-#define __BIG_ENDIAN 4321
-#define __LITTLE_ENDIAN 1234
-#define __BYTE_ORDER 1234
-#endif
-#ifndef __BYTE_ORDER
-#include <endian.h>
-#endif
-
-#ifdef __WINDOWS__
-#define ZT_PATH_SEPARATOR '\\'
-#define ZT_PATH_SEPARATOR_S "\\"
-#define ZT_EOL_S "\r\n"
-#else
-#define ZT_PATH_SEPARATOR '/'
-#define ZT_PATH_SEPARATOR_S "/"
-#define ZT_EOL_S "\n"
-#endif
-
-#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
-// #define inline __attribute__((always_inline))
-#ifndef restrict
-#define restrict __restrict__
-#endif
-#ifndef likely
-#define likely(x) __builtin_expect((x),1)
-#endif
-#ifndef unlikely
-#define unlikely(x) __builtin_expect((x),0)
-#endif
-#else /* not GCC-like */
-#ifndef restrict
-#define restrict
-#endif
-#ifndef likely
-#define inline inline
-#define likely(x) (x)
-#endif
-#ifndef unlikely
-#define unlikely(x) (x)
-#endif
-#endif
-
-#if defined(__WINDOWS__) && !defined(__GNUC__) && !defined (__clang__) && !defined(__INTEL_COMPILER)
-#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
-#else
-#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
-#endif
-
-#if __cplusplus > 199711L
-#ifndef __CPP11__
-#define __CPP11__
-#endif
-#endif
-
-#ifdef SOCKET
-#define ZT_SOCKET SOCKET
-#else
-#define ZT_SOCKET int
-#endif
-#ifdef INVALID_SOCKET
-#define ZT_INVALID_SOCKET INVALID_SOCKET
-#else
-#define ZT_INVALID_SOCKET -1
-#endif
-
-/****************************************************************************/
-/* Internal ZeroTier constants                                              */
-/****************************************************************************/
-
 /**
  * Length of a ZeroTier address in bytes
  */
@@ -204,29 +42,15 @@
 #define ZT_ADDRESS_RESERVED_PREFIX 0xff
 
 /**
- * Maximum DNS or URL name size for an Endpoint
+ * Maximum DNS or URL name size for an Endpoint (set so that max marshaled endpoint size is 128 bytes)
  */
-#define ZT_ENDPOINT_MAX_NAME_SIZE 256
+#define ZT_ENDPOINT_MAX_NAME_SIZE 124
 
 /**
  * Size of an identity hash (SHA384)
  */
 #define ZT_IDENTITY_HASH_SIZE 48
 
-/**
- * Secure DNS name for ZeroTier's default root
- *
- * This resolves via GeoDNS to the (probably) nearest actual root server's locator.
- */
-#define ZT_DEFAULT_ROOT_NAME "ztl-aj4zes4l6zumq64na6borruuvd6diw2koxrjcaatolcekt2gj5rrhric.ztl-6lhxeo7n3z7kzkgcqzj3ndliaq.zerotier.network"
-
-/**
- * Default locator for default root
- *
- * This is used before the root has been successfully fetched, or if DNS is unavailable.
- */
-#define ZT_DEFAULT_ROOT_LOCATOR "AAAAAW2OuYyfOkbxvzAAduZvqzPihUmmLuIGTRhDJzwsMAukXD8gvvAtutIlcju1mpu0sTU1cwlhruz1oWOs5HfM6wcnAluZrBSlFmoJowAEBLm0DVInCQS5tA1SAbsGKgJuoMgVAAAAAAAAAAAAACcJBioCbqDIFQAAAAAAAAAAAAABuwAAYDvTNB2snbn7TYom4PBTh/ohRgCnI2/A/nfKakGCb+2hGJTtxTCiGTzKZdbjd0vyKAKQLJxhj7RaoCo3XjPn8w9nDEmhdNCgCM/IITCJIzc9tEKFsSQnJY4VmB3dopBAfQAA"
-
 /**
  * Default virtual network MTU (not physical)
  */

+ 1 - 1
node/Endpoint.hpp

@@ -62,7 +62,7 @@ public:
 	inline Type type() const { return _t; }
 
 	static inline int marshalSizeMax() { return ZT_ENDPOINT_MARSHAL_SIZE_MAX; }
-	inline int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX])
+	inline int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const
 	{
 		int p;
 		switch(_t) {

+ 83 - 81
node/Identity.hpp

@@ -246,87 +246,6 @@ public:
 	 */
 	inline const Address &address() const { return _address; }
 
-	static inline int marshalSizeMax() { return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
-	inline int marshal(uint8_t restrict data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate = false) const
-	{
-		_address.copyTo(data,ZT_ADDRESS_LENGTH);
-		switch(_type) {
-
-			case C25519:
-				data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
-				memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
-				if ((includePrivate)&&(_hasPrivate)) {
-					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);
-					return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN);
-				}
-				data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0;
-				return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
-
-			case P384:
-				data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
-				memcpy(data + ZT_ADDRESS_LENGTH + 1,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
-				if ((includePrivate)&&(_hasPrivate)) {
-					data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_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);
-					data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE] = 0;
-					return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1);
-				}
-				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 + 1] = 0;
-				return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
-
-		}
-		return -1;
-	}
-	inline int unmarshal(const uint8_t *restrict data,const int len)
-	{
-		if (len < (ZT_ADDRESS_LENGTH + 1))
-			return -1;
-		unsigned int privlen;
-		switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) {
-
-			case C25519:
-				if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1))
-					return -1;
-				memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN);
-				privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
-				if (privlen == ZT_C25519_PRIVATE_KEY_LEN) {
-					if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN))
-						return -1;
-					_hasPrivate = true;
-					memcpy(_priv.c25519,data + 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) {
-					_hasPrivate = false;
-					return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
-				}
-				break;
-
-			case P384:
-				if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2))
-					return -1;
-				memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
-				privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
-				if (privlen == 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 + 1))
-						return -1;
-					_hasPrivate = true;
-					memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
-					privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE];
-					if (len < (privlen + (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1)))
-						return -1;
-					return (privlen + (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1));
-				} else if (privlen == 0) {
-					_hasPrivate = false;
-					return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
-				}
-				break;
-
-		}
-		return -1;
-	}
-
 	/**
 	 * Serialize this identity (binary)
 	 *
@@ -489,6 +408,89 @@ public:
 
 	inline unsigned long hashCode() const { return ((unsigned long)_address.toInt() + (unsigned long)_pub.c25519[0] + (unsigned long)_pub.c25519[1] + (unsigned long)_pub.c25519[2]); }
 
+	// Marshal interface ///////////////////////////////////////////////////////
+	static inline int marshalSizeMax() { return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
+	inline int marshal(uint8_t restrict data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate = false) const
+	{
+		_address.copyTo(data,ZT_ADDRESS_LENGTH);
+		switch(_type) {
+
+			case C25519:
+				data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
+				memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
+				if ((includePrivate)&&(_hasPrivate)) {
+					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);
+					return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN);
+				}
+				data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0;
+				return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
+
+			case P384:
+				data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
+				memcpy(data + ZT_ADDRESS_LENGTH + 1,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
+				if ((includePrivate)&&(_hasPrivate)) {
+					data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_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);
+					data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE] = 0;
+					return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1);
+				}
+				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 + 1] = 0;
+				return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
+
+		}
+		return -1;
+	}
+	inline int unmarshal(const uint8_t *restrict data,const int len)
+	{
+		if (len < (ZT_ADDRESS_LENGTH + 1))
+			return -1;
+		unsigned int privlen;
+		switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) {
+
+			case C25519:
+				if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1))
+					return -1;
+				memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN);
+				privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
+				if (privlen == ZT_C25519_PRIVATE_KEY_LEN) {
+					if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN))
+						return -1;
+					_hasPrivate = true;
+					memcpy(_priv.c25519,data + 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) {
+					_hasPrivate = false;
+					return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
+				}
+				break;
+
+			case P384:
+				if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2))
+					return -1;
+				memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
+				privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
+				if (privlen == 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 + 1))
+						return -1;
+					_hasPrivate = true;
+					memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
+					privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE];
+					if (len < (privlen + (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1)))
+						return -1;
+					return (privlen + (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1));
+				} else if (privlen == 0) {
+					_hasPrivate = false;
+					return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
+				}
+				break;
+
+		}
+		return -1;
+	}
+	////////////////////////////////////////////////////////////////////////////
+
 private:
 	Address _address;
 	Type _type; // _type determines which fields in _priv and _pub are used

+ 2 - 0
node/InetAddress.hpp

@@ -489,6 +489,7 @@ struct InetAddress : public sockaddr_storage
 	 */
 	inline operator bool() const { return (ss_family != 0); }
 
+	// Marshal interface ///////////////////////////////////////////////////////
 	static inline int marshalSizeMax() { return 19; }
 	inline int marshal(uint8_t restrict data[19]) const
 	{
@@ -547,6 +548,7 @@ struct InetAddress : public sockaddr_storage
 				return -1;
 		}
 	}
+	////////////////////////////////////////////////////////////////////////////
 
 	template<unsigned int C>
 	inline void serialize(Buffer<C> &b) const

+ 19 - 54
node/Locator.hpp

@@ -22,8 +22,7 @@
 #include "Identity.hpp"
 
 #define ZT_LOCATOR_MAX_ENDPOINTS 8
-
-#define ZT_LOCATOR_MARSHAL_SIZE_MAX ((ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 8 + 256 + ZT_SIGNATURE_BUFFER_SIZE)
+#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + 2 + (ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 2 + ZT_SIGNATURE_BUFFER_SIZE)
 
 namespace ZeroTier {
 
@@ -36,37 +35,12 @@ namespace ZeroTier {
 class Locator
 {
 public:
-	inline Locator() : _ts(0),_at(nullptr),_signatureLength(0) {}
-	inline ~Locator() { delete [] _at; }
-
-	inline Locator(const Locator &l) :
-		_ts(l._ts),
-		_id(l._id),
-		_at((l._endpointCount > 0) ? new Endpoint[l._endpointCount] : nullptr),
-		_endpointCount(l._endpointCount),
-		_signatureLength(l._signatureLength)
-	{
-		for(unsigned int i=0;i<_endpointCount;++i)
-			_at[i] = l._at[i];
-		memcpy(_signature,l._signature,_signatureLength);
-	}
-
-	inline Locator &operator=(const Locator &l)
-	{
-		_ts = l._ts;
-		_id = l._id;
-		delete [] _at;
-		_at = (l._endpointCount > 0) ? new Endpoint[l._endpointCount] : nullptr;
-		for(unsigned int i=0;i<l._endpointCount;++i)
-			_at[i] = l._at[i];
-		_endpointCount = l._endpointCount;
-		_signatureLength = l._signatureLength;
-		memcpy(_signature,l._signature,_signatureLength);
-		return *this;
-	}
+	inline Locator() : _ts(0),_endpointCount(0),_signatureLength(0) {}
 
+	/**
+	 * @return Timestamp (a.k.a. revision number) set by Location signer
+	 */
 	inline int64_t timestamp() const { return _ts; }
-	inline const Identity &id() const { return _id; }
 
 	/**
 	 * Create and sign a Locator
@@ -82,10 +56,6 @@ public:
 		if ((endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(!id.hasPrivate()))
 			return false;
 		_ts = ts;
-		_id = id;
-		if (_at)
-			delete [] _at;
-		_at = new Endpoint[endpointCount];
 		for(unsigned int i=0;i<endpointCount;++i)
 			_at[i] = at[i];
 		_endpointCount = endpointCount;
@@ -103,19 +73,21 @@ public:
 	/**
 	 * Verify this Locator's validity and signature
 	 *
+	 * @param id Identity corresponding to hash
 	 * @return True if valid and signature checks out
 	 */
-	inline bool verify() const
+	inline bool verify(const Identity &id) const
 	{
 		if ((_ts == 0)||(_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
 			return false;
 		uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
 		const unsigned int signLen = marshal(signData,true);
-		return _id.verify(signData,signLen,_signature,_signatureLength);
+		return id.verify(signData,signLen,_signature,_signatureLength);
 	}
 
 	inline operator bool() const { return (_ts != 0); }
 
+	// Marshal interface ///////////////////////////////////////////////////////
 	static inline int marshalSizeMax() { return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
 	inline int marshal(uint8_t restrict data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature = false) const
 	{
@@ -130,12 +102,9 @@ public:
 		data[5] = (uint8_t)((uint64_t)_ts >> 16);
 		data[6] = (uint8_t)((uint64_t)_ts >> 8);
 		data[7] = (uint8_t)((uint64_t)_ts);
+		int p = 8;
 
-		int p = _id.marshal(data + 8,false);
-		if (p <= 0)
-			return -1;
-		p += 8;
-
+		data[p++] = (uint8_t)(_endpointCount >> 8);
 		data[p++] = (uint8_t)_endpointCount;
 		for(unsigned int i=0;i<_endpointCount;++i) {
 			int tmp = _at[i].marshal(data + p);
@@ -155,7 +124,7 @@ public:
 	}
 	inline int unmarshal(const uint8_t *restrict data,const int len)
 	{
-		if (len <= 8)
+		if (len <= (8 + 48))
 			return -1;
 
 		uint64_t ts = ((uint64_t)data[0] << 56);
@@ -167,20 +136,16 @@ public:
 		ts |= ((uint64_t)data[6] << 8);
 		ts |= (uint64_t)data[7];
 		_ts = (int64_t)ts;
+		int p = 8;
 
-		int p = _id.unmarshal(data + 8,len - 8);
-		if (p <= 0)
-			return -1;
-		p += 8;
-
-		if (p >= len)
+		if ((p + 2) > len)
 			return -1;
 		unsigned int ec = (int)data[p++];
+		ec <<= 8;
+		ec |= data[p++];
 		if (ec > ZT_LOCATOR_MAX_ENDPOINTS)
 			return -1;
-		if (_at)
-			delete [] _at;
-		_at = new Endpoint[ec];
+		_endpointCount = ec;
 		for(int i=0;i<ec;++i) {
 			int tmp = _at[i].unmarshal(data + p,len - p);
 			if (tmp < 0)
@@ -203,13 +168,13 @@ public:
 
 		return p;
 	}
+	////////////////////////////////////////////////////////////////////////////
 
 private:
 	int64_t _ts;
-	Identity _id;
-	Endpoint *_at;
 	unsigned int _endpointCount;
 	unsigned int _signatureLength;
+	Endpoint _at[ZT_LOCATOR_MAX_ENDPOINTS];
 	uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
 };
 

+ 20 - 20
node/Mutex.hpp

@@ -28,24 +28,24 @@ namespace ZeroTier {
 class Mutex
 {
 public:
-	inline Mutex() { pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); }
-	inline ~Mutex() { pthread_mutex_destroy(&_mh); }
-	inline void lock() const { pthread_mutex_lock(&((const_cast <Mutex *> (this))->_mh)); }
-	inline void unlock() const { pthread_mutex_unlock(&((const_cast <Mutex *> (this))->_mh)); }
+	ZT_ALWAYS_INLINE Mutex() { pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); }
+	ZT_ALWAYS_INLINE ~Mutex() { pthread_mutex_destroy(&_mh); }
+	ZT_ALWAYS_INLINE void lock() const { pthread_mutex_lock(&((const_cast <Mutex *> (this))->_mh)); }
+	ZT_ALWAYS_INLINE void unlock() const { pthread_mutex_unlock(&((const_cast <Mutex *> (this))->_mh)); }
 
 	class Lock
 	{
 	public:
-		inline Lock(Mutex &m) : _m(&m) { m.lock(); }
-		inline Lock(const Mutex &m) : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
-		inline ~Lock() { _m->unlock(); }
+		ZT_ALWAYS_INLINE Lock(Mutex &m) : _m(&m) { m.lock(); }
+		ZT_ALWAYS_INLINE Lock(const Mutex &m) : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
+		ZT_ALWAYS_INLINE ~Lock() { _m->unlock(); }
 	private:
 		Mutex *const _m;
 	};
 
 private:
-	inline Mutex(const Mutex &) {}
-	const Mutex &operator=(const Mutex &) { return *this; }
+	ZT_ALWAYS_INLINE Mutex(const Mutex &) {}
+	ZT_ALWAYS_INLINE const Mutex &operator=(const Mutex &) { return *this; }
 
 	pthread_mutex_t _mh;
 };
@@ -65,26 +65,26 @@ namespace ZeroTier {
 class Mutex
 {
 public:
-	inline Mutex() { InitializeCriticalSection(&_cs); }
-	inline ~Mutex() { DeleteCriticalSection(&_cs); }
-	inline void lock() { EnterCriticalSection(&_cs); }
-	inline void unlock() { LeaveCriticalSection(&_cs); }
-	inline void lock() const { (const_cast <Mutex *> (this))->lock(); }
-	inline void unlock() const { (const_cast <Mutex *> (this))->unlock(); }
+	ZT_ALWAYS_INLINE Mutex() { InitializeCriticalSection(&_cs); }
+	ZT_ALWAYS_INLINE ~Mutex() { DeleteCriticalSection(&_cs); }
+	ZT_ALWAYS_INLINE void lock() { EnterCriticalSection(&_cs); }
+	ZT_ALWAYS_INLINE void unlock() { LeaveCriticalSection(&_cs); }
+	ZT_ALWAYS_INLINE void lock() const { (const_cast <Mutex *> (this))->lock(); }
+	ZT_ALWAYS_INLINE void unlock() const { (const_cast <Mutex *> (this))->unlock(); }
 
 	class Lock
 	{
 	public:
-		inline Lock(Mutex &m) : _m(&m) { m.lock(); }
-		inline Lock(const Mutex &m) : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
-		inline ~Lock() { _m->unlock(); }
+		ZT_ALWAYS_INLINE Lock(Mutex &m) : _m(&m) { m.lock(); }
+		ZT_ALWAYS_INLINE Lock(const Mutex &m) : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
+		ZT_ALWAYS_INLINE ~Lock() { _m->unlock(); }
 	private:
 		Mutex *const _m;
 	};
 
 private:
-	inline Mutex(const Mutex &) {}
-	const Mutex &operator=(const Mutex &) { return *this; }
+	ZT_ALWAYS_INLINE Mutex(const Mutex &) {}
+	ZT_ALWAYS_INLINE const Mutex &operator=(const Mutex &) { return *this; }
 
 	CRITICAL_SECTION _cs;
 };

+ 176 - 0
node/OS.hpp

@@ -0,0 +1,176 @@
+/*
+ * Copyright (c)2019 ZeroTier, Inc.
+ *
+ * Use of this software is governed by the Business Source License included
+ * in the LICENSE.TXT file in the project's root directory.
+ *
+ * Change Date: 2023-01-01
+ *
+ * On the date above, in accordance with the Business Source License, use
+ * of this software will be governed by version 2.0 of the Apache License.
+ */
+/****/
+
+#ifndef ZT_OS_HPP
+#define ZT_OS_HPP
+
+//
+// This include file also auto-detects and canonicalizes some environment
+// information defines:
+//
+// __LINUX__
+// __APPLE__
+// __BSD__ (OSX also defines this)
+// __UNIX_LIKE__ (Linux, BSD, etc.)
+// __WINDOWS__
+//
+// Also makes sure __BYTE_ORDER is defined reasonably.
+//
+
+// Hack: make sure __GCC__ is defined on old GCC compilers
+#ifndef __GCC__
+#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+#define __GCC__
+#endif
+#endif
+
+#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
+#ifndef __LINUX__
+#define __LINUX__
+#endif
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#include <endian.h>
+#endif
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#ifndef __BSD__
+#define __BSD__
+#endif
+#include <machine/endian.h>
+#endif
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#ifndef __BSD__
+#define __BSD__
+#endif
+#include <sys/endian.h>
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER _BYTE_ORDER
+#define __LITTLE_ENDIAN _LITTLE_ENDIAN
+#define __BIG_ENDIAN _BIG_ENDIAN
+#endif
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+#ifndef __WINDOWS__
+#define __WINDOWS__
+#endif
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#pragma warning(disable : 4290)
+#pragma warning(disable : 4996)
+#pragma warning(disable : 4101)
+#undef __UNIX_LIKE__
+#undef __BSD__
+#include <WinSock2.h>
+#include <Windows.h>
+#endif
+
+#ifdef __NetBSD__
+#ifndef RTF_MULTICAST
+#define RTF_MULTICAST 0x20000000
+#endif
+#endif
+
+// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86 and x86_64.
+#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
+#ifndef ZT_NO_TYPE_PUNNING
+#define ZT_NO_TYPE_PUNNING
+#endif
+#endif
+
+// Assume little endian if not defined on Mac and Windows as these don't run on any BE architectures.
+#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER))
+#undef __BYTE_ORDER
+#undef __LITTLE_ENDIAN
+#undef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#define __LITTLE_ENDIAN 1234
+#define __BYTE_ORDER 1234
+#endif
+#ifndef __BYTE_ORDER
+#include <endian.h>
+#endif
+
+#ifdef __WINDOWS__
+#define ZT_PATH_SEPARATOR '\\'
+#define ZT_PATH_SEPARATOR_S "\\"
+#define ZT_EOL_S "\r\n"
+#else
+#define ZT_PATH_SEPARATOR '/'
+#define ZT_PATH_SEPARATOR_S "/"
+#define ZT_EOL_S "\n"
+#endif
+
+#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
+#define ZT_ALWAYS_INLINE __attribute__((always_inline))
+#ifndef restrict
+#define restrict __restrict__
+#endif
+#ifndef likely
+#define likely(x) __builtin_expect((x),1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect((x),0)
+#endif
+#else /* not GCC-like */
+#ifndef restrict
+#define restrict
+#endif
+#ifndef likely
+#define inline inline
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif
+
+#if defined(__WINDOWS__) && !defined(__GNUC__) && !defined (__clang__) && !defined(__INTEL_COMPILER)
+#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
+#else
+#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
+#endif
+
+#if __cplusplus > 199711L
+#ifndef __CPP11__
+#define __CPP11__
+#endif
+#endif
+
+#ifdef SOCKET
+#define ZT_SOCKET SOCKET
+#else
+#define ZT_SOCKET int
+#endif
+#ifdef INVALID_SOCKET
+#define ZT_INVALID_SOCKET INVALID_SOCKET
+#else
+#define ZT_INVALID_SOCKET -1
+#endif
+
+#ifndef ZT_ALWAYS_INLINE
+#define ZT_ALWAYS_INLINE inline
+#endif
+
+#endif

+ 2 - 14
node/Packet.hpp

@@ -422,10 +422,10 @@ public:
 		 *   <[1] software minor version>
 		 *   <[2] software revision>
 		 *   <[8] timestamp for determining latency>
-		 *   <[...] binary serialized identity (see Identity)>
+		 *   <[...] binary serialized identity>
 		 *   <[...] physical destination address of packet>
 		 *   [... begin encrypted region ...]
-		 *   <[2] 16-bit reserved field, always 0>
+		 *   <[2] 16-bit reserved (legacy) field, always 0>
 		 *   <[2] 16-bit length of locator>
 		 *   <[...] locator for this node>
 		 *   <[2] 16-bit length of meta-data dictionary>
@@ -857,18 +857,6 @@ public:
 		 */
 		VERB_USER_MESSAGE = 0x14,
 
-		/**
-		 * A trace for remote debugging or diagnostics:
-		 *   <[...] null-terminated dictionary containing trace information>
-		 *  [<[...] additional null-terminated dictionaries>]
-		 *
-		 * This message contains a remote trace event. Remote trace events can
-		 * be sent to observers configured at the network level for those that
-		 * pertain directly to activity on a network, or to global observers if
-		 * locally configured.
-		 */
-		VERB_REMOTE_TRACE = 0x15,
-
 		/**
 		 * Peer-to-peer propagated multicast packet:
 		 *   <[128] 1024-bit bloom filter>

+ 26 - 0
node/Utils.cpp

@@ -67,6 +67,14 @@ namespace Utils {
 
 const char HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
 
+bool secureEq(const void *a,const void *b,unsigned int len)
+{
+	uint8_t diff = 0;
+	for(unsigned int i=0;i<len;++i)
+		diff |= ( (reinterpret_cast<const uint8_t *>(a))[i] ^ (reinterpret_cast<const uint8_t *>(b))[i] );
+	return (diff == 0);
+}
+
 // Crazy hack to force memory to be securely zeroed in spite of the best efforts of optimizing compilers.
 static void _Utils_doBurn(volatile uint8_t *ptr,unsigned int len)
 {
@@ -462,6 +470,24 @@ uint64_t random()
 	return result;
 }
 
+bool scopy(char *dest,unsigned int len,const char *src)
+{
+	if (!len)
+		return false; // sanity check
+	if (!src) {
+		*dest = (char)0;
+		return true;
+	}
+	char *const end = dest + len;
+	while ((*dest++ = *src++)) {
+		if (dest == end) {
+			*(--dest) = (char)0;
+			return false;
+		}
+	}
+	return true;
+}
+
 } // namespace Utils
 
 } // namespace ZeroTier

+ 41 - 63
node/Utils.hpp

@@ -44,13 +44,7 @@ const char HEXCHARS[16];
  * @param len Length of strings
  * @return True if strings are equal
  */
-inline bool secureEq(const void *a,const void *b,unsigned int len)
-{
-	uint8_t diff = 0;
-	for(unsigned int i=0;i<len;++i)
-		diff |= ( (reinterpret_cast<const uint8_t *>(a))[i] ^ (reinterpret_cast<const uint8_t *>(b))[i] );
-	return (diff == 0);
-}
+bool secureEq(const void *a,const void *b,unsigned int len);
 
 /**
  * Zero memory, ensuring to avoid any compiler optimizations or other things that may stop this.
@@ -148,7 +142,7 @@ void getSecureRandom(void *buf,unsigned int bytes);
 /**
  * Get a 64-bit unsigned secure random number
  */
-static inline uint64_t getSecureRandom64()
+static ZT_ALWAYS_INLINE uint64_t getSecureRandom64()
 {
 	uint64_t x;
 	getSecureRandom(&x,sizeof(x));
@@ -158,7 +152,7 @@ static inline uint64_t getSecureRandom64()
 int b32e(const uint8_t *data,int length,char *result,int bufSize);
 int b32d(const char *encoded, uint8_t *result, int bufSize);
 
-static inline unsigned int b64MaxEncodedSize(const unsigned int s) { return ((((s + 2) / 3) * 4) + 1); }
+static ZT_ALWAYS_INLINE unsigned int b64MaxEncodedSize(const unsigned int s) { return ((((s + 2) / 3) * 4) + 1); }
 unsigned int b64e(const uint8_t *in,unsigned int inlen,char *out,unsigned int outlen);
 unsigned int b64d(const char *in,uint8_t *out,unsigned int outlen);
 
@@ -167,7 +161,7 @@ unsigned int b64d(const char *in,uint8_t *out,unsigned int outlen);
  */
 uint64_t random();
 
-static inline float normalize(float value, int64_t bigMin, int64_t bigMax, int32_t targetMin, int32_t targetMax)
+static ZT_ALWAYS_INLINE float normalize(float value, int64_t bigMin, int64_t bigMax, int32_t targetMin, int32_t targetMax)
 {
 	int64_t bigSpan = bigMax - bigMin;
 	int64_t smallSpan = targetMax - targetMin;
@@ -182,7 +176,7 @@ static inline float normalize(float value, int64_t bigMin, int64_t bigMax, int32
  * @param delim Delimiters
  * @param saveptr Pointer to a char * for temporary reentrant storage
  */
-static inline char *stok(char *str,const char *delim,char **saveptr)
+static ZT_ALWAYS_INLINE char *stok(char *str,const char *delim,char **saveptr)
 {
 #ifdef __WINDOWS__
 	return strtok_s(str,delim,saveptr);
@@ -191,11 +185,11 @@ static inline char *stok(char *str,const char *delim,char **saveptr)
 #endif
 }
 
-static inline unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,10); }
-static inline int strToInt(const char *s) { return (int)strtol(s,(char **)0,10); }
-static inline unsigned long strToULong(const char *s) { return strtoul(s,(char **)0,10); }
-static inline long strToLong(const char *s) { return strtol(s,(char **)0,10); }
-static inline unsigned long long strToU64(const char *s)
+static ZT_ALWAYS_INLINE unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,10); }
+static ZT_ALWAYS_INLINE int strToInt(const char *s) { return (int)strtol(s,(char **)0,10); }
+static ZT_ALWAYS_INLINE unsigned long strToULong(const char *s) { return strtoul(s,(char **)0,10); }
+static ZT_ALWAYS_INLINE long strToLong(const char *s) { return strtol(s,(char **)0,10); }
+static ZT_ALWAYS_INLINE unsigned long long strToU64(const char *s)
 {
 #ifdef __WINDOWS__
 	return (unsigned long long)_strtoui64(s,(char **)0,10);
@@ -203,7 +197,7 @@ static inline unsigned long long strToU64(const char *s)
 	return strtoull(s,(char **)0,10);
 #endif
 }
-static inline long long strTo64(const char *s)
+static ZT_ALWAYS_INLINE long long strTo64(const char *s)
 {
 #ifdef __WINDOWS__
 	return (long long)_strtoi64(s,(char **)0,10);
@@ -211,11 +205,11 @@ static inline long long strTo64(const char *s)
 	return strtoll(s,(char **)0,10);
 #endif
 }
-static inline unsigned int hexStrToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,16); }
-static inline int hexStrToInt(const char *s) { return (int)strtol(s,(char **)0,16); }
-static inline unsigned long hexStrToULong(const char *s) { return strtoul(s,(char **)0,16); }
-static inline long hexStrToLong(const char *s) { return strtol(s,(char **)0,16); }
-static inline unsigned long long hexStrToU64(const char *s)
+static ZT_ALWAYS_INLINE unsigned int hexStrToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,16); }
+static ZT_ALWAYS_INLINE int hexStrToInt(const char *s) { return (int)strtol(s,(char **)0,16); }
+static ZT_ALWAYS_INLINE unsigned long hexStrToULong(const char *s) { return strtoul(s,(char **)0,16); }
+static ZT_ALWAYS_INLINE long hexStrToLong(const char *s) { return strtol(s,(char **)0,16); }
+static ZT_ALWAYS_INLINE unsigned long long hexStrToU64(const char *s)
 {
 #ifdef __WINDOWS__
 	return (unsigned long long)_strtoui64(s,(char **)0,16);
@@ -223,7 +217,7 @@ static inline unsigned long long hexStrToU64(const char *s)
 	return strtoull(s,(char **)0,16);
 #endif
 }
-static inline long long hexStrTo64(const char *s)
+static ZT_ALWAYS_INLINE long long hexStrTo64(const char *s)
 {
 #ifdef __WINDOWS__
 	return (long long)_strtoi64(s,(char **)0,16);
@@ -243,29 +237,13 @@ static inline long long hexStrTo64(const char *s)
  * @param src Source string (if NULL, dest will receive a zero-length string and true is returned)
  * @return True on success, false on overflow (buffer will still be 0-terminated)
  */
-static inline bool scopy(char *dest,unsigned int len,const char *src)
-{
-	if (!len)
-		return false; // sanity check
-	if (!src) {
-		*dest = (char)0;
-		return true;
-	}
-	char *const end = dest + len;
-	while ((*dest++ = *src++)) {
-		if (dest == end) {
-			*(--dest) = (char)0;
-			return false;
-		}
-	}
-	return true;
-}
+bool scopy(char *dest,unsigned int len,const char *src);
 
 #ifdef __GNUC__
-static inline unsigned int countBits(const uint8_t v) { return (unsigned int)__builtin_popcount((unsigned int)v); }
-static inline unsigned int countBits(const uint16_t v) { return (unsigned int)__builtin_popcount((unsigned int)v); }
-static inline unsigned int countBits(const uint32_t v) { return (unsigned int)__builtin_popcountl((unsigned long)v); }
-static inline unsigned int countBits(const uint64_t v) { return (unsigned int)__builtin_popcountll((unsigned long long)v); }
+static ZT_ALWAYS_INLINE unsigned int countBits(const uint8_t v) { return (unsigned int)__builtin_popcount((unsigned int)v); }
+static ZT_ALWAYS_INLINE unsigned int countBits(const uint16_t v) { return (unsigned int)__builtin_popcount((unsigned int)v); }
+static ZT_ALWAYS_INLINE unsigned int countBits(const uint32_t v) { return (unsigned int)__builtin_popcountl((unsigned long)v); }
+static ZT_ALWAYS_INLINE unsigned int countBits(const uint64_t v) { return (unsigned int)__builtin_popcountll((unsigned long long)v); }
 #else
 /**
  * Count the number of bits set in an integer
@@ -274,7 +252,7 @@ static inline unsigned int countBits(const uint64_t v) { return (unsigned int)__
  * @return Number of bits set in this integer (0-bits in integer)
  */
 template<typename T>
-static inline unsigned int countBits(T v)
+static ZT_ALWAYS_INLINE unsigned int countBits(T v)
 {
 	v = v - ((v >> 1) & (T)~(T)0/3);
 	v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);
@@ -285,11 +263,11 @@ static inline unsigned int countBits(T v)
 
 // Byte swappers for big/little endian conversion
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-static inline uint8_t hton(uint8_t n) { return n; }
-static inline int8_t hton(int8_t n) { return n; }
-static inline uint16_t hton(uint16_t n) { return htons(n); }
-static inline int16_t hton(int16_t n) { return (int16_t)Utils::hton((uint16_t)n); }
-static inline uint32_t hton(uint32_t n)
+static ZT_ALWAYS_INLINE uint8_t hton(uint8_t n) { return n; }
+static ZT_ALWAYS_INLINE int8_t hton(int8_t n) { return n; }
+static ZT_ALWAYS_INLINE uint16_t hton(uint16_t n) { return htons(n); }
+static ZT_ALWAYS_INLINE int16_t hton(int16_t n) { return (int16_t)Utils::hton((uint16_t)n); }
+static ZT_ALWAYS_INLINE uint32_t hton(uint32_t n)
 {
 #if defined(__GNUC__)
 #if defined(__FreeBSD__)
@@ -301,8 +279,8 @@ static inline uint32_t hton(uint32_t n)
 	return htonl(n);
 #endif
 }
-static inline int32_t hton(int32_t n) { return (int32_t)Utils::hton((uint32_t)n); }
-static inline uint64_t hton(uint64_t n)
+static ZT_ALWAYS_INLINE int32_t hton(int32_t n) { return (int32_t)Utils::hton((uint32_t)n); }
+static ZT_ALWAYS_INLINE uint64_t hton(uint64_t n)
 {
 #if defined(__GNUC__)
 #if defined(__FreeBSD__)
@@ -323,18 +301,18 @@ static inline uint64_t hton(uint64_t n)
 	);
 #endif
 }
-static inline int64_t hton(int64_t n) { return (int64_t)hton((uint64_t)n); }
+static ZT_ALWAYS_INLINE int64_t hton(int64_t n) { return (int64_t)hton((uint64_t)n); }
 #else
 template<typename T>
-static inline T hton(T n) { return n; }
+static ZT_ALWAYS_INLINE T hton(T n) { return n; }
 #endif
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-static inline uint8_t ntoh(uint8_t n) { return n; }
-static inline int8_t ntoh(int8_t n) { return n; }
-static inline uint16_t ntoh(uint16_t n) { return ntohs(n); }
-static inline int16_t ntoh(int16_t n) { return (int16_t)Utils::ntoh((uint16_t)n); }
-static inline uint32_t ntoh(uint32_t n)
+static ZT_ALWAYS_INLINE uint8_t ntoh(uint8_t n) { return n; }
+static ZT_ALWAYS_INLINE int8_t ntoh(int8_t n) { return n; }
+static ZT_ALWAYS_INLINE uint16_t ntoh(uint16_t n) { return ntohs(n); }
+static ZT_ALWAYS_INLINE int16_t ntoh(int16_t n) { return (int16_t)Utils::ntoh((uint16_t)n); }
+static ZT_ALWAYS_INLINE uint32_t ntoh(uint32_t n)
 {
 #if defined(__GNUC__)
 #if defined(__FreeBSD__)
@@ -346,8 +324,8 @@ static inline uint32_t ntoh(uint32_t n)
 	return ntohl(n);
 #endif
 }
-static inline int32_t ntoh(int32_t n) { return (int32_t)Utils::ntoh((uint32_t)n); }
-static inline uint64_t ntoh(uint64_t n)
+static ZT_ALWAYS_INLINE int32_t ntoh(int32_t n) { return (int32_t)Utils::ntoh((uint32_t)n); }
+static ZT_ALWAYS_INLINE uint64_t ntoh(uint64_t n)
 {
 #if defined(__GNUC__)
 #if defined(__FreeBSD__)
@@ -368,10 +346,10 @@ static inline uint64_t ntoh(uint64_t n)
 	);
 #endif
 }
-static inline int64_t ntoh(int64_t n) { return (int64_t)ntoh((uint64_t)n); }
+static ZT_ALWAYS_INLINE int64_t ntoh(int64_t n) { return (int64_t)ntoh((uint64_t)n); }
 #else
 template<typename T>
-static inline T ntoh(T n) { return n; }
+static ZT_ALWAYS_INLINE T ntoh(T n) { return n; }
 #endif
 
 } // namespace Utils