Adam Ierymenko 5 năm trước cách đây
mục cha
commit
627533cf48

+ 4 - 1
.gitignore

@@ -1,5 +1,8 @@
-build/
+/build
+/cmake-build-debug
+/cmake-build-release
 /version.h
+/.idea
 .DS_Store
 .Trashes
 *.swp

+ 1 - 6
.idea/ZeroTierOne.iml

@@ -1,9 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<module type="WEB_MODULE" version="4">
+<module classpath="CMake" type="WEB_MODULE" version="4">
   <component name="Go" enabled="true" />
-  <component name="NewModuleRootManager">
-    <content url="file://$MODULE_DIR$" />
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
 </module>

+ 1 - 0
.idea/misc.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
+  <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
   <component name="JavaScriptSettings">
     <option name="languageLevel" value="ES6" />
   </component>

+ 144 - 208
CMakeLists.txt

@@ -1,208 +1,144 @@
-cmake_minimum_required (VERSION 3.8)
-
-if(${CMAKE_VERSION} VERSION_LESS 3.15)
-	cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
-else()
-	cmake_policy(VERSION 3.15)
-endif()
-
-if(WIN32)
-	# If building on Windows, set minimum target to Windows 7
-	set(CMAKE_SYSTEM_VERSION "7" CACHE STRING INTERNAL FORCE)
-endif(WIN32)
-
-set(ZEROTIER_ONE_VERSION_MAJOR 2 CACHE INTERNAL "")
-set(ZEROTIER_ONE_VERSION_MINOR 0 CACHE INTERNAL "")
-set(ZEROTIER_ONE_VERSION_REVISION 0 CACHE INTERNAL "")
-set(ZEROTIER_ONE_VERSION_BUILD 0 CACHE INTERNAL "")
-
-set(default_build_type "Release")
-if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
-	set(default_build_type "Debug")
-endif()
-
-if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
-	message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
-	set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE
-		STRING "Choose the type of build." FORCE)
-	# Set the possible values of build type for cmake-gui
-	set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
-		"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
-endif()
-
-option(BUILD_CENTRAL_CONTROLLER "Build ZeroTier Central Controller" OFF)
-option(ZT_TRACE "Trace Messages" OFF)
-option(ZT_DEBUG_TRACE "Debug Trace Messages" OFF)
-
-if (BUILD_CENTRAL_CONTROLLER)
-	find_package(PostgreSQL REQUIRED)
-	set(ENABLE_SSL_SUPPORT OFF)
-	set(BUILD_SHARED_LIBS OFF)
-	set(BUILD_EXAMPLES OFF)
-	set(BUILD_TOOLS OFF)
-	set(BUILD_TESTS OFF)
-	set(BUILD_API_DOCS OFF)
-	add_subdirectory("ext/librabbitmq")
-endif(BUILD_CENTRAL_CONTROLLER)
-
-set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X Deployment Version")
-
-if(CMAKE_BUILD_TYPE STREQUAL "Debug")
-	add_definitions(-DZT_TRACE)
-endif(CMAKE_BUILD_TYPE STREQUAL "Debug")
-
-project(zerotier
-	DESCRIPTION "ZeroTier Network Hypervisor"
-	LANGUAGES CXX C)
-
-if(WIN32)
-	add_definitions(-DNOMINMAX)
-else(WIN32)
-	if(APPLE)
-
-		message("Setting macOS Compiler Flags ${CMAKE_BUILD_TYPE}")
-		add_compile_options(
-			-Wall
-			-Wno-deprecated
-			-mmacosx-version-min=10.9
-			$<$<CONFIG:Debug>:-g>
-			$<$<CONFIG:DEBUG>:-O0>
-			$<$<CONFIG:RELEASE>:-Ofast>
-			$<$<CONFIG:RELEASE>:-fPIE>
-			$<$<CONFIG:RELEASE>:-flto>
-			$<$<CONFIG:RELWITHDEBINFO>:-Ofast>
-			$<$<CONFIG:RELWITHDEBINFO>:-fPIE>
-			$<$<CONFIG:RELWITHDEBINFO>:-g>
-		)
-		add_link_options(
-			-mmacosx-version-min=10.9
-			$<$<CONFIG:RELEASE>:-flto>
-		)
-
-	elseif (
-		CMAKE_SYSTEM_NAME MATCHES "Linux" OR
-		CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR
-		CMAKE_SYSTEM_NAME MATCHES "OpenBSD" OR
-		CMAKE_SYSTEM_NAME MATCHES "NetBSD"
-	)
-
-		message("Setting Linux/BSD Compiler Flags (${CMAKE_BUILD_TYPE})")
-		add_compile_options(
-			-Wall
-			-Wno-deprecated
-			$<$<CONFIG:Debug>:-g>
-			$<$<CONFIG:DEBUG>:-O0>
-			$<$<CONFIG:RELEASE>:-O3>
-			$<$<CONFIG:RELEASE>:-fPIE>
-			$<$<CONFIG:RELWITHDEBINFO>:-O3>
-			$<$<CONFIG:RELWITHDEBINFO>:-fPIE>
-			$<$<CONFIG:RELWITHDEBINFO>:-g>
-		)
-
-	endif(APPLE)
-endif(WIN32)
-
-if (
-	CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR
-	CMAKE_SYSTEM_PROCESSOR MATCHES "amd64" OR
-	CMAKE_SYSTEM_PROCESSOR MATCHES "i386" OR
-	CMAKE_SYSTEM_PROCESSOR MATCHES "i486" OR
-	CMAKE_SYSTEM_PROCESSOR MATCHES "i586" OR
-	CMAKE_SYSTEM_PROCESSOR MATCHES "i686"
-)
-	message("Adding SSE and AES-NI flags for processor ${CMAKE_SYSTEM_PROCESSOR}")
-	add_compile_options(
-		-maes
-		-mmmx
-		-mrdrnd
-		-mpclmul
-		-msse
-		-msse2
-		-msse3
-		-msse4.1
-	)
-endif()
-
-if(ZT_TRACE)
-	add_definitions(-DZT_TRACE)
-endif()
-if(ZT_DEBUG_TRACE)
-	add_definitions(-DZT_DEBUG_TRACE)
-endif()
-
-add_subdirectory(node)
-add_subdirectory(controller)
-add_subdirectory(osdep)
-add_subdirectory(root)
-add_subdirectory(go/native)
-
-#if(WIN32)
-#	add_subdirectory("windows/WinUI")
-#	add_subdirectory("windows/copyutil")
-#	add_definitions(-DNOMINMAX)
-#endif(WIN32)
-
-set(
-	zt_osdep
-	zt_core
-	zt_controller
-	zt_go_native
-)
-
-configure_file(
-	${CMAKE_SOURCE_DIR}/version.h.in
-	${CMAKE_BINARY_DIR}/version.h
-)
-
-#set(src
-#	one.cpp
-#	"ext/http-parser/http_parser.c"
-#)
-#set(headers
-#	"ext/http-parser/http_parser.h"
-#)
-
-if(WIN32)
-	set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi)
-else(WIN32)
-	set(libs ${libs} pthread)
-endif(WIN32)
-
-#if(WIN32)
-#	set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi)
-#	set(src
-#		${src}
-#		"windows/ZeroTierOne/ServiceBase.cpp"
-#		"windows/ZeroTierOne/ServiceInstaller.cpp"
-#		"windows/ZeroTierOne/ZeroTierOneService.cpp"
-#		"windows/ZeroTierOne/ZeroTierOne.rc"
-#	)
-#	set(headers
-#		${headers}
-#		"windows/ZeroTierOne/ServiceBase.h"
-#		"windows/ZeroTierOne/ServiceInstaller.h"
-#		"windows/ZeroTierOne/ZeroTierOneService.h"
-#	)
-#else(WIN32)
-#	set(libs ${libs} pthread resolv)
-#endif(WIN32)
-
-#if(BUILD_CENTRAL_CONTROLLER)
-#	set(libs ${libs} rabbitmq-static ${PostgreSQL_LIBRARIES})
-#endif(BUILD_CENTRAL_CONTROLLER)
-
-#add_executable(${PROJECT_NAME} ${src} ${headers})
-#target_link_libraries(${PROJECT_NAME} ${libs})
-#target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR})
-
-add_custom_command(
-	OUTPUT zerotier
-	WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/go
-	COMMAND go build -trimpath -ldflags -s -o ../build/zerotier cmd/zerotier/zerotier.go
-	DEPENDS zt_osdep zt_core zt_go_native
-)
-add_custom_target(build_zerotier ALL DEPENDS zerotier)
-
-add_executable(zerotier-selftest selftest.cpp)
-target_link_libraries(zerotier-selftest ${libs} zt_core zt_osdep)
-target_compile_features(zerotier-selftest PUBLIC cxx_std_11)
+cmake_minimum_required(VERSION 3.15)
+project(ZeroTierOne)
+
+set(CMAKE_CXX_STANDARD 14)
+
+include_directories(controller)
+include_directories(ext)
+include_directories(ext/json)
+include_directories(include)
+include_directories(node)
+include_directories(osdep)
+include_directories(root)
+
+add_executable(ZeroTierOne
+        controller/CMakeLists.txt
+        controller/DB.cpp
+        controller/DB.hpp
+        controller/DBMirrorSet.cpp
+        controller/DBMirrorSet.hpp
+        controller/EmbeddedNetworkController.cpp
+        controller/EmbeddedNetworkController.hpp
+        controller/FileDB.cpp
+        controller/FileDB.hpp
+        controller/LFDB.cpp
+        controller/LFDB.hpp
+        controller/PostgreSQL.cpp
+        controller/PostgreSQL.hpp
+        controller/RabbitMQ.cpp
+        controller/RabbitMQ.hpp
+        ext/json/json.hpp
+        include/ZeroTierCore.h
+        include/ZeroTierDebug.h
+        node/Address.hpp
+        node/AES-aesni.c
+        node/AES.cpp
+        node/AES.hpp
+        node/AtomicCounter.hpp
+        node/Buffer.hpp
+        node/C25519.cpp
+        node/C25519.hpp
+        node/Capability.hpp
+        node/CertificateOfMembership.hpp
+        node/CertificateOfOwnership.hpp
+        node/CMakeLists.txt
+        node/Constants.hpp
+        node/Credential.cpp
+        node/Credential.hpp
+        node/Dictionary.hpp
+        node/ECC384.cpp
+        node/ECC384.hpp
+        node/Endpoint.hpp
+        node/Hashtable.hpp
+        node/Identity.cpp
+        node/Identity.hpp
+        node/IncomingPacket.cpp
+        node/IncomingPacket.hpp
+        node/InetAddress.cpp
+        node/InetAddress.hpp
+        node/Locator.hpp
+        node/MAC.hpp
+        node/Membership.cpp
+        node/Membership.hpp
+        node/Meter.hpp
+        node/MulticastGroup.hpp
+        node/Mutex.hpp
+        node/Network.cpp
+        node/Network.hpp
+        node/NetworkConfig.cpp
+        node/NetworkConfig.hpp
+        node/NetworkController.hpp
+        node/Node.cpp
+        node/Node.hpp
+        node/OS.hpp
+        node/Packet.cpp
+        node/Packet.hpp
+        node/Path.cpp
+        node/Path.hpp
+        node/Peer.cpp
+        node/Peer.hpp
+        node/Poly1305.cpp
+        node/Poly1305.hpp
+        node/README.md
+        node/Revocation.hpp
+        node/RingBuffer.hpp
+        node/RuntimeEnvironment.hpp
+        node/Salsa20.cpp
+        node/Salsa20.hpp
+        node/ScopedPtr.hpp
+        node/SelfAwareness.cpp
+        node/SelfAwareness.hpp
+        node/SHA512.cpp
+        node/SHA512.hpp
+        node/SharedPtr.hpp
+        node/Str.hpp
+        node/Switch.cpp
+        node/Switch.hpp
+        node/Tag.hpp
+        node/Topology.hpp
+        node/Trace.cpp
+        node/Trace.hpp
+        node/Utils.cpp
+        node/Utils.hpp
+        osdep/Arp.cpp
+        osdep/Arp.hpp
+        osdep/BlockingQueue.hpp
+        osdep/BSDEthernetTap.cpp
+        osdep/BSDEthernetTap.hpp
+        osdep/CMakeLists.txt
+        osdep/EthernetTap.cpp
+        osdep/EthernetTap.hpp
+        osdep/freebsd_getifmaddrs.c
+        osdep/freebsd_getifmaddrs.h
+        osdep/LinuxEthernetTap.cpp
+        osdep/LinuxEthernetTap.hpp
+        osdep/LinuxNetLink.cpp
+        osdep/LinuxNetLink.hpp
+        osdep/MacEthernetTap.cpp
+        osdep/MacEthernetTap.hpp
+        osdep/MacEthernetTapAgent.c
+        osdep/MacEthernetTapAgent.h
+        osdep/MacKextEthernetTap.cpp
+        osdep/MacKextEthernetTap.hpp
+        osdep/ManagedRoute.cpp
+        osdep/ManagedRoute.hpp
+        osdep/NeighborDiscovery.cpp
+        osdep/NeighborDiscovery.hpp
+        osdep/NetBSDEthernetTap.cpp
+        osdep/NetBSDEthernetTap.hpp
+        osdep/OSUtils.cpp
+        osdep/OSUtils.hpp
+        osdep/README.md
+        osdep/Thread.hpp
+        osdep/WindowsEthernetTap.cpp
+        osdep/WindowsEthernetTap.hpp
+        root/CMakeLists.txt
+        root/geoip-html.h
+        root/root.cpp
+        AUTHORS.md
+        CMakeLists.txt
+        LICENSE.txt
+        OFFICIAL-RELEASE-STEPS.md
+        README.md
+        RELEASE-NOTES.md
+        selftest.cpp)

+ 0 - 1
node/CMakeLists.txt

@@ -17,7 +17,6 @@ set(core_headers
 	Credential.hpp
 	Dictionary.hpp
 	ECC384.hpp
-	EphemeralKey.hpp
 	Hashtable.hpp
 	Identity.hpp
 	InetAddress.hpp

+ 6 - 50
node/Constants.hpp

@@ -31,11 +31,6 @@
  */
 #define ZT_ADDRESS_LENGTH 5
 
-/**
- * Length of a hexadecimal ZeroTier address
- */
-#define ZT_ADDRESS_LENGTH_HEX 10
-
 /**
  * Addresses beginning with this byte are reserved for the joy of in-band signaling
  */
@@ -131,30 +126,6 @@
  */
 #define ZT_MULTICAST_ANNOUNCE_PERIOD 60000
 
-/**
- * Period for multicast GATHER on multicast groups
- */
-#define ZT_MULTICAST_GATHER_PERIOD ZT_MULTICAST_ANNOUNCE_PERIOD
-
-/**
- * Period for multicast GATHER if there are no known recipients
- */
-#define ZT_MULTICAST_GATHER_PERIOD_WHEN_NO_RECIPIENTS 2500
-
-/**
- * Timeout for outgoing multicasts
- *
- * This is how long we wait for explicit or implicit gather results.
- */
-#define ZT_MULTICAST_TRANSMIT_TIMEOUT 5000
-
-/**
- * How frequently to check for changes to the system's network interfaces. When
- * the service decides to use this constant it's because we want to react more
- * quickly to new interfaces that pop up or go down.
- */
-#define ZT_MULTIPATH_BINDER_REFRESH_PERIOD 5000
-
 /**
  * Packets are only used for QoS/ACK statistical sampling if their packet ID is divisible by
  * this integer. This is to provide a mechanism for both peers to agree on which packets need
@@ -319,11 +290,6 @@
  */
 #define ZT_QOS_DEFAULT_BUCKET 0
 
-/**
- * Do not accept HELLOs over a given path more often than this
- */
-#define ZT_PATH_HELLO_RATE_LIMIT 1000
-
 /**
  * Delay between full-fledge pings of directly connected peers
  *
@@ -348,21 +314,6 @@
 #define ZT_PEER_ACTIVITY_TIMEOUT 30000
 #endif
 
-/**
- * Rescan for best/fastest root every N milliseconds
- */
-#define ZT_FIND_BEST_ROOT_PERIOD 2000
-
-/**
- * General rate limit timeout for multiple packet types (HELLO, etc.)
- */
-#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 500
-
-/**
- * General limit for max RTT for requests over the network
- */
-#define ZT_GENERAL_RTT_LIMIT 5000
-
 /**
  * Delay between requests for updated network autoconf information
  *
@@ -477,7 +428,7 @@
  */
 #define ZT_THREAD_MIN_STACK_SIZE 1048576
 
-// Internal cryptographic algorithm IDs
+// Internal cryptographic algorithm IDs (these match relevant identity types)
 #define ZT_CRYPTO_ALG_C25519 0
 #define ZT_CRYPTO_ALG_P384 1
 
@@ -491,4 +442,9 @@
 #define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN 202
 #define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203
 
+/* Ethernet frame types that might be relevant to us */
+#define ZT_ETHERTYPE_IPV4 0x0800
+#define ZT_ETHERTYPE_ARP 0x0806
+#define ZT_ETHERTYPE_IPV6 0x86dd
+
 #endif

+ 14 - 14
node/Endpoint.hpp

@@ -44,24 +44,24 @@ public:
 		ETHERNET = 5  // 48-bit LAN-local Ethernet address
 	};
 
-	inline Endpoint() { memset(reinterpret_cast<void *>(this),0,sizeof(Endpoint)); }
+	ZT_ALWAYS_INLINE Endpoint() { memset(reinterpret_cast<void *>(this),0,sizeof(Endpoint)); }
 
-	inline Endpoint(const InetAddress &sa) : _t(INETADDR) { _v.sa = sa; }
-	inline Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) : _t(ZEROTIER) { _v.zt.a = zt.toInt(); memcpy(_v.zt.idh,identityHash,ZT_IDENTITY_HASH_SIZE); }
-	inline Endpoint(const char *name,const int port) : _t(DNSNAME) { Utils::scopy(_v.dns.name,sizeof(_v.dns.name),name); _v.dns.port = port; }
-	inline Endpoint(const char *url) : _t(URL) { Utils::scopy(_v.url,sizeof(_v.url),url); }
+	ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) : _t(INETADDR) { _v.sa = sa; }
+	ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) : _t(ZEROTIER) { _v.zt.a = zt.toInt(); memcpy(_v.zt.idh,identityHash,ZT_IDENTITY_HASH_SIZE); }
+	ZT_ALWAYS_INLINE Endpoint(const char *name,const int port) : _t(DNSNAME) { Utils::scopy(_v.dns.name,sizeof(_v.dns.name),name); _v.dns.port = port; }
+	ZT_ALWAYS_INLINE Endpoint(const char *url) : _t(URL) { Utils::scopy(_v.url,sizeof(_v.url),url); }
 
-	inline const InetAddress *sockaddr() const { return (_t == INETADDR) ? reinterpret_cast<const InetAddress *>(&_v.sa) : nullptr; }
-	inline const char *dnsName() const { return (_t == DNSNAME) ? _v.dns.name : nullptr; }
-	inline const int dnsPort() const { return (_t == DNSNAME) ? _v.dns.port : -1; }
-	inline Address ztAddress() const { return (_t == ZEROTIER) ? Address(_v.zt.a) : Address(); }
-	inline const uint8_t *ztIdentityHash() const { return (_t == ZEROTIER) ? _v.zt.idh : nullptr; }
-	inline const char *url() const { return (_t == URL) ? _v.url : nullptr; }
-	inline MAC ethernet() const { return (_t == ETHERNET) ? MAC(_v.eth) : MAC(); }
+	ZT_ALWAYS_INLINE const InetAddress *sockaddr() const { return (_t == INETADDR) ? reinterpret_cast<const InetAddress *>(&_v.sa) : nullptr; }
+	ZT_ALWAYS_INLINE const char *dnsName() const { return (_t == DNSNAME) ? _v.dns.name : nullptr; }
+	ZT_ALWAYS_INLINE const int dnsPort() const { return (_t == DNSNAME) ? _v.dns.port : -1; }
+	ZT_ALWAYS_INLINE Address ztAddress() const { return (_t == ZEROTIER) ? Address(_v.zt.a) : Address(); }
+	ZT_ALWAYS_INLINE const uint8_t *ztIdentityHash() const { return (_t == ZEROTIER) ? _v.zt.idh : nullptr; }
+	ZT_ALWAYS_INLINE const char *url() const { return (_t == URL) ? _v.url : nullptr; }
+	ZT_ALWAYS_INLINE MAC ethernet() const { return (_t == ETHERNET) ? MAC(_v.eth) : MAC(); }
 
-	inline Type type() const { return _t; }
+	ZT_ALWAYS_INLINE Type type() const { return _t; }
 
-	static inline int marshalSizeMax() { return ZT_ENDPOINT_MARSHAL_SIZE_MAX; }
+	static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_ENDPOINT_MARSHAL_SIZE_MAX; }
 	inline int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const
 	{
 		int p;

+ 0 - 118
node/EphemeralKey.hpp

@@ -1,118 +0,0 @@
-/*
- * 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_EPHEMERALKEY_HPP
-#define ZT_EPHEMERALKEY_HPP
-
-#include "Constants.hpp"
-#include "C25519.hpp"
-#include "ECC384.hpp"
-#include "SHA512.hpp"
-#include "Buffer.hpp"
-#include "Utils.hpp"
-
-namespace ZeroTier {
-
-#define ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE (ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE)
-#define ZT_EPHEMERAL_KEY_TYPE_1_PRIVATE_SIZE (ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE)
-
-/**
- * An ephemeral key exchanged to implement forward secrecy
- *
- * This key includes both C25519 and ECC384 keys and key agreement executes
- * ECDH for both and hashes the results together. This should be able to be
- * FIPS compliant (if the C25519 portion is just considered a nonce) while
- * simultaneously being more secure than either curve alone.
- *
- * Serialization includes only the public portion since ephemeral private
- * keys are never shared or stored anywhere.
- */
-class EphemeralKey
-{
-public:
-	enum Type
-	{
-		NONE = 0,
-		C25519ECC384 = 1
-	};
-
-	inline EphemeralKey() : _priv(nullptr),_type(NONE) {}
-
-	inline ~EphemeralKey()
-	{
-		if (_priv) {
-			Utils::burn(_priv,ZT_EPHEMERAL_KEY_TYPE_1_PRIVATE_SIZE);
-			delete [] _priv;
-		}
-	}
-
-	inline Type type() const { return (Type)_type; }
-	inline bool hasPrivate() const { return (_priv != nullptr); }
-
-	inline void generate()
-	{
-		if (!_priv)
-			_priv = new uint8_t[ZT_EPHEMERAL_KEY_TYPE_1_PRIVATE_SIZE];
-		C25519::generate(_pub,_priv);
-		ECC384GenerateKey(_pub + ZT_C25519_PUBLIC_KEY_LEN,_priv + ZT_C25519_PRIVATE_KEY_LEN);
-		_type = C25519ECC384;
-	}
-
-	inline bool agree(const EphemeralKey &theirs,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const
-	{
-		if ((_priv)&&(_type == 1)) {
-			uint8_t rawkey[128],h[48];
-			C25519::agree(_priv,theirs._pub,rawkey);
-			ECC384ECDH(theirs._pub + ZT_C25519_PUBLIC_KEY_LEN,_priv + ZT_C25519_PRIVATE_KEY_LEN,rawkey + ZT_C25519_SHARED_KEY_LEN);
-			SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
-			memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
-			return true;
-		}
-		return false;
-	}
-
-	template<unsigned int C>
-	inline void serialize(Buffer<C> &b) const
-	{
-		b.append(_type);
-		if (_type == C25519ECC384)
-			b.append(_pub,ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE);
-	}
-
-	template<unsigned int C>
-	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
-	{
-		unsigned int p = startAt;
-		delete [] _priv;
-		_priv = nullptr;
-		switch(b[p++]) {
-			case C25519ECC384:
-				memcpy(_pub,b.field(p,ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE),ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE);
-				p += ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE;
-				break;
-			default:
-				_type = NONE;
-				break;
-		}
-		return (p - startAt);
-	}
-
-private:
-	uint8_t *_priv;
-	uint8_t _pub[ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE];
-	uint8_t _type;
-};
-
-} // namespace ZeroTier
-
-#endif

+ 16 - 16
node/Hashtable.hpp

@@ -33,10 +33,10 @@ class Hashtable
 private:
 	struct _Bucket
 	{
-		inline _Bucket(const K &k,const V &v) : k(k),v(v) {}
-		inline _Bucket(const K &k) : k(k),v() {}
-		inline _Bucket(const _Bucket &b) : k(b.k),v(b.v) {}
-		inline _Bucket &operator=(const _Bucket &b) { k = b.k; v = b.v; return *this; }
+		ZT_ALWAYS_INLINE _Bucket(const K &k,const V &v) : k(k),v(v) {}
+		ZT_ALWAYS_INLINE _Bucket(const K &k) : k(k),v() {}
+		ZT_ALWAYS_INLINE _Bucket(const _Bucket &b) : k(b.k),v(b.v) {}
+		ZT_ALWAYS_INLINE _Bucket &operator=(const _Bucket &b) { k = b.k; v = b.v; return *this; }
 		_Bucket *next; // must be set manually for each _Bucket
 		const K k;
 		V v;
@@ -56,7 +56,7 @@ public:
 		/**
 		 * @param ht Hash table to iterate over
 		 */
-		inline Iterator(Hashtable &ht) :
+		ZT_ALWAYS_INLINE Iterator(Hashtable &ht) :
 			_idx(0),
 			_ht(&ht),
 			_b(ht._t[0])
@@ -68,7 +68,7 @@ public:
 		 * @param vptr Pointer to set to point to next value
 		 * @return True if kptr and vptr are set, false if no more entries
 		 */
-		inline bool next(K *&kptr,V *&vptr)
+		ZT_ALWAYS_INLINE bool next(K *&kptr,V *&vptr)
 		{
 			for(;;) {
 				if (_b) {
@@ -358,23 +358,23 @@ public:
 	/**
 	 * @return Number of entries
 	 */
-	inline unsigned long size() const { return _s; }
+	ZT_ALWAYS_INLINE unsigned long size() const { return _s; }
 
 	/**
 	 * @return True if table is empty
 	 */
-	inline bool empty() const { return (_s == 0); }
+	ZT_ALWAYS_INLINE bool empty() const { return (_s == 0); }
 
 private:
 	template<typename O>
-	static inline unsigned long _hc(const O &obj) { return (unsigned long)obj.hashCode(); }
-
-	static inline unsigned long _hc(const uint64_t i) { return (unsigned long)(i ^ (i >> 32)); }
-	static inline unsigned long _hc(const uint32_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
-	static inline unsigned long _hc(const uint16_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
-	static inline unsigned long _hc(const int i) { return ((unsigned long)i * (unsigned long)0x9e3379b1); }
-	static inline unsigned long _hc(void *p) { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
-	static inline unsigned long _hc(const void *p) { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
+	static ZT_ALWAYS_INLINE unsigned long _hc(const O &obj) { return (unsigned long)obj.hashCode(); }
+
+	static ZT_ALWAYS_INLINE unsigned long _hc(const uint64_t i) { return (unsigned long)(i ^ (i >> 32)); }
+	static ZT_ALWAYS_INLINE unsigned long _hc(const uint32_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
+	static ZT_ALWAYS_INLINE unsigned long _hc(const uint16_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
+	static ZT_ALWAYS_INLINE unsigned long _hc(const int i) { return ((unsigned long)i * (unsigned long)0x9e3379b1); }
+	static ZT_ALWAYS_INLINE unsigned long _hc(void *p) { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
+	static ZT_ALWAYS_INLINE unsigned long _hc(const void *p) { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
 
 	inline void _grow()
 	{

+ 4 - 4
node/IncomingPacket.hpp

@@ -46,7 +46,7 @@ class Network;
 class IncomingPacket : public Packet
 {
 public:
-	inline IncomingPacket() : Packet(),_receiveTime(0),_path() {}
+	ZT_ALWAYS_INLINE IncomingPacket() : Packet(),_receiveTime(0),_path() {}
 
 	/**
 	 * Create a new packet-in-decode
@@ -57,7 +57,7 @@ public:
 	 * @param now Current time
 	 * @throws std::out_of_range Range error processing packet
 	 */
-	inline IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) :
+	ZT_ALWAYS_INLINE IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) :
 		Packet(data,len),
 		_receiveTime(now),
 		_path(path)
@@ -73,7 +73,7 @@ public:
 	 * @param now Current time
 	 * @throws std::out_of_range Range error processing packet
 	 */
-	inline void init(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now)
+	ZT_ALWAYS_INLINE void init(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now)
 	{
 		copyFrom(data,len);
 		_receiveTime = now;
@@ -98,7 +98,7 @@ public:
 	/**
 	 * @return Time of packet receipt / start of decode
 	 */
-	inline uint64_t receiveTime() const { return _receiveTime; }
+	ZT_ALWAYS_INLINE uint64_t receiveTime() const { return _receiveTime; }
 
 private:
 	uint64_t _receiveTime;

+ 51 - 55
node/InetAddress.hpp

@@ -75,59 +75,55 @@ struct InetAddress : public sockaddr_storage
 		IP_SCOPE_PRIVATE = 7        // 10.x.x.x, 192.168.x.x, etc.
 	};
 
-	// Can be used with the unordered maps and sets in c++11. We don't use C++11 in the core
-	// but this is safe to put here.
-	struct Hasher
-	{
-		inline std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); }
-	};
-
-	inline InetAddress() { memset(this,0,sizeof(InetAddress)); }
-	inline InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); }
-	inline InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); }
-	inline InetAddress(const struct sockaddr_storage &ss) { *this = ss; }
-	inline InetAddress(const struct sockaddr_storage *ss) { *this = ss; }
-	inline InetAddress(const struct sockaddr &sa) { *this = sa; }
-	inline InetAddress(const struct sockaddr *sa) { *this = sa; }
-	inline InetAddress(const struct sockaddr_in &sa) { *this = sa; }
-	inline InetAddress(const struct sockaddr_in *sa) { *this = sa; }
-	inline InetAddress(const struct sockaddr_in6 &sa) { *this = sa; }
-	inline InetAddress(const struct sockaddr_in6 *sa) { *this = sa; }
-	inline InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) { this->set(ipBytes,ipLen,port); }
-	inline InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); }
-	inline InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); }
-
-	inline void clear() { memset(this,0,sizeof(InetAddress)); }
-
-	inline InetAddress &operator=(const InetAddress &a)
+	// Hasher for unordered sets and maps in C++11
+	struct Hasher { ZT_ALWAYS_INLINE std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); } };
+
+	ZT_ALWAYS_INLINE InetAddress() { memset(this,0,sizeof(InetAddress)); }
+	ZT_ALWAYS_INLINE InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); }
+	ZT_ALWAYS_INLINE InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); }
+	ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage &ss) { *this = ss; }
+	ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage *ss) { *this = ss; }
+	ZT_ALWAYS_INLINE InetAddress(const struct sockaddr &sa) { *this = sa; }
+	ZT_ALWAYS_INLINE InetAddress(const struct sockaddr *sa) { *this = sa; }
+	ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in &sa) { *this = sa; }
+	ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in *sa) { *this = sa; }
+	ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 &sa) { *this = sa; }
+	ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 *sa) { *this = sa; }
+	ZT_ALWAYS_INLINE InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) { this->set(ipBytes,ipLen,port); }
+	ZT_ALWAYS_INLINE InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); }
+	ZT_ALWAYS_INLINE InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); }
+
+	ZT_ALWAYS_INLINE void clear() { memset(this,0,sizeof(InetAddress)); }
+
+	ZT_ALWAYS_INLINE InetAddress &operator=(const InetAddress &a)
 	{
 		if (&a != this)
 			memcpy(this,&a,sizeof(InetAddress));
 		return *this;
 	}
 
-	inline InetAddress &operator=(const InetAddress *a)
+	ZT_ALWAYS_INLINE InetAddress &operator=(const InetAddress *a)
 	{
 		if (a != this)
 			memcpy(this,a,sizeof(InetAddress));
 		return *this;
 	}
 
-	inline InetAddress &operator=(const struct sockaddr_storage &ss)
+	ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage &ss)
 	{
 		if (reinterpret_cast<const InetAddress *>(&ss) != this)
 			memcpy(this,&ss,sizeof(InetAddress));
 		return *this;
 	}
 
-	inline InetAddress &operator=(const struct sockaddr_storage *ss)
+	ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage *ss)
 	{
 		if (reinterpret_cast<const InetAddress *>(ss) != this)
 			memcpy(this,ss,sizeof(InetAddress));
 		return *this;
 	}
 
-	inline InetAddress &operator=(const struct sockaddr_in &sa)
+	ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in &sa)
 	{
 		if (reinterpret_cast<const InetAddress *>(&sa) != this) {
 			memset(this,0,sizeof(InetAddress));
@@ -136,7 +132,7 @@ struct InetAddress : public sockaddr_storage
 		return *this;
 	}
 
-	inline InetAddress &operator=(const struct sockaddr_in *sa)
+	ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in *sa)
 	{
 		if (reinterpret_cast<const InetAddress *>(sa) != this) {
 			memset(this,0,sizeof(InetAddress));
@@ -145,7 +141,7 @@ struct InetAddress : public sockaddr_storage
 		return *this;
 	}
 
-	inline InetAddress &operator=(const struct sockaddr_in6 &sa)
+	ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 &sa)
 	{
 		if (reinterpret_cast<const InetAddress *>(&sa) != this) {
 			memset(this,0,sizeof(InetAddress));
@@ -154,7 +150,7 @@ struct InetAddress : public sockaddr_storage
 		return *this;
 	}
 
-	inline InetAddress &operator=(const struct sockaddr_in6 *sa)
+	ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 *sa)
 	{
 		if (reinterpret_cast<const InetAddress *>(sa) != this) {
 			memset(this,0,sizeof(InetAddress));
@@ -163,7 +159,7 @@ struct InetAddress : public sockaddr_storage
 		return *this;
 	}
 
-	inline InetAddress &operator=(const struct sockaddr &sa)
+	ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr &sa)
 	{
 		if (reinterpret_cast<const InetAddress *>(&sa) != this) {
 			memset(this,0,sizeof(InetAddress));
@@ -179,7 +175,7 @@ struct InetAddress : public sockaddr_storage
 		return *this;
 	}
 
-	inline InetAddress &operator=(const struct sockaddr *sa)
+	ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr *sa)
 	{
 		if (reinterpret_cast<const InetAddress *>(sa) != this) {
 			memset(this,0,sizeof(InetAddress));
@@ -214,7 +210,7 @@ struct InetAddress : public sockaddr_storage
 	 *
 	 * @param port Port, 0 to 65535
 	 */
-	inline void setPort(unsigned int port)
+	ZT_ALWAYS_INLINE void setPort(unsigned int port)
 	{
 		switch(ss_family) {
 			case AF_INET:
@@ -229,7 +225,7 @@ struct InetAddress : public sockaddr_storage
 	/**
 	 * @return True if this network/netmask route describes a default route (e.g. 0.0.0.0/0)
 	 */
-	inline bool isDefaultRoute() const
+	ZT_ALWAYS_INLINE bool isDefaultRoute() const
 	{
 		switch(ss_family) {
 			case AF_INET:
@@ -264,7 +260,7 @@ struct InetAddress : public sockaddr_storage
 	/**
 	 * @return Port or 0 if no port component defined
 	 */
-	inline unsigned int port() const
+	ZT_ALWAYS_INLINE unsigned int port() const
 	{
 		switch(ss_family) {
 			case AF_INET: return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port));
@@ -282,12 +278,12 @@ struct InetAddress : public sockaddr_storage
 	 *
 	 * @return Netmask bits
 	 */
-	inline unsigned int netmaskBits() const { return port(); }
+	ZT_ALWAYS_INLINE unsigned int netmaskBits() const { return port(); }
 
 	/**
 	 * @return True if netmask bits is valid for the address type
 	 */
-	inline bool netmaskBitsValid() const
+	ZT_ALWAYS_INLINE bool netmaskBitsValid() const
 	{
 		const unsigned int n = port();
 		switch(ss_family) {
@@ -305,7 +301,7 @@ struct InetAddress : public sockaddr_storage
 	 *
 	 * @return Gateway metric
 	 */
-	inline unsigned int metric() const { return port(); }
+	ZT_ALWAYS_INLINE unsigned int metric() const { return port(); }
 
 	/**
 	 * Construct a full netmask as an InetAddress
@@ -350,17 +346,17 @@ struct InetAddress : public sockaddr_storage
 	/**
 	 * @return True if this is an IPv4 address
 	 */
-	inline bool isV4() const { return (ss_family == AF_INET); }
+	ZT_ALWAYS_INLINE bool isV4() const { return (ss_family == AF_INET); }
 
 	/**
 	 * @return True if this is an IPv6 address
 	 */
-	inline bool isV6() const { return (ss_family == AF_INET6); }
+	ZT_ALWAYS_INLINE bool isV6() const { return (ss_family == AF_INET6); }
 
 	/**
 	 * @return pointer to raw address bytes or NULL if not available
 	 */
-	inline const void *rawIpData() const
+	ZT_ALWAYS_INLINE const void *rawIpData() const
 	{
 		switch(ss_family) {
 			case AF_INET: return (const void *)&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
@@ -372,7 +368,7 @@ struct InetAddress : public sockaddr_storage
 	/**
 	 * @return InetAddress containing only the IP portion of this address and a zero port, or NULL if not IPv4 or IPv6
 	 */
-	inline InetAddress ipOnly() const
+	ZT_ALWAYS_INLINE InetAddress ipOnly() const
 	{
 		InetAddress r;
 		switch(ss_family) {
@@ -394,7 +390,7 @@ struct InetAddress : public sockaddr_storage
 	 * @param a InetAddress to compare again
 	 * @return True if only IP portions are equal (false for non-IP or null addresses)
 	 */
-	inline bool ipsEqual(const InetAddress &a) const
+	ZT_ALWAYS_INLINE bool ipsEqual(const InetAddress &a) const
 	{
 		if (ss_family == a.ss_family) {
 			if (ss_family == AF_INET)
@@ -414,7 +410,7 @@ struct InetAddress : public sockaddr_storage
 	 * @param a InetAddress to compare again
 	 * @return True if only IP portions are equal (false for non-IP or null addresses)
 	 */
-	inline bool ipsEqual2(const InetAddress &a) const
+	ZT_ALWAYS_INLINE bool ipsEqual2(const InetAddress &a) const
 	{
 		if (ss_family == a.ss_family) {
 			if (ss_family == AF_INET)
@@ -426,7 +422,7 @@ struct InetAddress : public sockaddr_storage
 		return false;
 	}
 
-	inline unsigned long hashCode() const
+	ZT_ALWAYS_INLINE unsigned long hashCode() const
 	{
 		if (ss_family == AF_INET) {
 			return ((unsigned long)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast<const struct sockaddr_in *>(this)->sin_port);
@@ -448,7 +444,7 @@ struct InetAddress : public sockaddr_storage
 	/**
 	 * Set to null/zero
 	 */
-	inline void zero() { memset(this,0,sizeof(InetAddress)); }
+	ZT_ALWAYS_INLINE void zero() { memset(this,0,sizeof(InetAddress)); }
 
 	/**
 	 * Check whether this is a network/route rather than an IP assignment
@@ -463,7 +459,7 @@ struct InetAddress : public sockaddr_storage
 	/**
 	 * @return 14-bit (0-16383) hash of this IP's first 24 or 48 bits (for V4 or V6) for rate limiting code, or 0 if non-IP
 	 */
-	inline unsigned long rateGateHash() const
+	ZT_ALWAYS_INLINE unsigned long rateGateHash() const
 	{
 		unsigned long h = 0;
 		switch(ss_family) {
@@ -487,10 +483,10 @@ struct InetAddress : public sockaddr_storage
 	/**
 	 * @return True if address family is non-zero
 	 */
-	inline operator bool() const { return (ss_family != 0); }
+	ZT_ALWAYS_INLINE operator bool() const { return (ss_family != 0); }
 
 	// Marshal interface ///////////////////////////////////////////////////////
-	static inline int marshalSizeMax() { return 19; }
+	static ZT_ALWAYS_INLINE int marshalSizeMax() { return 19; }
 	inline int marshal(uint8_t restrict data[19]) const
 	{
 		switch(ss_family) {
@@ -608,10 +604,10 @@ struct InetAddress : public sockaddr_storage
 
 	bool operator==(const InetAddress &a) const;
 	bool operator<(const InetAddress &a) const;
-	inline bool operator!=(const InetAddress &a) const { return !(*this == a); }
-	inline bool operator>(const InetAddress &a) const { return (a < *this); }
-	inline bool operator<=(const InetAddress &a) const { return !(a < *this); }
-	inline bool operator>=(const InetAddress &a) const { return !(*this < a); }
+	ZT_ALWAYS_INLINE bool operator!=(const InetAddress &a) const { return !(*this == a); }
+	ZT_ALWAYS_INLINE bool operator>(const InetAddress &a) const { return (a < *this); }
+	ZT_ALWAYS_INLINE bool operator<=(const InetAddress &a) const { return !(a < *this); }
+	ZT_ALWAYS_INLINE bool operator>=(const InetAddress &a) const { return !(*this < a); }
 
 	/**
 	 * @param mac MAC address seed

+ 4 - 4
node/Locator.hpp

@@ -35,12 +35,12 @@ namespace ZeroTier {
 class Locator
 {
 public:
-	inline Locator() : _ts(0),_endpointCount(0),_signatureLength(0) {}
+	ZT_ALWAYS_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; }
+	ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
 
 	/**
 	 * Create and sign a Locator
@@ -85,10 +85,10 @@ public:
 		return id.verify(signData,signLen,_signature,_signatureLength);
 	}
 
-	inline operator bool() const { return (_ts != 0); }
+	ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); }
 
 	// Marshal interface ///////////////////////////////////////////////////////
-	static inline int marshalSizeMax() { return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
+	static ZT_ALWAYS_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
 	{
 		if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))

+ 1 - 1
node/MAC.hpp

@@ -187,7 +187,7 @@ public:
 
 	ZT_ALWAYS_INLINE unsigned long hashCode() const { return (unsigned long)_m; }
 
-	ZT_ALWAYS_INLINE char *toString(char buf[18]) const
+	inline char *toString(char buf[18]) const
 	{
 		buf[0] = Utils::HEXCHARS[(_m >> 44) & 0xf];
 		buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf];

+ 3 - 3
node/Meter.hpp

@@ -29,7 +29,7 @@ namespace ZeroTier {
 class Meter
 {
 public:
-	inline Meter()
+	ZT_ALWAYS_INLINE Meter()
 	{
 		for(int i=0;i<ZT_METER_HISTORY_LENGTH;++i)
 			_history[i] = 0.0;
@@ -38,7 +38,7 @@ public:
 	}
 
 	template<typename I>
-	inline void log(const int64_t now,I count)
+	ZT_ALWAYS_INLINE void log(const int64_t now,I count)
 	{
 		const int64_t since = now - _ts;
 		if (since >= ZT_METER_HISTORY_TICK_DURATION) {
@@ -50,7 +50,7 @@ public:
 		}
 	}
 
-	inline double perSecond(const int64_t now) const
+	ZT_ALWAYS_INLINE double perSecond(const int64_t now) const
 	{
 		double r = 0.0,n = 0.0;
 		const int64_t since = (now - _ts);

+ 12 - 33
node/MulticastGroup.hpp

@@ -41,8 +41,8 @@ namespace ZeroTier {
 class MulticastGroup
 {
 public:
-	inline MulticastGroup() : _mac(),_adi(0) {}
-	inline MulticastGroup(const MAC &m,uint32_t a) : _mac(m),_adi(a) {}
+	ZT_ALWAYS_INLINE MulticastGroup() : _mac(),_adi(0) {}
+	ZT_ALWAYS_INLINE MulticastGroup(const MAC &m,uint32_t a) : _mac(m),_adi(a) {}
 
 	/**
 	 * Derive the multicast group used for address resolution (ARP/NDP) for an IP
@@ -50,7 +50,7 @@ public:
 	 * @param ip IP address (port field is ignored)
 	 * @return Multicast group for ARP/NDP
 	 */
-	static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip)
+	static ZT_ALWAYS_INLINE MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip)
 	{
 		if (ip.isV4()) {
 			// IPv4 wants broadcast MACs, so we shove the V4 address itself into
@@ -72,37 +72,16 @@ public:
 	/**
 	 * @return Ethernet MAC portion of multicast group
 	 */
-	inline const MAC &mac() const { return _mac; }
+	ZT_ALWAYS_INLINE const MAC &mac() const { return _mac; }
 
 	/**
 	 * @return Additional distinguishing information, which is normally zero except for IPv4 ARP where it's the IPv4 address
 	 */
-	inline uint32_t adi() const { return _adi; }
+	ZT_ALWAYS_INLINE uint32_t adi() const { return _adi; }
 
-	/**
-	 * @return 32-bit non-cryptographic hash ID of this multicast group
-	 */
-	inline uint32_t id() const
-	{
-		uint64_t m = _mac.toInt();
-		uint32_t x1 = _adi;
-		uint32_t x2 = (uint32_t)(m >> 32);
-		uint32_t x3 = (uint32_t)m;
-		x1 = ((x1 >> 16) ^ x1) * 0x45d9f3b;
-		x2 = ((x2 >> 16) ^ x2) * 0x45d9f3b;
-		x3 = ((x3 >> 16) ^ x3) * 0x45d9f3b;
-		x1 = ((x1 >> 16) ^ x1) * 0x45d9f3b;
-		x2 = ((x2 >> 16) ^ x2) * 0x45d9f3b;
-		x3 = ((x3 >> 16) ^ x3) * 0x45d9f3b;
-		x1 = (x1 >> 16) ^ x1;
-		x2 = (x2 >> 16) ^ x2;
-		x3 = (x3 >> 16) ^ x3;
-		return (x1 ^ x2 ^ x3);
-	}
-
-	inline bool operator==(const MulticastGroup &g) const { return ((_mac == g._mac)&&(_adi == g._adi)); }
-	inline bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); }
-	inline bool operator<(const MulticastGroup &g) const
+	ZT_ALWAYS_INLINE bool operator==(const MulticastGroup &g) const { return ((_mac == g._mac)&&(_adi == g._adi)); }
+	ZT_ALWAYS_INLINE bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); }
+	ZT_ALWAYS_INLINE bool operator<(const MulticastGroup &g) const
 	{
 		if (_mac < g._mac)
 			return true;
@@ -110,11 +89,11 @@ public:
 			return (_adi < g._adi);
 		return false;
 	}
-	inline bool operator>(const MulticastGroup &g) const { return (g < *this); }
-	inline bool operator<=(const MulticastGroup &g) const { return !(g < *this); }
-	inline bool operator>=(const MulticastGroup &g) const { return !(*this < g); }
+	ZT_ALWAYS_INLINE bool operator>(const MulticastGroup &g) const { return (g < *this); }
+	ZT_ALWAYS_INLINE bool operator<=(const MulticastGroup &g) const { return !(g < *this); }
+	ZT_ALWAYS_INLINE bool operator>=(const MulticastGroup &g) const { return !(*this < g); }
 
-	inline unsigned long hashCode() const { return (_mac.hashCode() ^ (unsigned long)_adi); }
+	ZT_ALWAYS_INLINE unsigned long hashCode() const { return (_mac.hashCode() ^ (unsigned long)_adi); }
 
 private:
 	MAC _mac;

+ 18 - 8
node/Switch.cpp

@@ -125,6 +125,8 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
 					return;
 
 				if (destination != RR->identity.address()) {
+					// This packet is not for this node, so possibly relay it ----------
+
 					Packet packet(data,len);
 					if (packet.hops() < ZT_RELAY_MAX_HOPS) {
 						packet.incrementHops();
@@ -146,8 +148,9 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
 							}
 						}
 					}
+
 				} else if ((reinterpret_cast<const uint8_t *>(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) {
-					// Packet is the head of a fragmented packet series
+					// Packet is the head of a fragmented packet series ----------------
 
 					const uint64_t packetId = (
 						(((uint64_t)reinterpret_cast<const uint8_t *>(data)[0]) << 56) |
@@ -172,10 +175,10 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
 						rq->haveFragments = 1;
 						rq->complete = false;
 					} else if (!(rq->haveFragments & 1)) {
-						// If we have other fragments but no head, see if we are complete with the head
+						// Check if packet is complete -----------------------------------
 
 						if ((rq->totalFragments > 1)&&(Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) {
-							// We have all fragments -- assemble and process full Packet
+							// We have all fragments -- assemble and process full Packet ---
 
 							rq->frag0.init(data,len,path,now);
 							for(unsigned int f=1;f<rq->totalFragments;++f)
@@ -186,13 +189,17 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
 							} else {
 								rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something
 							}
+
 						} else {
-							// Still waiting on more fragments, but keep the head
+							// Still waiting on more fragments, but keep the head ----------
+
 							rq->frag0.init(data,len,path,now);
+
 						}
 					} // else this is a duplicate head, ignore
 				} else {
-					// Packet is unfragmented, so just process it
+
+					// Packet is unfragmented, so just process it ----------------------
 					IncomingPacket packet(data,len,path,now);
 					if (!packet.tryDecode(RR,tPtr)) {
 						RXQueueEntry *const rq = _nextRXQueueEntry();
@@ -204,6 +211,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
 						rq->haveFragments = 1;
 						rq->complete = true;
 					}
+
 				}
 
 				// --------------------------------------------------------------------
@@ -364,10 +372,12 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
 			len);
 		*/
 	} else if (to == network->mac()) {
-		// Destination is this node, so just reinject it
+		// Destination is this node, so just reinject it -------------------------
+
 		RR->node->putFrame(tPtr,network->id(),network->userPtr(),from,to,etherType,vlanId,data,len);
+
 	} else if (to[0] == MAC::firstOctetForNetwork(network->id())) {
-		// Destination is another ZeroTier peer on the same network
+		// Destination is another ZeroTier peer on the same network --------------
 
 		Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this
 		SharedPtr<Peer> toPeer(RR->topology->get(toZT));
@@ -400,7 +410,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
 			aqm_enqueue(tPtr,network,outp,true,qosBucket);
 		}
 	} else {
-		// Destination is bridged behind a remote peer
+		// Destination is bridged behind a remote peer ---------------------------
 
 		// We filter with a NULL destination ZeroTier address first. Filtrations
 		// for each ZT destination are also done below. This is the same rationale

+ 0 - 10
node/Switch.hpp

@@ -31,16 +31,6 @@
 #include "IncomingPacket.hpp"
 #include "Hashtable.hpp"
 
-/* Ethernet frame types that might be relevant to us */
-#define ZT_ETHERTYPE_IPV4 0x0800
-#define ZT_ETHERTYPE_ARP 0x0806
-#define ZT_ETHERTYPE_RARP 0x8035
-#define ZT_ETHERTYPE_ATALK 0x809b
-#define ZT_ETHERTYPE_AARP 0x80f3
-#define ZT_ETHERTYPE_IPX_A 0x8137
-#define ZT_ETHERTYPE_IPX_B 0x8138
-#define ZT_ETHERTYPE_IPV6 0x86dd
-
 namespace ZeroTier {
 
 class RuntimeEnvironment;

+ 2 - 2
node/Topology.hpp

@@ -161,7 +161,7 @@ public:
 	 * @tparam F Function or function object type
 	 */
 	template<typename F>
-	inline void eachPeer(F f)
+	ZT_ALWAYS_INLINE void eachPeer(F f)
 	{
 		Mutex::Lock l(_peers_l);
 		Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
@@ -191,7 +191,7 @@ public:
 	/**
 	 * @param allPeers vector to fill with all current peers
 	 */
-	inline void getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const
+	ZT_ALWAYS_INLINE void getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const
 	{
 		Mutex::Lock l(_peers_l);
 		allPeers.clear();

+ 24 - 60
node/Utils.cpp

@@ -107,40 +107,7 @@ char *decimal(unsigned long n,char s[24])
 
 unsigned short crc16(const void *buf,unsigned int len)
 {
-	static const uint16_t crc16tab[256]= {
-		0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
-		0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
-		0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
-		0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
-		0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
-		0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
-		0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
-		0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
-		0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
-		0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
-		0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
-		0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
-		0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
-		0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
-		0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
-		0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
-		0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
-		0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
-		0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
-		0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
-		0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
-		0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
-		0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
-		0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
-		0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
-		0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
-		0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
-		0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
-		0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
-		0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
-		0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
-		0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
-	};
+	static const uint16_t crc16tab[256]= { 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 };
 	uint16_t crc = 0;
 	const uint8_t *p = (const uint8_t *)buf;
 	for(unsigned int i=0;i<len;++i)
@@ -148,35 +115,32 @@ unsigned short crc16(const void *buf,unsigned int len)
 	return crc;
 }
 
-unsigned int unhex(const char *h,void *buf,unsigned int buflen)
+char *hex10(uint64_t i,char s[11])
 {
-	unsigned int l = 0;
-	while (l < buflen) {
-		uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
-		if (!hc) break;
-
-		uint8_t c = 0;
-		if ((hc >= 48)&&(hc <= 57)) // 0..9
-			c = hc - 48;
-		else if ((hc >= 97)&&(hc <= 102)) // a..f
-			c = hc - 87;
-		else if ((hc >= 65)&&(hc <= 70)) // A..F
-			c = hc - 55;
-
-		hc = *(reinterpret_cast<const uint8_t *>(h++));
-		if (!hc) break;
-
-		c <<= 4;
-		if ((hc >= 48)&&(hc <= 57))
-			c |= hc - 48;
-		else if ((hc >= 97)&&(hc <= 102))
-			c |= hc - 87;
-		else if ((hc >= 65)&&(hc <= 70))
-			c |= hc - 55;
+	s[0] = HEXCHARS[(i >> 36) & 0xf];
+	s[1] = HEXCHARS[(i >> 32) & 0xf];
+	s[2] = HEXCHARS[(i >> 28) & 0xf];
+	s[3] = HEXCHARS[(i >> 24) & 0xf];
+	s[4] = HEXCHARS[(i >> 20) & 0xf];
+	s[5] = HEXCHARS[(i >> 16) & 0xf];
+	s[6] = HEXCHARS[(i >> 12) & 0xf];
+	s[7] = HEXCHARS[(i >> 8) & 0xf];
+	s[8] = HEXCHARS[(i >> 4) & 0xf];
+	s[9] = HEXCHARS[i & 0xf];
+	s[10] = (char)0;
+	return s;
+}
 
-		reinterpret_cast<uint8_t *>(buf)[l++] = c;
+char *hex(const void *d,unsigned int l,char *s)
+{
+	char *const save = s;
+	for(unsigned int i=0;i<l;++i) {
+		const unsigned int b = reinterpret_cast<const uint8_t *>(d)[i];
+		*(s++) = HEXCHARS[b >> 4];
+		*(s++) = HEXCHARS[b & 0xf];
 	}
-	return l;
+	*s = (char)0;
+	return save;
 }
 
 unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen)

+ 48 - 43
node/Utils.hpp

@@ -89,21 +89,7 @@ static inline char *hex(I x,char *s)
  * @param s Buffer of size [11] to receive 10 hex characters
  * @return Pointer to buffer
  */
-static inline char *hex10(uint64_t i,char s[11])
-{
-	s[0] = HEXCHARS[(i >> 36) & 0xf];
-	s[1] = HEXCHARS[(i >> 32) & 0xf];
-	s[2] = HEXCHARS[(i >> 28) & 0xf];
-	s[3] = HEXCHARS[(i >> 24) & 0xf];
-	s[4] = HEXCHARS[(i >> 20) & 0xf];
-	s[5] = HEXCHARS[(i >> 16) & 0xf];
-	s[6] = HEXCHARS[(i >> 12) & 0xf];
-	s[7] = HEXCHARS[(i >> 8) & 0xf];
-	s[8] = HEXCHARS[(i >> 4) & 0xf];
-	s[9] = HEXCHARS[i & 0xf];
-	s[10] = (char)0;
-	return s;
-}
+char *hex10(uint64_t i,char s[11]);
 
 /**
  * Convert a byte array into hex
@@ -113,19 +99,17 @@ static inline char *hex10(uint64_t i,char s[11])
  * @param s String buffer, must be at least (l*2)+1 in size or overflow will occur
  * @return Pointer to filled string buffer
  */
-static inline char *hex(const void *d,unsigned int l,char *s)
-{
-	char *const save = s;
-	for(unsigned int i=0;i<l;++i) {
-		const unsigned int b = reinterpret_cast<const uint8_t *>(d)[i];
-		*(s++) = HEXCHARS[b >> 4];
-		*(s++) = HEXCHARS[b & 0xf];
-	}
-	*s = (char)0;
-	return save;
-}
+char *hex(const void *d,unsigned int l,char *s);
 
-unsigned int unhex(const char *h,void *buf,unsigned int buflen);
+/**
+ * Decode a hex string
+ *
+ * @param h Hex C-string (non hex chars are ignored)
+ * @param hlen Maximum length of string (will stop at terminating zero)
+ * @param buf Output buffer
+ * @param buflen Length of output buffer
+ * @return Number of written bytes
+ */
 unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen);
 
 /**
@@ -165,6 +149,19 @@ int b32d(const char *encoded, uint8_t *result, int bufSize);
  */
 uint64_t random();
 
+/**
+ * Perform a safe C string copy, ALWAYS null-terminating the result
+ *
+ * This will never ever EVER result in dest[] not being null-terminated
+ * regardless of any input parameter (other than len==0 which is invalid).
+ *
+ * @param dest Destination buffer (must not be NULL)
+ * @param len Length of dest[] (if zero, false is returned and nothing happens)
+ * @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)
+ */
+bool scopy(char *dest,unsigned int len,const char *src);
+
 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;
@@ -230,19 +227,6 @@ static ZT_ALWAYS_INLINE long long hexStrTo64(const char *s)
 #endif
 }
 
-/**
- * Perform a safe C string copy, ALWAYS null-terminating the result
- *
- * This will never ever EVER result in dest[] not being null-terminated
- * regardless of any input parameter (other than len==0 which is invalid).
- *
- * @param dest Destination buffer (must not be NULL)
- * @param len Length of dest[] (if zero, false is returned and nothing happens)
- * @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)
- */
-bool scopy(char *dest,unsigned int len,const char *src);
-
 /**
  * Calculate a non-cryptographic hash of a byte string
  *
@@ -281,11 +265,21 @@ static ZT_ALWAYS_INLINE unsigned int countBits(T v)
 }
 #endif
 
-// Byte swappers for big/little endian conversion
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 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 uint16_t hton(uint16_t n)
+{
+#if defined(__GNUC__)
+#if defined(__FreeBSD__)
+	return htons(n);
+#elif (!defined(__OpenBSD__))
+	return __builtin_bswap16(n);
+#endif
+#else
+	return htons(n);
+#endif
+}
 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)
 {
@@ -330,7 +324,18 @@ static ZT_ALWAYS_INLINE T hton(T n) { return n; }
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 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 uint16_t ntoh(uint16_t n)
+{
+#if defined(__GNUC__)
+#if defined(__FreeBSD__)
+	return htons(n);
+#elif (!defined(__OpenBSD__))
+	return __builtin_bswap16(n);
+#endif
+#else
+	return htons(n);
+#endif
+}
 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)
 {