Adam Ierymenko vor 5 Jahren
Ursprung
Commit
9642ff5fb9
21 geänderte Dateien mit 500 neuen und 758 gelöschten Zeilen
  1. 18 188
      include/ZeroTierCore.h
  2. 2 2
      node/Constants.hpp
  3. 14 14
      node/ECC384.cpp
  4. 68 28
      node/Endpoint.hpp
  5. 2 2
      node/Identity.hpp
  6. 61 63
      node/InetAddress.cpp
  7. 18 16
      node/InetAddress.hpp
  8. 45 43
      node/Locator.hpp
  9. 15 15
      node/Membership.hpp
  10. 76 217
      node/Node.cpp
  11. 29 61
      node/Node.hpp
  12. 6 5
      node/Path.hpp
  13. 0 4
      node/Peer.cpp
  14. 27 51
      node/Peer.hpp
  15. 14 14
      node/Revocation.hpp
  16. 0 1
      node/SharedPtr.hpp
  17. 24 24
      node/Tag.hpp
  18. 40 4
      node/Topology.hpp
  19. 2 2
      node/Trace.cpp
  20. 35 0
      node/Utils.hpp
  21. 4 4
      selftest.cpp

+ 18 - 188
include/ZeroTierCore.h

@@ -19,7 +19,11 @@
 #ifndef ZT_ZEROTIER_API_H
 #define ZT_ZEROTIER_API_H
 
+#ifdef __cplusplus
+#include <cstdint>
+#else
 #include <stdint.h>
+#endif
 
 /* For struct sockaddr_storage, which is referenced here. */
 #if defined(_WIN32) || defined(_WIN64)
@@ -513,45 +517,6 @@ enum ZT_Event
 	ZT_EVENT_REMOTE_TRACE = 7
 };
 
-/**
- * A root server
- */
-typedef struct {
-	/**
-	 * Name of root
-	 *
-	 * This will be a DNS name for dynamic roots. For static roots
-	 * it will be the ZeroTier address. The presence or absence
-	 * of a dot is used internally as a distinguisher.
-	 */
-	const char *name;
-
-	/**
-	 * Serialized locator
-	 */
-	const void *locator;
-
-	/**
-	 * The size of locator in bytes
-	 */
-	unsigned int locatorSize;
-} ZT_Root;
-
-/**
- * List of root servers
- */
-typedef struct {
-	/**
-	 * Number of root servers
-	 */
-	unsigned int count;
-
-	/**
-	 * Array of root servers
-	 */
-	ZT_Root roots[];
-} ZT_RootList;
-
 /**
  * Payload of REMOTE_TRACE event
  */
@@ -1010,29 +975,6 @@ enum ZT_PeerRole
 	ZT_PEER_ROLE_PLANET = 2      // planetary root
 };
 
-/**
- * DNS record types for reporting DNS results
- *
- * These integer IDs (other than end of results) are the same as the DNS protocol's
- * internal IDs. Not all of these are used by ZeroTier, and not all DNS record types
- * are listed here. These are just common ones that are used now or may be used in
- * the future for some purpose.
- */
-enum ZT_DNSRecordType
-{
-	ZT_DNS_RECORD__END_OF_RESULTS = 0,
-	ZT_DNS_RECORD_A = 1,
-	ZT_DNS_RECORD_NS = 2,
-	ZT_DNS_RECORD_CNAME = 5,
-	ZT_DNS_RECORD_PTR = 12,
-	ZT_DNS_RECORD_MX = 15,
-	ZT_DNS_RECORD_TXT = 16,
-	ZT_DNS_RECORD_AAAA = 28,
-	ZT_DNS_RECORD_LOC = 29,
-	ZT_DNS_RECORD_SRV = 33,
-	ZT_DNS_RECORD_DNAME = 39
-};
-
 /**
  * Virtual network configuration
  */
@@ -1541,8 +1483,9 @@ typedef int (*ZT_PathCheckFunction)(
  *  (1) Node
  *  (2) User pointer
  *  (3) ZeroTier address (least significant 40 bits)
- *  (4) Desired address family or -1 for any
- *  (5) Buffer to fill with result
+ *  (4) Identity in string form
+ *  (5) Desired address family or -1 for any
+ *  (6) Buffer to fill with result
  *
  * If provided this function will be occasionally called to get physical
  * addresses that might be tried to reach a ZeroTier address. It must
@@ -1554,53 +1497,10 @@ typedef int (*ZT_PathLookupFunction)(
 	void *,                           /* User ptr */
 	void *,                           /* Thread ptr */
 	uint64_t,                         /* ZeroTier address (40 bits) */
+	const char *,                     /* Identity in string form */
 	int,                              /* Desired ss_family or -1 for any */
 	struct sockaddr_storage *);       /* Result buffer */
 
-/**
- * Function to request an asynchronous DNS TXT lookup
- *
- * Parameters:
- *  (1) Node
- *  (2) User pointer
- *  (3) Thread pointer
- *  (4) Array of DNS record types we want
- *  (5) Number of DNS record types in array
- *  (6) DNS name to fetch
- *  (7) DNS request ID to supply to ZT_Node_processDNSResult()
- *
- * DNS is not handled in the core because every platform and runtime
- * typically has its own DNS functions or libraries and these may need
- * to interface with OS or network services in your local environment.
- * Instead this function and its result submission counterpart are
- * provided so you can provide a DNS implementation.
- *
- * If this callback is set in your callback struct to a NULL value,
- * DNS will not be available. The ZeroTier protocol is designed to
- * work in the absence of DNS but you may not get optimal results. For
- * example you may default to root servers that are not geographically
- * optimal or your node may cease to function if a root server's IP
- * changes and there's no way to signal this.
- *
- * This function requests resolution of a DNS record. The result
- * submission method ZT_Node_processDNSResult() must be called at
- * least once in response. See its documentation.
- *
- * Right now ZeroTier only requests resolution of TXT records, but
- * it's possible that this will change in the future.
- *
- * It's safe to call processDNSResult() from within your handler
- * for this function.
- */
-typedef void (*ZT_DNSResolver)(
-	ZT_Node *,                        /* Node */
-	void *,                           /* User ptr */
-	void *,                           /* Thread ptr */
-	const enum ZT_DNSRecordType *,    /* DNS record type(s) to fetch */
-	unsigned int,                     /* Number of DNS record type(s) */
-	const char *,                     /* DNS name to fetch */
-	uintptr_t);                       /* Request ID for returning results */
-
 /****************************************************************************/
 /* C Node API                                                               */
 /****************************************************************************/
@@ -1640,11 +1540,6 @@ struct ZT_Node_Callbacks
 	 */
 	ZT_EventCallback eventCallback;
 
-	/**
-	 * STRONGLY RECOMMENDED: Function to request a DNS lookup
-	 */
-	ZT_DNSResolver dnsResolver;
-
 	/**
 	 * OPTIONAL: Function to check whether a given physical path should be used
 	 */
@@ -1750,60 +1645,6 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(
 	int64_t now,
 	volatile int64_t *nextBackgroundTaskDeadline);
 
-/**
- * Submit the result(s) of a requested DNS query
- *
- * This MUST be called at least once after the node requsts DNS resolution.
- * If there are no results or DNS is not implemented or available, just
- * send one ZT_DNS_RECORD__END_OF_RESULTS to signal that no results were
- * obtained.
- *
- * If result is non-NULL but resultLength is zero then result is assumed to
- * be a C string terminated by a zero. Passing an unterminated string with a
- * zero resultLength will result in a crash.
- *
- * The results of A and AAAA records can be returned as either strings or
- * binary IP address bytes (network byte order). If the result is a string,
- * resultLength must be 0 to signal that result is a C string. Otherwise for
- * A resultLength must be 4 and for AAAA it must be 16 if the result is
- * in binary format.
- *
- * The Node implementation makes an effort to ignore obviously invalid
- * submissions like an AAAA record in bianry form with length 25, but this
- * is not guaranteed. It's possible to crash your program by calling this
- * with garbage inputs.
- *
- * Results may be submitted in any order and order should not be assumed
- * to have any meaning.
- *
- * The ZT_DNS_RECORD__END_OF_RESULTS pseudo-response must be sent after all
- * results have been submitted. The result and resultLength paramters are
- * ignored for this type ID.
- *
- * It is safe to call this function from inside the DNS request callback,
- * such as to return a locally cached result or a result from some kind
- * of local database. It's also safe to call this function from threads
- * other than the one that received the DNS request.
- *
- * @param node Node instance that requested DNS resolution
- * @param tptr Thread pointer to pass to functions/callbacks resulting from this call
- * @param dnsRequestID Request ID supplied to DNS request callback
- * @param name DNS name
- * @param recordType Record type of this result
- * @param result Result (content depends on record type)
- * @param resultLength Length of result
- * @param resultIsString If non-zero, IP results for A and AAAA records are being given as C strings not binary IPs
- */
-ZT_SDK_API void ZT_Node_processDNSResult(
-	ZT_Node *node,
-	void *tptr,
-	uintptr_t dnsRequestID,
-	const char *name,
-	enum ZT_DNSRecordType recordType,
-	const void *result,
-	unsigned int resultLength,
-	int resultIsString);
-
 /**
  * Join a network
  *
@@ -1884,36 +1725,25 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tpt
 ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
 
 /**
- * List roots for this node
+ * Add a root server (has no effect if already added)
  *
  * @param node Node instance
- * @param now Current time
- * @return List of roots, use ZT_Node_freeQueryResult to free this when done
+ * @param identity Identity of this root server in string format
+ * @return OK (0) or error code if a fatal error condition has occurred
  */
-ZT_SDK_API ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now);
+ZT_SDK_API enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,const char *identity);
 
 /**
- * Add or update a root
+ * Remove a root server
  *
- * The node will begin trying to resolve the DNS TXT record for
- * this root and possibly obtain it from other peers.
+ * This removes this node's root designation but does not prevent this node
+ * from communicating with it or close active paths to it.
  *
  * @param node Node instance
- * @param name DNS name or simply the address in hex form for static roots
- * @param locator Binary-serialized locator of NULL if none
- * @param locatorSize Size of locator or 0 if none
- * @return OK (0) or error code
- */
-ZT_SDK_API enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize);
-
-/**
- * Remove a dynamic root
- *
- * @param node Node instance
- * @param name DNS name of this dynamic root or the address in hex form for static roots
- * @return OK (0) or error code
+ * @param identity Identity in string format
+ * @return OK (0) or error code if a fatal error condition has occurred
  */
-ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name);
+ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *identity);
 
 /**
  * Get this node's 40-bit ZeroTier address

+ 2 - 2
node/Constants.hpp

@@ -37,9 +37,9 @@
 #define ZT_ADDRESS_RESERVED_PREFIX 0xff
 
 /**
- * Maximum DNS or URL name size for an Endpoint (set so that max marshaled endpoint size is 128 bytes)
+ * Maximum DNS or URL name size for an Endpoint (set so that max marshaled endpoint size is 64 bytes)
  */
-#define ZT_ENDPOINT_MAX_NAME_SIZE 124
+#define ZT_ENDPOINT_MAX_NAME_SIZE 61
 
 /**
  * Size of an identity hash (SHA384)

+ 14 - 14
node/ECC384.cpp

@@ -60,13 +60,13 @@ static EccPoint curve_G = CONCAT(Curve_G_, ECC_CURVE);
 static uint64_t curve_n[NUM_ECC_DIGITS] = CONCAT(Curve_N_, ECC_CURVE);
 
 // Use ZeroTier's secure PRNG
-static inline int getRandomNumber(uint64_t *p_vli)
+static ZT_ALWAYS_INLINE int getRandomNumber(uint64_t *p_vli)
 {
 	Utils::getSecureRandom(p_vli,ECC_BYTES);
 	return 1;
 }
 
-static inline void vli_clear(uint64_t *p_vli)
+static ZT_ALWAYS_INLINE void vli_clear(uint64_t *p_vli)
 {
 	uint i;
 	for(i=0; i<NUM_ECC_DIGITS; ++i)
@@ -76,7 +76,7 @@ static inline void vli_clear(uint64_t *p_vli)
 }
 
 /* Returns 1 if p_vli == 0, 0 otherwise. */
-static inline int vli_isZero(uint64_t *p_vli)
+static ZT_ALWAYS_INLINE int vli_isZero(uint64_t *p_vli)
 {
 	uint i;
 	for(i = 0; i < NUM_ECC_DIGITS; ++i)
@@ -90,13 +90,13 @@ static inline int vli_isZero(uint64_t *p_vli)
 }
 
 /* Returns nonzero if bit p_bit of p_vli is set. */
-static inline uint64_t vli_testBit(uint64_t *p_vli, uint p_bit)
+static ZT_ALWAYS_INLINE uint64_t vli_testBit(uint64_t *p_vli, uint p_bit)
 {
 	return (p_vli[p_bit/64] & ((uint64_t)1 << (p_bit % 64)));
 }
 
 /* Counts the number of 64-bit "digits" in p_vli. */
-static inline uint vli_numDigits(uint64_t *p_vli)
+static ZT_ALWAYS_INLINE uint vli_numDigits(uint64_t *p_vli)
 {
 	int i;
 	/* Search from the end until we find a non-zero digit.
@@ -109,7 +109,7 @@ static inline uint vli_numDigits(uint64_t *p_vli)
 }
 
 /* Counts the number of bits required for p_vli. */
-static inline uint vli_numBits(uint64_t *p_vli)
+static ZT_ALWAYS_INLINE uint vli_numBits(uint64_t *p_vli)
 {
 	uint i;
 	uint64_t l_digit;
@@ -130,7 +130,7 @@ static inline uint vli_numBits(uint64_t *p_vli)
 }
 
 /* Sets p_dest = p_src. */
-static inline void vli_set(uint64_t *p_dest, uint64_t *p_src)
+static ZT_ALWAYS_INLINE void vli_set(uint64_t *p_dest, uint64_t *p_src)
 {
 	uint i;
 	for(i=0; i<NUM_ECC_DIGITS; ++i)
@@ -464,7 +464,7 @@ static inline void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product)
 //#endif
 
 /* Computes p_result = (p_left * p_right) % curve_p. */
-static inline void vli_modMult_fast(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right)
+static ZT_ALWAYS_INLINE void vli_modMult_fast(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right)
 {
 	uint64_t l_product[2 * NUM_ECC_DIGITS];
 	vli_mult(l_product, p_left, p_right);
@@ -472,7 +472,7 @@ static inline void vli_modMult_fast(uint64_t *p_result, uint64_t *p_left, uint64
 }
 
 /* Computes p_result = p_left^2 % curve_p. */
-static inline void vli_modSquare_fast(uint64_t *p_result, uint64_t *p_left)
+static ZT_ALWAYS_INLINE void vli_modSquare_fast(uint64_t *p_result, uint64_t *p_left)
 {
 	uint64_t l_product[2 * NUM_ECC_DIGITS];
 	vli_square(l_product, p_left);
@@ -576,7 +576,7 @@ static inline void vli_modInv(uint64_t *p_result, uint64_t *p_input, uint64_t *p
 /* ------ Point operations ------ */
 
 /* Returns 1 if p_point is the point at infinity, 0 otherwise. */
-static inline int EccPoint_isZero(EccPoint *p_point)
+static ZT_ALWAYS_INLINE int EccPoint_isZero(EccPoint *p_point)
 {
 	return (vli_isZero(p_point->x) && vli_isZero(p_point->y));
 }
@@ -635,7 +635,7 @@ static inline void EccPoint_double_jacobian(uint64_t *X1, uint64_t *Y1, uint64_t
 }
 
 /* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
-static inline void apply_z(uint64_t *X1, uint64_t *Y1, uint64_t *Z)
+static ZT_ALWAYS_INLINE void apply_z(uint64_t *X1, uint64_t *Y1, uint64_t *Z)
 {
 	uint64_t t1[NUM_ECC_DIGITS];
 
@@ -772,7 +772,7 @@ static inline void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint64_t
 	vli_set(p_result->y, Ry[0]);
 }
 
-static inline void ecc_bytes2native(uint64_t p_native[NUM_ECC_DIGITS], const uint8_t p_bytes[ECC_BYTES])
+static ZT_ALWAYS_INLINE void ecc_bytes2native(uint64_t p_native[NUM_ECC_DIGITS], const uint8_t p_bytes[ECC_BYTES])
 {
 	unsigned i;
 	for(i=0; i<NUM_ECC_DIGITS; ++i)
@@ -783,7 +783,7 @@ static inline void ecc_bytes2native(uint64_t p_native[NUM_ECC_DIGITS], const uin
 	}
 }
 
-static inline void ecc_native2bytes(uint8_t p_bytes[ECC_BYTES], const uint64_t p_native[NUM_ECC_DIGITS])
+static ZT_ALWAYS_INLINE void ecc_native2bytes(uint8_t p_bytes[ECC_BYTES], const uint64_t p_native[NUM_ECC_DIGITS])
 {
 	unsigned i;
 	for(i=0; i<NUM_ECC_DIGITS; ++i)
@@ -961,7 +961,7 @@ static inline void vli_modMult(uint64_t *p_result, uint64_t *p_left, uint64_t *p
 	vli_set(p_result, l_product);
 }
 
-static inline uint umax(uint a, uint b)
+static ZT_ALWAYS_INLINE uint umax(uint a, uint b)
 {
 	return (a > b ? a : b);
 }

+ 68 - 28
node/Endpoint.hpp

@@ -24,7 +24,7 @@
 #include "Address.hpp"
 #include "Utils.hpp"
 
-#define ZT_ENDPOINT_MARSHAL_SIZE_MAX (ZT_ENDPOINT_MAX_NAME_SIZE+4)
+#define ZT_ENDPOINT_MARSHAL_SIZE_MAX (ZT_ENDPOINT_MAX_NAME_SIZE+3)
 
 namespace ZeroTier {
 
@@ -46,10 +46,10 @@ public:
 
 	ZT_ALWAYS_INLINE Endpoint() { memset(reinterpret_cast<void *>(this),0,sizeof(Endpoint)); }
 
-	ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) : _t(INETADDR) { _v.sa = sa; }
+	explicit 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); }
+	explicit ZT_ALWAYS_INLINE Endpoint(const char *url) : _t(URL) { Utils::scopy(_v.url,sizeof(_v.url),url); }
 
 	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; }
@@ -61,6 +61,45 @@ public:
 
 	ZT_ALWAYS_INLINE Type type() const { return _t; }
 
+	ZT_ALWAYS_INLINE bool operator==(const Endpoint &ep) const
+	{
+		if (_t == ep._t) {
+			switch(_t) {
+				case INETADDR: return (*sockaddr() == *ep.sockaddr());
+				case DNSNAME:  return ((_v.dns.port == ep._v.dns.port)&&(strcmp(_v.dns.name,ep._v.dns.name) == 0));
+				case ZEROTIER: return ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) == 0));
+				case URL:      return (strcmp(_v.url,ep._v.url) == 0);
+				case ETHERNET: return (_v.eth == ep._v.eth);
+				default:       return true;
+			}
+		}
+		return false;
+	}
+	ZT_ALWAYS_INLINE bool operator!=(const Endpoint &ep) const { return (!(*this == ep)); }
+	ZT_ALWAYS_INLINE bool operator<(const Endpoint &ep) const
+	{
+		if ((int)_t < (int)ep._t) {
+			return true;
+		} else if (_t == ep._t) {
+			int ncmp;
+			switch(_t) {
+				case INETADDR: return (*sockaddr() < *ep.sockaddr());
+				case DNSNAME:
+					ncmp = strcmp(_v.dns.name,ep._v.dns.name);
+					return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port));
+				case ZEROTIER: return (_v.zt.a < ep._v.zt.a) ? true : ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) < 0));
+				case URL:      return (strcmp(_v.url,ep._v.url) < 0);
+				case ETHERNET: return (_v.eth < ep._v.eth);
+				default:       return false;
+			}
+		}
+		return false;
+	}
+	ZT_ALWAYS_INLINE bool operator>(const Endpoint &ep) const { return (ep < *this); }
+	ZT_ALWAYS_INLINE bool operator<=(const Endpoint &ep) const { return !(ep < *this); }
+	ZT_ALWAYS_INLINE bool operator>=(const Endpoint &ep) const { return !(*this < ep); }
+
+	// Marshal interface ///////////////////////////////////////////////////////
 	static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_ENDPOINT_MARSHAL_SIZE_MAX; }
 	inline int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const
 	{
@@ -79,16 +118,16 @@ public:
 					if (p == (ZT_ENDPOINT_MAX_NAME_SIZE+1))
 						return -1;
 				}
-				data[p++] = (uint8_t)((_v.dns.port >> 8) & 0xff);
-				data[p++] = (uint8_t)(_v.dns.port & 0xff);
+				data[p++] = (uint8_t)(_v.dns.port >> 8U);
+				data[p++] = (uint8_t)_v.dns.port;
 				return p;
 			case ZEROTIER:
 				data[0] = (uint8_t)ZEROTIER;
-				data[1] = (uint8_t)((_v.zt.a >> 32) & 0xff);
-				data[2] = (uint8_t)((_v.zt.a >> 24) & 0xff);
-				data[3] = (uint8_t)((_v.zt.a >> 16) & 0xff);
-				data[4] = (uint8_t)((_v.zt.a >> 8) & 0xff);
-				data[5] = (uint8_t)(_v.zt.a & 0xff);
+				data[1] = (uint8_t)(_v.zt.a >> 32U);
+				data[2] = (uint8_t)(_v.zt.a >> 24U);
+				data[3] = (uint8_t)(_v.zt.a >> 16U);
+				data[4] = (uint8_t)(_v.zt.a >> 8U);
+				data[5] = (uint8_t)_v.zt.a;
 				memcpy(data + 6,_v.zt.idh,ZT_IDENTITY_HASH_SIZE);
 				return (ZT_IDENTITY_HASH_SIZE + 6);
 			case URL:
@@ -104,12 +143,12 @@ public:
 				return p;
 			case ETHERNET:
 				data[0] = (uint8_t)ETHERNET;
-				data[1] = (uint8_t)((_v.eth >> 40) & 0xff);
-				data[2] = (uint8_t)((_v.eth >> 32) & 0xff);
-				data[3] = (uint8_t)((_v.eth >> 24) & 0xff);
-				data[4] = (uint8_t)((_v.eth >> 16) & 0xff);
-				data[5] = (uint8_t)((_v.eth >> 8) & 0xff);
-				data[6] = (uint8_t)(_v.eth & 0xff);
+				data[1] = (uint8_t)(_v.eth >> 40U);
+				data[2] = (uint8_t)(_v.eth >> 32U);
+				data[3] = (uint8_t)(_v.eth >> 24U);
+				data[4] = (uint8_t)(_v.eth >> 16U);
+				data[5] = (uint8_t)(_v.eth >> 8U);
+				data[6] = (uint8_t)_v.eth;
 				return 7;
 			default:
 				data[0] = (uint8_t)NIL;
@@ -142,17 +181,17 @@ public:
 					if ((p >= (ZT_ENDPOINT_MAX_NAME_SIZE+1))||(p >= (len-2)))
 						return -1;
 				}
-				_v.dns.port = ((int)data[p++]) << 8;
-				_v.dns.port |= (int)data[p++];
+				_v.dns.port = (uint16_t)(((unsigned int)data[p++]) << 8U);
+				_v.dns.port |= (uint16_t)data[p++];
 				return p;
 			case ZEROTIER:
 				if (len < (ZT_IDENTITY_HASH_SIZE + 6))
 					return -1;
 				_t = ZEROTIER;
-				_v.zt.a = ((uint64_t)data[1]) << 32;
-				_v.zt.a |= ((uint64_t)data[2]) << 24;
-				_v.zt.a |= ((uint64_t)data[3]) << 16;
-				_v.zt.a |= ((uint64_t)data[4]) << 8;
+				_v.zt.a = ((uint64_t)data[1]) << 32U;
+				_v.zt.a |= ((uint64_t)data[2]) << 24U;
+				_v.zt.a |= ((uint64_t)data[3]) << 16U;
+				_v.zt.a |= ((uint64_t)data[4]) << 8U;
 				_v.zt.a |= (uint64_t)data[5];
 				memcpy(_v.zt.idh,data + 6,ZT_IDENTITY_HASH_SIZE);
 				return (ZT_IDENTITY_HASH_SIZE + 6);
@@ -175,16 +214,17 @@ public:
 				if (len < 7)
 					return -1;
 				_t = ZEROTIER;
-				_v.eth = ((uint64_t)data[1]) << 40;
-				_v.eth |= ((uint64_t)data[2]) << 32;
-				_v.eth |= ((uint64_t)data[3]) << 24;
-				_v.eth |= ((uint64_t)data[4]) << 16;
-				_v.eth |= ((uint64_t)data[5]) << 8;
+				_v.eth = ((uint64_t)data[1]) << 40U;
+				_v.eth |= ((uint64_t)data[2]) << 32U;
+				_v.eth |= ((uint64_t)data[3]) << 24U;
+				_v.eth |= ((uint64_t)data[4]) << 16U;
+				_v.eth |= ((uint64_t)data[5]) << 8U;
 				_v.eth |= (uint64_t)data[6];
 				return 7;
 		}
 		return false;
 	}
+	////////////////////////////////////////////////////////////////////////////
 
 private:
 	Type _t;
@@ -192,7 +232,7 @@ private:
 		struct sockaddr_storage sa;
 		struct {
 			char name[ZT_ENDPOINT_MAX_NAME_SIZE];
-			int port;
+			uint16_t port;
 		} dns;
 		struct {
 			uint64_t a;

+ 2 - 2
node/Identity.hpp

@@ -368,7 +368,7 @@ public:
 	/**
 	 * @return True if this identity contains something
 	 */
-	ZT_ALWAYS_INLINE operator bool() const { return (_address); }
+	explicit ZT_ALWAYS_INLINE operator bool() const { return (_address); }
 
 	ZT_ALWAYS_INLINE bool operator==(const Identity &id) const
 	{
@@ -407,7 +407,7 @@ public:
 
 	// Marshal interface ///////////////////////////////////////////////////////
 	static ZT_ALWAYS_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
+	inline int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate = false) const
 	{
 		_address.copyTo(data,ZT_ADDRESS_LENGTH);
 		switch(_type) {

+ 61 - 63
node/InetAddress.cpp

@@ -11,11 +11,8 @@
  */
 /****/
 
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#include <string>
+#include <cstring>
+#include <cstdint>
 
 #include "Constants.hpp"
 #include "InetAddress.hpp"
@@ -33,20 +30,20 @@ InetAddress::IpScope InetAddress::ipScope() const
 
 		case AF_INET: {
 			const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
-			switch(ip >> 24) {
+			switch(ip >> 24U) {
 				case 0x00: return IP_SCOPE_NONE;                                   // 0.0.0.0/8 (reserved, never used)
 				case 0x06: return IP_SCOPE_PSEUDOPRIVATE;                          // 6.0.0.0/8 (US Army)
 				case 0x0a: return IP_SCOPE_PRIVATE;                                // 10.0.0.0/8
-				case 0x0b: return IP_SCOPE_PSEUDOPRIVATE;                          // 11.0.0.0/8 (US DoD)
-				case 0x15: return IP_SCOPE_PSEUDOPRIVATE;                          // 21.0.0.0/8 (US DDN-RVN)
-				case 0x16: return IP_SCOPE_PSEUDOPRIVATE;                          // 22.0.0.0/8 (US DISA)
-				case 0x19: return IP_SCOPE_PSEUDOPRIVATE;                          // 25.0.0.0/8 (UK Ministry of Defense)
-				case 0x1a: return IP_SCOPE_PSEUDOPRIVATE;                          // 26.0.0.0/8 (US DISA)
-				case 0x1c: return IP_SCOPE_PSEUDOPRIVATE;                          // 28.0.0.0/8 (US DSI-North)
-				case 0x1d: return IP_SCOPE_PSEUDOPRIVATE;                          // 29.0.0.0/8 (US DISA)
-				case 0x1e: return IP_SCOPE_PSEUDOPRIVATE;                          // 30.0.0.0/8 (US DISA)
-				case 0x33: return IP_SCOPE_PSEUDOPRIVATE;                          // 51.0.0.0/8 (UK Department of Social Security)
-				case 0x37: return IP_SCOPE_PSEUDOPRIVATE;                          // 55.0.0.0/8 (US DoD)
+				case 0x0b: //return IP_SCOPE_PSEUDOPRIVATE;                        // 11.0.0.0/8 (US DoD)
+				case 0x15: //return IP_SCOPE_PSEUDOPRIVATE;                        // 21.0.0.0/8 (US DDN-RVN)
+				case 0x16: //return IP_SCOPE_PSEUDOPRIVATE;                        // 22.0.0.0/8 (US DISA)
+				case 0x19: //return IP_SCOPE_PSEUDOPRIVATE;                        // 25.0.0.0/8 (UK Ministry of Defense)
+				case 0x1a: //return IP_SCOPE_PSEUDOPRIVATE;                        // 26.0.0.0/8 (US DISA)
+				case 0x1c: //return IP_SCOPE_PSEUDOPRIVATE;                        // 28.0.0.0/8 (US DSI-North)
+				case 0x1d: //return IP_SCOPE_PSEUDOPRIVATE;                        // 29.0.0.0/8 (US DISA)
+				case 0x1e: //return IP_SCOPE_PSEUDOPRIVATE;                        // 30.0.0.0/8 (US DISA)
+				case 0x33: //return IP_SCOPE_PSEUDOPRIVATE;                        // 51.0.0.0/8 (UK Department of Social Security)
+				case 0x37: //return IP_SCOPE_PSEUDOPRIVATE;                        // 55.0.0.0/8 (US DoD)
 				case 0x38: return IP_SCOPE_PSEUDOPRIVATE;                          // 56.0.0.0/8 (US Postal Service)
 				case 0x64:
 					if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_PRIVATE;    // 100.64.0.0/10
@@ -164,7 +161,7 @@ bool InetAddress::fromString(const char *ipSlashPort)
 	unsigned int port = 0;
 	if (*portAt) {
 		*(portAt++) = (char)0;
-		port = Utils::strToUInt(portAt) & 0xffff;
+		port = Utils::strToUInt(portAt) & 0xffffU;
 	}
 
 	if (strchr(buf,':')) {
@@ -189,7 +186,7 @@ InetAddress InetAddress::netmask() const
 	InetAddress r(*this);
 	switch(r.ss_family) {
 		case AF_INET:
-			reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
+			reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits())));
 			break;
 		case AF_INET6: {
 			uint64_t nm[2];
@@ -211,7 +208,7 @@ InetAddress InetAddress::broadcast() const
 {
 	if (ss_family == AF_INET) {
 		InetAddress r(*this);
-		reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
+		reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffffU >> netmaskBits()));
 		return r;
 	}
 	return InetAddress();
@@ -222,7 +219,7 @@ InetAddress InetAddress::network() const
 	InetAddress r(*this);
 	switch(r.ss_family) {
 		case AF_INET:
-			reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
+			reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits())));
 			break;
 		case AF_INET6: {
 			uint64_t nm[2];
@@ -294,7 +291,7 @@ bool InetAddress::isNetwork() const
 			if (bits >= 32)
 				return false;
 			uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
-			return ((ip & (0xffffffff >> bits)) == 0);
+			return ((ip & (0xffffffffU >> bits)) == 0);
 		}
 		case AF_INET6: {
 			unsigned int bits = netmaskBits();
@@ -304,7 +301,7 @@ bool InetAddress::isNetwork() const
 				return false;
 			const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
 			unsigned int p = bits / 8;
-			if ((ip[p++] & (0xff >> (bits % 8))) != 0)
+			if ((ip[p++] & (0xffU >> (bits % 8))) != 0)
 				return false;
 			while (p < 16) {
 				if (ip[p++])
@@ -378,48 +375,49 @@ bool InetAddress::operator<(const InetAddress &a) const
 
 InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
 {
-	struct sockaddr_in6 sin6;
-	sin6.sin6_family = AF_INET6;
-	sin6.sin6_addr.s6_addr[0] = 0xfe;
-	sin6.sin6_addr.s6_addr[1] = 0x80;
-	sin6.sin6_addr.s6_addr[2] = 0x00;
-	sin6.sin6_addr.s6_addr[3] = 0x00;
-	sin6.sin6_addr.s6_addr[4] = 0x00;
-	sin6.sin6_addr.s6_addr[5] = 0x00;
-	sin6.sin6_addr.s6_addr[6] = 0x00;
-	sin6.sin6_addr.s6_addr[7] = 0x00;
-	sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd;
-	sin6.sin6_addr.s6_addr[9] = mac[1];
-	sin6.sin6_addr.s6_addr[10] = mac[2];
-	sin6.sin6_addr.s6_addr[11] = 0xff;
-	sin6.sin6_addr.s6_addr[12] = 0xfe;
-	sin6.sin6_addr.s6_addr[13] = mac[3];
-	sin6.sin6_addr.s6_addr[14] = mac[4];
-	sin6.sin6_addr.s6_addr[15] = mac[5];
-	sin6.sin6_port = Utils::hton((uint16_t)64);
-	return InetAddress(sin6);
+	InetAddress r;
+	sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
+	sin6->sin6_family = AF_INET6;
+	sin6->sin6_addr.s6_addr[0] = 0xfe;
+	sin6->sin6_addr.s6_addr[1] = 0x80;
+	sin6->sin6_addr.s6_addr[2] = 0x00;
+	sin6->sin6_addr.s6_addr[3] = 0x00;
+	sin6->sin6_addr.s6_addr[4] = 0x00;
+	sin6->sin6_addr.s6_addr[5] = 0x00;
+	sin6->sin6_addr.s6_addr[6] = 0x00;
+	sin6->sin6_addr.s6_addr[7] = 0x00;
+	sin6->sin6_addr.s6_addr[8] = mac[0] & 0xfdU;
+	sin6->sin6_addr.s6_addr[9] = mac[1];
+	sin6->sin6_addr.s6_addr[10] = mac[2];
+	sin6->sin6_addr.s6_addr[11] = 0xff;
+	sin6->sin6_addr.s6_addr[12] = 0xfe;
+	sin6->sin6_addr.s6_addr[13] = mac[3];
+	sin6->sin6_addr.s6_addr[14] = mac[4];
+	sin6->sin6_addr.s6_addr[15] = mac[5];
+	sin6->sin6_port = Utils::hton((uint16_t)64);
+	return r;
 }
 
 InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
 {
 	InetAddress r;
-	struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
+	sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
 	sin6->sin6_family = AF_INET6;
 	sin6->sin6_addr.s6_addr[0] = 0xfd;
-	sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56);
-	sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48);
-	sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40);
-	sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32);
-	sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24);
-	sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16);
-	sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8);
+	sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56U);
+	sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48U);
+	sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40U);
+	sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32U);
+	sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24U);
+	sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16U);
+	sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8U);
 	sin6->sin6_addr.s6_addr[8] = (uint8_t)nwid;
 	sin6->sin6_addr.s6_addr[9] = 0x99;
 	sin6->sin6_addr.s6_addr[10] = 0x93;
-	sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32);
-	sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24);
-	sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16);
-	sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8);
+	sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32U);
+	sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24U);
+	sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16U);
+	sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8U);
 	sin6->sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress;
 	sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that
 	return r;
@@ -427,19 +425,19 @@ InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
 
 InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress)
 {
-	nwid ^= (nwid >> 32);
+	nwid ^= (nwid >> 32U);
 	InetAddress r;
-	struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
+	sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
 	sin6->sin6_family = AF_INET6;
 	sin6->sin6_addr.s6_addr[0] = 0xfc;
-	sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24);
-	sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16);
-	sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8);
+	sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24U);
+	sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16U);
+	sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8U);
 	sin6->sin6_addr.s6_addr[4] = (uint8_t)nwid;
-	sin6->sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32);
-	sin6->sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24);
-	sin6->sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16);
-	sin6->sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8);
+	sin6->sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32U);
+	sin6->sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24U);
+	sin6->sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16U);
+	sin6->sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8U);
 	sin6->sin6_addr.s6_addr[9] = (uint8_t)zeroTierAddress;
 	sin6->sin6_addr.s6_addr[15] = 0x01;
 	sin6->sin6_port = Utils::hton((uint16_t)40);

+ 18 - 16
node/InetAddress.hpp

@@ -18,8 +18,9 @@
 #include <cstring>
 #include <cstdint>
 
-#include "Constants.hpp"
 #include "../include/ZeroTierOne.h"
+
+#include "Constants.hpp"
 #include "Utils.hpp"
 #include "MAC.hpp"
 #include "Buffer.hpp"
@@ -464,16 +465,16 @@ struct InetAddress : public sockaddr_storage
 		unsigned long h = 0;
 		switch(ss_family) {
 			case AF_INET:
-				h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffffff00) >> 8;
-				h ^= (h >> 14);
+				h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffffff00U) >> 8U;
+				h ^= (h >> 14U);
 				break;
 			case AF_INET6: {
 				const uint8_t *ip = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
-				h = ((unsigned long)ip[0]); h <<= 1;
-				h += ((unsigned long)ip[1]); h <<= 1;
-				h += ((unsigned long)ip[2]); h <<= 1;
-				h += ((unsigned long)ip[3]); h <<= 1;
-				h += ((unsigned long)ip[4]); h <<= 1;
+				h = ((unsigned long)ip[0]); h <<= 1U;
+				h += ((unsigned long)ip[1]); h <<= 1U;
+				h += ((unsigned long)ip[2]); h <<= 1U;
+				h += ((unsigned long)ip[3]); h <<= 1U;
+				h += ((unsigned long)ip[4]); h <<= 1U;
 				h += ((unsigned long)ip[5]);
 			}	break;
 		}
@@ -483,30 +484,31 @@ struct InetAddress : public sockaddr_storage
 	/**
 	 * @return True if address family is non-zero
 	 */
-	ZT_ALWAYS_INLINE operator bool() const { return (ss_family != 0); }
+	explicit ZT_ALWAYS_INLINE operator bool() const { return (ss_family != 0); }
 
 	// Marshal interface ///////////////////////////////////////////////////////
 	static ZT_ALWAYS_INLINE int marshalSizeMax() { return 19; }
-	inline int marshal(uint8_t restrict data[19]) const
+	inline int marshal(uint8_t data[19]) const
 	{
+		unsigned int port;
 		switch(ss_family) {
 			case AF_INET:
-				const unsigned int port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in *>(this)->sin_port);
+				port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in *>(this)->sin_port);
 				data[0] = 4;
 				data[1] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[0];
 				data[2] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[1];
 				data[3] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[2];
 				data[4] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[3];
-				data[5] = (uint8_t)((port >> 8) & 0xff);
-				data[6] = (uint8_t)(port & 0xff);
+				data[5] = (uint8_t)(port >> 8U);
+				data[6] = (uint8_t)port;
 				return 7;
 			case AF_INET6:
-				const unsigned int port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in6 *>(this)->sin6_port);
+				port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in6 *>(this)->sin6_port);
 				data[0] = 6;
 				for(int i=0;i<16;++i)
 					data[i+1] = reinterpret_cast<const sockaddr_in6 *>(this)->sin6_addr.s6_addr[i];
-				data[17] = (uint8_t)((port >> 8) & 0xff);
-				data[18] = (uint8_t)(port & 0xff);
+				data[17] = (uint8_t)(port >> 8U);
+				data[18] = (uint8_t)port;
 				return 19;
 			default:
 				data[0] = 0;

+ 45 - 43
node/Locator.hpp

@@ -16,6 +16,7 @@
 
 #include <algorithm>
 #include <vector>
+#include <cstdint>
 
 #include "Constants.hpp"
 #include "Endpoint.hpp"
@@ -35,7 +36,12 @@ namespace ZeroTier {
 class Locator
 {
 public:
-	ZT_ALWAYS_INLINE Locator() : _ts(0),_endpointCount(0),_signatureLength(0) {}
+	ZT_ALWAYS_INLINE Locator() { this->clear(); }
+
+	/**
+	 * Zero the Locator data structure
+	 */
+	ZT_ALWAYS_INLINE void clear() { memset(reinterpret_cast<void *>(this),0,sizeof(Locator)); }
 
 	/**
 	 * @return Timestamp (a.k.a. revision number) set by Location signer
@@ -43,31 +49,42 @@ public:
 	ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
 
 	/**
-	 * Create and sign a Locator
+	 * @return True if locator is signed
+	 */
+	ZT_ALWAYS_INLINE bool isSigned() const { return (_signatureLength > 0); }
+
+	/**
+	 * Add an endpoint to this locator if not already present
 	 *
-	 * @param ts Timestamp
-	 * @param id Identity (must include secret to allow signing)
-	 * @param at Array of Endpoint objects specifying where this peer might be found
-	 * @param endpointCount Number of endpoints (max: ZT_LOCATOR_MAX_ENDPOINTS)
-	 * @return True if init and sign were successful
+	 * @param ep Endpoint to add
+	 * @return True if endpoint was added (or already present), false if locator is full
 	 */
-	inline bool create(const int64_t ts,const Identity &id,const Endpoint *restrict at,const unsigned int endpointCount)
+	inline bool add(const Endpoint &ep)
 	{
-		if ((endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(!id.hasPrivate()))
+		if (_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS)
 			return false;
-		_ts = ts;
-		for(unsigned int i=0;i<endpointCount;++i)
-			_at[i] = at[i];
-		_endpointCount = endpointCount;
+		if (!std::binary_search(_at,_at + _endpointCount,ep)) {
+			_at[_endpointCount++] = ep;
+			std::sort(_at,_at + _endpointCount);
+		}
+		return true;
+	}
 
+	/**
+	 * Sign this locator
+	 *
+	 * @param id Identity that includes private key
+	 * @return True if signature successful
+	 */
+	inline bool sign(const int64_t ts,const Identity &id)
+	{
 		uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
-		const unsigned int signLen = marshal(signData,true);
-		if (signLen == 0)
+		if (!id.hasPrivate())
 			return false;
-		if ((_signatureLength = id.sign(signData,signLen,_signature,sizeof(_signature))) == 0)
-			return false;
-
-		return true;
+		_ts = ts;
+		const unsigned int signLen = marshal(signData,true);
+		_signatureLength = id.sign(signData, signLen, _signature, sizeof(_signature));
+		return (_signatureLength > 0);
 	}
 
 	/**
@@ -85,26 +102,19 @@ public:
 		return id.verify(signData,signLen,_signature,_signatureLength);
 	}
 
-	ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); }
+	explicit ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); }
 
 	// Marshal interface ///////////////////////////////////////////////////////
 	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
+	inline int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature = false) const
 	{
 		if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
 			return -1;
 
-		data[0] = (uint8_t)((uint64_t)_ts >> 56);
-		data[1] = (uint8_t)((uint64_t)_ts >> 48);
-		data[2] = (uint8_t)((uint64_t)_ts >> 40);
-		data[3] = (uint8_t)((uint64_t)_ts >> 32);
-		data[4] = (uint8_t)((uint64_t)_ts >> 24);
-		data[5] = (uint8_t)((uint64_t)_ts >> 16);
-		data[6] = (uint8_t)((uint64_t)_ts >> 8);
-		data[7] = (uint8_t)((uint64_t)_ts);
+		Utils::putUInt64(data,(uint64_t)_ts);
 		int p = 8;
 
-		data[p++] = (uint8_t)(_endpointCount >> 8);
+		data[p++] = (uint8_t)(_endpointCount >> 8U);
 		data[p++] = (uint8_t)_endpointCount;
 		for(unsigned int i=0;i<_endpointCount;++i) {
 			int tmp = _at[i].marshal(data + p);
@@ -114,10 +124,10 @@ public:
 		}
 
 		if (!excludeSignature) {
-			data[p++] = (uint8_t)(_signatureLength >> 8);
+			data[p++] = (uint8_t)(_signatureLength >> 8U);
 			data[p++] = (uint8_t)_signatureLength;
 			memcpy(data + p,_signature,_signatureLength);
-			p += _signatureLength;
+			p += (int)_signatureLength;
 		}
 
 		return p;
@@ -127,21 +137,13 @@ public:
 		if (len <= (8 + 48))
 			return -1;
 
-		uint64_t ts = ((uint64_t)data[0] << 56);
-		ts |= ((uint64_t)data[1] << 48);
-		ts |= ((uint64_t)data[2] << 40);
-		ts |= ((uint64_t)data[3] << 32);
-		ts |= ((uint64_t)data[4] << 24);
-		ts |= ((uint64_t)data[5] << 16);
-		ts |= ((uint64_t)data[6] << 8);
-		ts |= (uint64_t)data[7];
-		_ts = (int64_t)ts;
+		_ts = (int64_t)Utils::readUInt64(data);
 		int p = 8;
 
 		if ((p + 2) > len)
 			return -1;
 		unsigned int ec = (int)data[p++];
-		ec <<= 8;
+		ec <<= 8U;
 		ec |= data[p++];
 		if (ec > ZT_LOCATOR_MAX_ENDPOINTS)
 			return -1;
@@ -156,7 +158,7 @@ public:
 		if ((p + 2) > len)
 			return -1;
 		unsigned int sl = data[p++];
-		sl <<= 8;
+		sl <<= 8U;
 		sl |= data[p++];
 		if (sl > ZT_SIGNATURE_BUFFER_SIZE)
 			return -1;

+ 15 - 15
node/Membership.hpp

@@ -68,7 +68,7 @@ public:
 	/**
 	 * @return Time we last pushed credentials to this member
 	 */
-	inline int64_t lastPushedCredentials() const { return _lastPushedCredentials; }
+	ZT_ALWAYS_INLINE int64_t lastPushedCredentials() const { return _lastPushedCredentials; }
 
 	/**
 	 * Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true
@@ -76,7 +76,7 @@ public:
 	 * @param now Current time
 	 * @return True if we should update multicasts
 	 */
-	inline bool multicastLikeGate(const int64_t now)
+	ZT_ALWAYS_INLINE bool multicastLikeGate(const int64_t now)
 	{
 		if ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD) {
 			_lastUpdatedMulticast = now;
@@ -91,7 +91,7 @@ public:
 	 * @param nconf Our network config
 	 * @return True if this peer is allowed on this network at all
 	 */
-	inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
+	ZT_ALWAYS_INLINE bool isAllowedOnNetwork(const NetworkConfig &nconf) const
 	{
 		if (nconf.isPublic()) return true; // public network
 		if (_com.timestamp() <= _comRevocationThreshold) return false; // COM has been revoked
@@ -107,7 +107,7 @@ public:
 	 * @return True if this peer has a certificate of ownership for the given resource
 	 */
 	template<typename T>
-	inline bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const
+	ZT_ALWAYS_INLINE bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const
 	{
 		if (_isUnspoofableAddress(nconf,r))
 			return true;
@@ -128,7 +128,7 @@ public:
 	 * @param id Tag ID
 	 * @return Pointer to tag or NULL if not found
 	 */
-	inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
+	ZT_ALWAYS_INLINE const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
 	{
 		const Tag *const t = _remoteTags.get(id);
 		return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
@@ -146,7 +146,7 @@ public:
 	 * @param now Current time
 	 * @param nconf Current network configuration
 	 */
-	void clean(const int64_t now,const NetworkConfig &nconf);
+	void clean(int64_t now,const NetworkConfig &nconf);
 
 	/**
 	 * Generates a key for internal use in indexing credentials by type and credential ID
@@ -156,29 +156,29 @@ public:
 	/**
 	 * @return Bytes received so far
 	 */
-	inline uint64_t receivedBytes() const { return _received; }
+	ZT_ALWAYS_INLINE uint64_t receivedBytes() const { return _received; }
 
 	/**
 	 * @return Bytes sent so far
 	 */
-	inline uint64_t sentBytes() const { return _sent; }
+	ZT_ALWAYS_INLINE uint64_t sentBytes() const { return _sent; }
 
 	/**
 	 * @param bytes Bytes received
 	 */
-	inline void logReceivedBytes(const unsigned int bytes) { _received = (uint64_t)bytes; }
+	ZT_ALWAYS_INLINE void logReceivedBytes(const unsigned int bytes) { _received = (uint64_t)bytes; }
 
 	/**
 	 * @param bytes Bytes sent
 	 */
-	inline void logSentBytes(const unsigned int bytes) { _sent = (uint64_t)bytes; }
+	ZT_ALWAYS_INLINE void logSentBytes(const unsigned int bytes) { _sent = (uint64_t)bytes; }
 
 private:
 	// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT
 	// address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to
 	// always return true for them. A certificate is not required for these.
-	inline bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; }
-	inline bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const
+	ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; }
+	ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const
 	{
 		if ((ip.isV6())&&(nconf.ndpEmulation())) {
 			const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));
@@ -219,7 +219,7 @@ private:
 	// This compares the remote credential's timestamp to the timestamp in our network config
 	// plus or minus the permitted maximum timestamp delta.
 	template<typename C>
-	inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
+	ZT_ALWAYS_INLINE bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
 	{
 		const int64_t ts = remoteCredential.timestamp();
 		if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) {
@@ -271,7 +271,7 @@ public:
 	class CapabilityIterator
 	{
 	public:
-		inline CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
+		ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
 			_hti(m._remoteCaps),
 			_k((uint32_t *)0),
 			_c((Capability *)0),
@@ -280,7 +280,7 @@ public:
 		{
 		}
 
-		inline Capability *next()
+		ZT_ALWAYS_INLINE Capability *next()
 		{
 			while (_hti.next(_k,_c)) {
 				if (_m._isCredentialTimestampValid(_nconf,*_c))

+ 76 - 217
node/Node.cpp

@@ -11,11 +11,11 @@
  */
 /****/
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdint.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstdarg>
+#include <cstring>
+#include <cstdint>
 
 #include "Constants.hpp"
 #include "SharedPtr.hpp"
@@ -40,10 +40,10 @@ namespace ZeroTier {
 /* Public Node interface (C++, exposed via CAPI bindings)                   */
 /****************************************************************************/
 
-Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now) :
+Node::Node(void *uPtr, void *tPtr, const struct ZT_Node_Callbacks *callbacks, int64_t now) :
 	_RR(this),
 	RR(&_RR),
-	_uPtr(uptr),
+	_uPtr(uPtr),
 	_networks(8),
 	_now(now),
 	_lastPing(0),
@@ -61,7 +61,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
 	uint64_t idtmp[2];
 	idtmp[0] = 0; idtmp[1] = 0;
 	char tmp[2048];
-	int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp,sizeof(tmp) - 1);
+	int n = stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, tmp, sizeof(tmp) - 1);
 	if (n > 0) {
 		tmp[n] = (char)0;
 		if (RR->identity.fromString(tmp)) {
@@ -77,14 +77,14 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
 		RR->identity.toString(false,RR->publicIdentityStr);
 		RR->identity.toString(true,RR->secretIdentityStr);
 		idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
-		stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,RR->secretIdentityStr,(unsigned int)strlen(RR->secretIdentityStr));
-		stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr));
+		stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, RR->secretIdentityStr, (unsigned int)strlen(RR->secretIdentityStr));
+		stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
 	} else {
 		idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
-		n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1);
+		n = stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, tmp, sizeof(tmp) - 1);
 		if ((n > 0)&&(n < (int)sizeof(RR->publicIdentityStr))&&(n < (int)sizeof(tmp))) {
-			if (memcmp(tmp,RR->publicIdentityStr,n))
-				stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr));
+			if (memcmp(tmp,RR->publicIdentityStr,n) != 0)
+				stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
 		}
 	}
 
@@ -117,7 +117,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
 		throw;
 	}
 
-	postEvent(tptr,ZT_EVENT_UP);
+	postEvent(tPtr, ZT_EVENT_UP);
 }
 
 Node::~Node()
@@ -130,7 +130,7 @@ Node::~Node()
 	if (RR->topology) RR->topology->~Topology();
 	if (RR->sw) RR->sw->~Switch();
 	if (RR->t) RR->t->~Trace();
-	::free(RR->rtmem);
+	free(RR->rtmem);
 }
 
 ZT_ResultCode Node::processWirePacket(
@@ -169,74 +169,42 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
 	}
 }
 
-// This is passed as the argument to the DNS request handler and
-// aggregates results.
-struct _processBackgroundTasks_dnsResultAccumulator
+// This function object is run past every peer every ZT_PEER_PING_PERIOD.
+struct _processBackgroundTasks_ping_eachPeer
 {
-	_processBackgroundTasks_dnsResultAccumulator(const Str &n) : dnsName(n) {}
-	Str dnsName;
-	std::vector<Str> txtRecords;
-};
+	ZT_ALWAYS_INLINE bool operator()(const SharedPtr<Peer> &peer,const bool isRoot)
+	{
+		unsigned int v4SendCount = 0,v6SendCount = 0;
+		peer->ping(tPtr,now,v4SendCount,v6SendCount);
 
-static const ZT_DNSRecordType s_txtRecordType[1] = { ZT_DNS_RECORD_TXT };
+		if (isRoot) {
+			if ((now - peer->lastReceive()) <= ZT_PEER_PING_PERIOD)
+				online = true;
 
-struct _processBackgroundTasks_eachRootName
-{
-	ZT_Node_Callbacks *cb;
-	Node *n;
-	void *uPtr;
-	void *tPtr;
-	bool updateAll;
+			if (v4SendCount == 0) {
+				InetAddress try4;
+				parent->externalPathLookup(tPtr,peer->identity(),AF_INET,try4);
+				if (try4.ss_family == AF_INET)
+					peer->sendHELLO(tPtr,-1,try4,now);
+			}
 
-	inline bool operator()(const Str &dnsName,const Locator &loc)
-	{
-		if ((strchr(dnsName.c_str(),'.'))&&((updateAll)||(!loc))) {
-			_processBackgroundTasks_dnsResultAccumulator *dnsReq = new _processBackgroundTasks_dnsResultAccumulator(dnsName);
-			cb->dnsResolver(reinterpret_cast<ZT_Node *>(n),uPtr,tPtr,s_txtRecordType,1,dnsName.c_str(),(uintptr_t)dnsReq);
+			if (v6SendCount == 0) {
+				InetAddress try6;
+				parent->externalPathLookup(tPtr,peer->identity(),AF_INET6,try6);
+				if (try6.ss_family == AF_INET6)
+					peer->sendHELLO(tPtr,-1,try6,now);
+			}
 		}
-		return true;
-	}
-};
 
-struct _processBackgroundTasks_ping_eachRoot
-{
-	Hashtable< void *,bool > roots;
-	int64_t now;
-	void *tPtr;
-	bool online;
-
-	inline bool operator()(const SharedPtr<Peer> &peer,const std::vector<InetAddress> &addrs)
-	{
-		unsigned int v4SendCount = 0,v6SendCount = 0;
-		peer->ping(tPtr,now,v4SendCount,v6SendCount);
-		for(std::vector<InetAddress>::const_iterator a(addrs.begin());a!=addrs.end();++a) {
-			if ( ((a->isV4())&&(v4SendCount == 0)) || ((a->isV6())&&(v6SendCount == 0)) )
-				peer->sendHELLO(tPtr,-1,*a,now);
-		}
-		if (!online)
-			online = ((now - peer->lastReceive()) <= ((ZT_PEER_PING_PERIOD * 2) + 5000));
-		roots.set((void *)peer.ptr(),true);
 		return true;
 	}
-};
-
-struct _processBackgroundTasks_ping_eachPeer
-{
 	int64_t now;
+	Node *parent;
 	void *tPtr;
-	Hashtable< void *,bool > *roots;
-
-	inline bool operator()(const SharedPtr<Peer> &peer)
-	{
-		if (!roots->contains((void *)peer.ptr())) {
-			unsigned int v4SendCount = 0,v6SendCount = 0;
-			peer->ping(tPtr,now,v4SendCount,v6SendCount);
-		}
-		return true;
-	}
+	bool online;
 };
 
-ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
+ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline)
 {
 	_now = now;
 	Mutex::Lock bl(_backgroundTasksLock);
@@ -252,41 +220,19 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
 	if ((now - _lastPing) >= ZT_PEER_PING_PERIOD) {
 		_lastPing = now;
 		try {
-			// Periodically refresh locators for dynamic roots from their DNS names.
-			if (_cb.dnsResolver) {
-				_processBackgroundTasks_eachRootName cr;
-				cr.cb = &_cb;
-				cr.n = this;
-				cr.uPtr = _uPtr;
-				cr.tPtr = tptr;
-				if ((now - _lastDynamicRootUpdate) >= ZT_DYNAMIC_ROOT_UPDATE_PERIOD) {
-					_lastDynamicRootUpdate = now;
-					cr.updateAll = true;
-				} else {
-					cr.updateAll = false;
-				}
-				RR->topology->eachRootName(cr);
-			}
-
-			// Ping each root explicitly no matter what
-			_processBackgroundTasks_ping_eachRoot rf;
-			rf.now = now;
-			rf.tPtr = tptr;
-			rf.online = false;
-			RR->topology->eachRoot(rf);
-
-			// Ping peers that are active and we want to keep alive
 			_processBackgroundTasks_ping_eachPeer pf;
 			pf.now = now;
-			pf.tPtr = tptr;
-			pf.roots = &rf.roots;
-			RR->topology->eachPeer(pf);
-
-			// Update online status based on whether we can reach a root
-			if (rf.online != _online) {
-				_online = rf.online;
-				postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
+			pf.parent = this;
+			pf.tPtr = tPtr;
+			pf.online = false;
+			RR->topology->eachPeerWithRoot<_processBackgroundTasks_ping_eachPeer &>(pf);
+
+			if (pf.online != _online) {
+				_online = pf.online;
+				postEvent(tPtr, _online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
 			}
+
+			RR->topology->rankRoots(now);
 		} catch ( ... ) {
 			return ZT_RESULT_FATAL_ERROR_INTERNAL;
 		}
@@ -300,7 +246,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
 			uint64_t *nwid = (uint64_t *)0;
 			SharedPtr<Network> *network = (SharedPtr<Network> *)0;
 			while (i.next(nwid,network)) {
-				(*network)->doPeriodicTasks(tptr,now);
+				(*network)->doPeriodicTasks(tPtr, now);
 			}
 		}
 	}
@@ -332,7 +278,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
 	}
 
 	try {
-		*nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min((unsigned long)ZT_MAX_TIMER_TASK_INTERVAL,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_MIN_TIMER_TASK_INTERVAL);
+		*nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min((unsigned long)ZT_MAX_TIMER_TASK_INTERVAL,RR->sw->doTimerTasks(tPtr, now)), (unsigned long)ZT_MIN_TIMER_TASK_INTERVAL);
 	} catch ( ... ) {
 		return ZT_RESULT_FATAL_ERROR_INTERNAL;
 	}
@@ -340,30 +286,6 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
 	return ZT_RESULT_OK;
 }
 
-void Node::processDNSResult(
-	void *tptr,
-	uintptr_t dnsRequestID,
-	const char *name,
-	enum ZT_DNSRecordType recordType,
-	const void *result,
-	unsigned int resultLength,
-	int resultIsString)
-{
-	if (dnsRequestID) {
-		_processBackgroundTasks_dnsResultAccumulator *const acc = reinterpret_cast<_processBackgroundTasks_dnsResultAccumulator *>(dnsRequestID);
-		if (recordType == ZT_DNS_RECORD_TXT) {
-			if (result)
-				acc->txtRecords.emplace_back(reinterpret_cast<const char *>(result));
-		} else if (recordType == ZT_DNS_RECORD__END_OF_RESULTS) {
-			Locator loc;
-			if (loc.decodeTxtRecords(acc->dnsName,acc->txtRecords.begin(),acc->txtRecords.end())) {
-				RR->topology->setRoot(acc->dnsName,loc);
-				delete acc;
-			}
-		}
-	}
-}
-
 ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr)
 {
 	Mutex::Lock _l(_networks_m);
@@ -423,44 +345,25 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u
 	} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
 }
 
-ZT_RootList *Node::listRoots(int64_t now)
-{
-	return RR->topology->apiRoots(now);
-}
-
-enum ZT_ResultCode Node::setRoot(const char *name,const void *locator,unsigned int locatorSize)
+ZT_ResultCode Node::addRoot(const char *identity)
 {
-	try {
-		Locator loc;
-		if ((locator)&&(locatorSize > 0)&&(locatorSize < 65535)) {
-			ScopedPtr< Buffer<65536> > locbuf(new Buffer<65536>());
-			locbuf->append(locator,locatorSize);
-			loc.deserialize(*locbuf,0);
-			if (!loc.verify())
-				return ZT_RESULT_ERROR_BAD_PARAMETER;
-		}
-		Str n;
-		if ((!name)||(strlen(name) == 0)) {
-			if (!loc)
-				return ZT_RESULT_ERROR_BAD_PARAMETER; /* no name and no locator */
-			char tmp[16];
-			loc.id().address().toString(tmp);
-			n = tmp;
-		} else {
-			n = name;
-		}
-		return RR->topology->setRoot(n,loc) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED;
-	} catch ( ... ) {
+	if (!identity)
 		return ZT_RESULT_ERROR_BAD_PARAMETER;
-	}
+	Identity id;
+	if (!id.fromString(identity))
+		return ZT_RESULT_ERROR_BAD_PARAMETER;
+	RR->topology->addRoot(id);
+	return ZT_RESULT_OK;
 }
 
-enum ZT_ResultCode Node::removeRoot(const char *name)
+ZT_ResultCode Node::removeRoot(const char *identity)
 {
-	try {
-		if (name)
-			RR->topology->removeRoot(Str(name));
-	} catch ( ... ) {}
+	if (!identity)
+		return ZT_RESULT_ERROR_BAD_PARAMETER;
+	Identity id;
+	if (!id.fromString(identity))
+		return ZT_RESULT_ERROR_BAD_PARAMETER;
+	RR->topology->removeRoot(id);
 	return ZT_RESULT_OK;
 }
 
@@ -631,33 +534,6 @@ void Node::setController(void *networkControllerInstance)
 /* Node methods used only within node/                                      */
 /****************************************************************************/
 
-SharedPtr< const Locator > Node::locator()
-{
-	Mutex::Lock lck(_locator_m);
-	if (!_locator) {
-		Locator *l = new Locator();
-		try {
-			RR->topology->eachRoot([l](const SharedPtr<Peer> &p,const std::vector<InetAddress> &phyAddr) -> bool {
-				l->add(p->identity());
-				return true;
-			});
-			{
-				Mutex::Lock lck2(_localInterfaceAddresses_m);
-				for(std::vector< ZT_InterfaceAddress >::const_iterator a(_localInterfaceAddresses.begin());a!=_localInterfaceAddresses.end();++a) {
-					if (a->permanent != 0) {
-						l->add(*reinterpret_cast<const InetAddress *>(&(a->address)));
-					}
-				}
-			}
-		} catch ( ... ) {
-			delete l;
-			throw;
-		}
-		_locator.set(l);
-	}
-	return _locator;
-}
-
 bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress)
 {
 	if (!Path::isAddressValidForPath(remoteAddress))
@@ -679,6 +555,13 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,cons
 	return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),localSocket,reinterpret_cast<const struct sockaddr_storage *>(&remoteAddress)) != 0) : true);
 }
 
+bool Node::externalPathLookup(void *tPtr,const Identity &id,int family,InetAddress &addr)
+{
+	char idStr[ZT_IDENTITY_STRING_BUFFER_LENGTH];
+	id.toString(false,idStr);
+	return (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,id.address().toInt(),idStr,family,reinterpret_cast<sockaddr_storage *>(&addr)) == ZT_RESULT_OK);
+}
+
 ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork, const ZT_PhysicalPathConfiguration *pathConfig)
 {
 	RR->topology->setPhysicalPathConfiguration(pathNetwork,pathConfig);
@@ -870,21 +753,6 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64
 	}
 }
 
-void ZT_Node_processDNSResult(
-	ZT_Node *node,
-	void *tptr,
-	uintptr_t dnsRequestID,
-	const char *name,
-	enum ZT_DNSRecordType recordType,
-	const void *result,
-	unsigned int resultLength,
-	int resultIsString)
-{
-	try {
-		reinterpret_cast<ZeroTier::Node *>(node)->processDNSResult(tptr,dnsRequestID,name,recordType,result,resultLength,resultIsString);
-	} catch ( ... ) {}
-}
-
 enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr)
 {
 	try {
@@ -929,19 +797,10 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint
 	}
 }
 
-ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now)
-{
-	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->listRoots(now);
-	} catch ( ... ) {
-		return nullptr;
-	}
-}
-
-enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize)
+enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,const char *identity)
 {
 	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->setRoot(name,locator,locatorSize);
+		return reinterpret_cast<ZeroTier::Node *>(node)->addRoot(identity);
 	} catch (std::bad_alloc &exc) {
 		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
 	} catch ( ... ) {
@@ -949,10 +808,10 @@ enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *lo
 	}
 }
 
-enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name)
+enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *identity)
 {
 	try {
-		return reinterpret_cast<ZeroTier::Node *>(node)->removeRoot(name);
+		return reinterpret_cast<ZeroTier::Node *>(node)->removeRoot(identity);
 	} catch (std::bad_alloc &exc) {
 		return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
 	} catch ( ... ) {

+ 29 - 61
node/Node.hpp

@@ -51,7 +51,7 @@ class Locator;
 class Node : public NetworkController::Sender
 {
 public:
-	Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
+	Node(void *uPtr, void *tPtr, const struct ZT_Node_Callbacks *callbacks, int64_t now);
 	virtual ~Node();
 
 	// Get rid of alignment warnings on 32-bit Windows and possibly improve performance
@@ -81,22 +81,13 @@ public:
 		const void *frameData,
 		unsigned int frameLength,
 		volatile int64_t *nextBackgroundTaskDeadline);
-	ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline);
-	void processDNSResult(
-		void *tptr,
-		uintptr_t dnsRequestID,
-		const char *name,
-		enum ZT_DNSRecordType recordType,
-		const void *result,
-		unsigned int resultLength,
-		int resultIsString);
+	ZT_ResultCode processBackgroundTasks(void *tPtr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline);
 	ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr);
 	ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr);
 	ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
 	ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
-	ZT_RootList *listRoots(int64_t now);
-	enum ZT_ResultCode setRoot(const char *name,const void *locator,unsigned int locatorSize);
-	enum ZT_ResultCode removeRoot(const char *name);
+	ZT_ResultCode addRoot(const char *identity);
+	ZT_ResultCode removeRoot(const char *identity);
 	uint64_t address() const;
 	void status(ZT_NodeStatus *status) const;
 	ZT_PeerList *peers() const;
@@ -104,16 +95,15 @@ public:
 	ZT_VirtualNetworkList *networks() const;
 	void setNetworkUserPtr(uint64_t nwid,void *ptr);
 	void freeQueryResult(void *qr);
-	int addLocalInterfaceAddress(const struct sockaddr_storage *addr);
-	void clearLocalInterfaceAddresses();
+	void setInterfaceAddresses(const ZT_InterfaceAddress *addrs,unsigned int addrCount);
 	int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len);
 	void setController(void *networkControllerInstance);
 
 	// Internal functions ------------------------------------------------------
 
-	inline int64_t now() const { return _now; }
+	ZT_ALWAYS_INLINE int64_t now() const { return _now; }
 
-	inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
+	ZT_ALWAYS_INLINE bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
 	{
 		return (_cb.wirePacketSendFunction(
 			reinterpret_cast<ZT_Node *>(this),
@@ -126,7 +116,7 @@ public:
 			ttl) == 0);
 	}
 
-	inline void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
+	ZT_ALWAYS_INLINE void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
 	{
 		_cb.virtualNetworkFrameFunction(
 			reinterpret_cast<ZT_Node *>(this),
@@ -142,7 +132,7 @@ public:
 			len);
 	}
 
-	inline SharedPtr<Network> network(uint64_t nwid) const
+	ZT_ALWAYS_INLINE SharedPtr<Network> network(uint64_t nwid) const
 	{
 		Mutex::Lock _l(_networks_m);
 		const SharedPtr<Network> *n = _networks.get(nwid);
@@ -151,43 +141,22 @@ public:
 		return SharedPtr<Network>();
 	}
 
-	inline bool belongsToNetwork(uint64_t nwid) const
-	{
-		Mutex::Lock _l(_networks_m);
-		return _networks.contains(nwid);
-	}
-
-	inline std::vector< SharedPtr<Network> > allNetworks() const
-	{
-		std::vector< SharedPtr<Network> > nw;
-		Mutex::Lock _l(_networks_m);
-		Hashtable< uint64_t,SharedPtr<Network> >::Iterator i(*const_cast< Hashtable< uint64_t,SharedPtr<Network> > * >(&_networks));
-		uint64_t *k = (uint64_t *)0;
-		SharedPtr<Network> *v = (SharedPtr<Network> *)0;
-		while (i.next(k,v))
-			nw.push_back(*v);
-		return nw;
-	}
-
-	inline std::vector<ZT_InterfaceAddress> directPaths() const
+	ZT_ALWAYS_INLINE std::vector<ZT_InterfaceAddress> directPaths() const
 	{
 		Mutex::Lock _l(_localInterfaceAddresses_m);
 		return _localInterfaceAddresses;
 	}
 
-	void setInterfaceAddresses(const ZT_InterfaceAddress *addrs,unsigned int addrCount);
-
-	SharedPtr< const Locator > locator();
-	inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ev,md); }
-	inline void configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,nwid,nuptr,op,nc); }
-	inline bool online() const { return _online; }
-	inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,maxlen); }
-	inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,(int)len); }
-	inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,(const void *)0,-1); }
+	ZT_ALWAYS_INLINE void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ev,md); }
+	ZT_ALWAYS_INLINE void configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,nwid,nuptr,op,nc); }
+	ZT_ALWAYS_INLINE bool online() const { return _online; }
+	ZT_ALWAYS_INLINE int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,maxlen); }
+	ZT_ALWAYS_INLINE void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,(int)len); }
+	ZT_ALWAYS_INLINE void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,(const void *)0,-1); }
 	bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress);
-	inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast<struct sockaddr_storage *>(&addr)) != 0) : false ); }
+	bool externalPathLookup(void *tPtr,const Identity &id,int family,InetAddress &addr);
 	ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
-	inline const Identity &identity() const { return _RR.identity; }
+	ZT_ALWAYS_INLINE const Identity &identity() const { return _RR.identity; }
 
 	/**
 	 * Register that we are expecting a reply to a packet ID
@@ -198,9 +167,9 @@ public:
 	 *
 	 * @param packetId Packet ID to expect reply to
 	 */
-	inline void expectReplyTo(const uint64_t packetId)
+	ZT_ALWAYS_INLINE void expectReplyTo(const uint64_t packetId)
 	{
-		const unsigned long pid2 = (unsigned long)(packetId >> 32);
+		const unsigned long pid2 = (unsigned long)(packetId >> 32U);
 		const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1);
 		_expectingRepliesTo[bucket][_expectingRepliesToBucketPtr[bucket]++ & ZT_EXPECTING_REPLIES_BUCKET_MASK2] = (uint32_t)pid2;
 	}
@@ -215,7 +184,7 @@ public:
 	 * @param packetId Packet ID to check
 	 * @return True if we're expecting a reply
 	 */
-	inline bool expectingReplyTo(const uint64_t packetId) const
+	ZT_ALWAYS_INLINE bool expectingReplyTo(const uint64_t packetId) const
 	{
 		const uint32_t pid2 = (uint32_t)(packetId >> 32);
 		const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1);
@@ -233,7 +202,7 @@ public:
 	 * @param from Source address of packet
 	 * @return True if within rate limits
 	 */
-	inline bool rateGateIdentityVerification(const int64_t now,const InetAddress &from)
+	ZT_ALWAYS_INLINE bool rateGateIdentityVerification(const int64_t now,const InetAddress &from)
 	{
 		unsigned long iph = from.rateGateHash();
 		if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) {
@@ -247,9 +216,6 @@ public:
 	virtual void ncSendRevocation(const Address &destination,const Revocation &rev);
 	virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode);
 
-	inline void setMultipathMode(uint8_t mode) { _multipathMode = mode; }
-	inline uint8_t getMultipathMode() { return _multipathMode; }
-
 	inline bool localControllerHasAuthorized(const int64_t now,const uint64_t nwid,const Address &addr) const
 	{
 		_localControllerAuthorizations_m.lock();
@@ -260,6 +226,9 @@ public:
 		return false;
 	}
 
+	inline void setMultipathMode(uint8_t mode) { _multipathMode = mode; }
+	inline uint8_t getMultipathMode() { return _multipathMode; }
+
 private:
 	RuntimeEnvironment _RR;
 	RuntimeEnvironment *RR;
@@ -281,10 +250,10 @@ private:
 	struct _LocalControllerAuth
 	{
 		uint64_t nwid,address;
-		inline _LocalControllerAuth(const uint64_t nwid_,const Address &address_) : nwid(nwid_),address(address_.toInt()) {}
-		inline unsigned long hashCode() const { return (unsigned long)(nwid ^ address); }
-		inline bool operator==(const _LocalControllerAuth &a) const { return ((a.nwid == nwid)&&(a.address == address)); }
-		inline bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); }
+		ZT_ALWAYS_INLINE _LocalControllerAuth(const uint64_t nwid_,const Address &address_) : nwid(nwid_),address(address_.toInt()) {}
+		ZT_ALWAYS_INLINE unsigned long hashCode() const { return (unsigned long)(nwid ^ address); }
+		ZT_ALWAYS_INLINE bool operator==(const _LocalControllerAuth &a) const { return ((a.nwid == nwid)&&(a.address == address)); }
+		ZT_ALWAYS_INLINE bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); }
 	};
 	Hashtable< _LocalControllerAuth,int64_t > _localControllerAuthorizations;
 	Hashtable< uint64_t,SharedPtr<Network> > _networks;
@@ -293,7 +262,6 @@ private:
 
 	Mutex _localControllerAuthorizations_m;
 	Mutex _networks_m;
-	Mutex _locator_m;
 	Mutex _localInterfaceAddresses_m;
 	Mutex _backgroundTasksLock;
 

+ 6 - 5
node/Path.hpp

@@ -28,6 +28,7 @@
 #include "Utils.hpp"
 #include "RingBuffer.hpp"
 #include "Packet.hpp"
+#include "Mutex.hpp"
 
 /**
  * Maximum return value of preferenceRank()
@@ -52,9 +53,9 @@ public:
 	class HashKey
 	{
 	public:
-		inline HashKey() {}
+		ZT_ALWAYS_INLINE HashKey() {}
 
-		inline HashKey(const int64_t l,const InetAddress &r)
+		ZT_ALWAYS_INLINE HashKey(const int64_t l,const InetAddress &r)
 		{
 			if (r.ss_family == AF_INET) {
 				_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr;
@@ -69,10 +70,10 @@ public:
 			}
 		}
 
-		inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); }
+		ZT_ALWAYS_INLINE unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); }
 
-		inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); }
-		inline bool operator!=(const HashKey &k) const { return (!(*this == k)); }
+		ZT_ALWAYS_INLINE bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); }
+		ZT_ALWAYS_INLINE bool operator!=(const HashKey &k) const { return (!(*this == k)); }
 
 	private:
 		uint64_t _k[3];

+ 0 - 4
node/Peer.cpp

@@ -691,12 +691,8 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
 
 void Peer::ping(void *tPtr,int64_t now,unsigned int &v4SendCount,unsigned int &v6SendCount)
 {
-	v4SendCount = 0;
-	v6SendCount = 0;
-
 	Mutex::Lock _l(_paths_m);
 
-	// Emit traces regarding aggregate link status
 	if (_canUseMultipath) {
 		int alivePathCount = aggregateLinkPhysicalPathCount();
 		if ((now - _lastAggregateStatsReport) > ZT_PATH_AGGREGATE_STATS_REPORT_INTERVAL) {

+ 27 - 51
node/Peer.hpp

@@ -30,8 +30,6 @@
 #include "Hashtable.hpp"
 #include "Mutex.hpp"
 
-#define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2))
-
 namespace ZeroTier {
 
 /**
@@ -45,7 +43,7 @@ private:
 	inline Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
 
 public:
-	inline ~Peer() { Utils::burn(_key,sizeof(_key)); }
+	ZT_ALWAYS_INLINE ~Peer() { Utils::burn(_key,sizeof(_key)); }
 
 	/**
 	 * Construct a new peer
@@ -60,12 +58,12 @@ public:
 	/**
 	 * @return This peer's ZT address (short for identity().address())
 	 */
-	inline const Address &address() const { return _id.address(); }
+	ZT_ALWAYS_INLINE const Address &address() const { return _id.address(); }
 
 	/**
 	 * @return This peer's identity
 	 */
-	inline const Identity &identity() const { return _id; }
+	ZT_ALWAYS_INLINE const Identity &identity() const { return _id; }
 
 	/**
 	 * Log receipt of an authenticated packet
@@ -85,13 +83,13 @@ public:
 	void received(
 		void *tPtr,
 		const SharedPtr<Path> &path,
-		const unsigned int hops,
-		const uint64_t packetId,
-		const unsigned int payloadLength,
-		const Packet::Verb verb,
-		const uint64_t inRePacketId,
-		const Packet::Verb inReVerb,
-		const uint64_t networkId);
+		unsigned int hops,
+		uint64_t packetId,
+		unsigned int payloadLength,
+		Packet::Verb verb,
+		uint64_t inRePacketId,
+		Packet::Verb inReVerb,
+		uint64_t networkId);
 
 	/**
 	 * Check whether we have an active path to this peer via the given address
@@ -122,7 +120,7 @@ public:
 	 * @param force If true, send even if path is not alive
 	 * @return True if we actually sent something
 	 */
-	inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force)
+	ZT_ALWAYS_INLINE bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force)
 	{
 		SharedPtr<Path> bp(getAppropriatePath(now,force));
 		if (bp)
@@ -139,7 +137,7 @@ public:
 	 * @param verb Packet verb
 	 * @param now Current time
 	 */
-	void recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
+	void recordOutgoingPacket(const SharedPtr<Path> &path, uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
 
 	/**
 	 * Record statistics on incoming packets
@@ -150,7 +148,7 @@ public:
 	 * @param verb Packet verb
 	 * @param now Current time
 	 */
-	void recordIncomingPacket(void *tPtr, const SharedPtr<Path> &path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
+	void recordIncomingPacket(void *tPtr, const SharedPtr<Path> &path, uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
 
 	/**
 	 * Send an ACK to peer for the most recent packets received
@@ -160,7 +158,7 @@ public:
 	 * @param atAddress Destination for the ACK packet
 	 * @param now Current time
 	 */
-	void sendACK(void *tPtr, const SharedPtr<Path> &path, const int64_t localSocket,const InetAddress &atAddress,int64_t now);
+	void sendACK(void *tPtr, const SharedPtr<Path> &path, int64_t localSocket,const InetAddress &atAddress,int64_t now);
 
 	/**
 	 * Send a QoS packet to peer so that it can evaluate the quality of this link
@@ -170,7 +168,7 @@ public:
 	 * @param atAddress Destination for the QoS packet
 	 * @param now Current time
 	 */
-	void sendQOS_MEASUREMENT(void *tPtr, const SharedPtr<Path> &path, const int64_t localSocket,const InetAddress &atAddress,int64_t now);
+	void sendQOS_MEASUREMENT(void *tPtr, const SharedPtr<Path> &path, int64_t localSocket,const InetAddress &atAddress,int64_t now);
 
 	/**
 	 * Compute relative quality values and allocations for the components of the aggregate link
@@ -217,7 +215,7 @@ public:
 	/**
 	 * Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path
 	 */
-	void introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &other) const;
+	void introduce(void *tPtr,int64_t now,const SharedPtr<Peer> &other) const;
 
 	/**
 	 * Send a HELLO to this peer at a specified physical address
@@ -229,7 +227,7 @@ public:
 	 * @param atAddress Destination address
 	 * @param now Current time
 	 */
-	void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now);
+	void sendHELLO(void *tPtr,int64_t localSocket,const InetAddress &atAddress,int64_t now);
 
 	/**
 	 * Send pings to active paths
@@ -276,17 +274,17 @@ public:
 	/**
 	 * @return Time of last receive of anything, whether direct or relayed
 	 */
-	inline int64_t lastReceive() const { return _lastReceive; }
+	ZT_ALWAYS_INLINE int64_t lastReceive() const { return _lastReceive; }
 
 	/**
 	 * @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT
 	 */
-	inline bool alive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
+	ZT_ALWAYS_INLINE bool alive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
 
 	/**
 	 * @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths
 	 */
-	inline unsigned int latency(const int64_t now)
+	ZT_ALWAYS_INLINE unsigned int latency(const int64_t now)
 	{
 		if (_canUseMultipath) {
 			return (int)computeAggregateLinkMeanLatency();
@@ -298,32 +296,10 @@ public:
 		}
 	}
 
-	/**
-	 * This computes a quality score for relays and root servers
-	 *
-	 * If we haven't heard anything from these in ZT_PEER_ACTIVITY_TIMEOUT, they
-	 * receive the worst possible quality (max unsigned int). Otherwise the
-	 * quality is a product of latency and the number of potential missed
-	 * pings. This causes roots and relays to switch over a bit faster if they
-	 * fail.
-	 *
-	 * @return Relay quality score computed from latency and other factors, lower is better
-	 */
-	inline unsigned int relayQuality(const int64_t now)
-	{
-		const uint64_t tsr = now - _lastReceive;
-		if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT)
-			return (~(unsigned int)0);
-		unsigned int l = latency(now);
-		if (!l)
-			l = 0xffff;
-		return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1));
-	}
-
 	/**
 	 * @return 256-bit secret symmetric encryption key
 	 */
-	inline const unsigned char *key() const { return _key; }
+	ZT_ALWAYS_INLINE const unsigned char *key() const { return _key; }
 
 	/**
 	 * Set the currently known remote version of this peer's client
@@ -333,7 +309,7 @@ public:
 	 * @param vmin Minor version
 	 * @param vrev Revision
 	 */
-	inline void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev)
+	ZT_ALWAYS_INLINE void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev)
 	{
 		_vProto = (uint16_t)vproto;
 		_vMajor = (uint16_t)vmaj;
@@ -341,11 +317,11 @@ public:
 		_vRevision = (uint16_t)vrev;
 	}
 
-	inline unsigned int remoteVersionProtocol() const { return _vProto; }
-	inline unsigned int remoteVersionMajor() const { return _vMajor; }
-	inline unsigned int remoteVersionMinor() const { return _vMinor; }
-	inline unsigned int remoteVersionRevision() const { return _vRevision; }
-	inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
+	ZT_ALWAYS_INLINE unsigned int remoteVersionProtocol() const { return _vProto; }
+	ZT_ALWAYS_INLINE unsigned int remoteVersionMajor() const { return _vMajor; }
+	ZT_ALWAYS_INLINE unsigned int remoteVersionMinor() const { return _vMinor; }
+	ZT_ALWAYS_INLINE unsigned int remoteVersionRevision() const { return _vRevision; }
+	ZT_ALWAYS_INLINE bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
 
 	/**
 	 * Periodically update known multipath activation constraints. This is done so that we know when and when

+ 14 - 14
node/Revocation.hpp

@@ -45,9 +45,9 @@ class Revocation : public Credential
 	friend class Credential;
 
 public:
-	static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
+	static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
 
-	inline Revocation() :
+	ZT_ALWAYS_INLINE Revocation() :
 		_id(0),
 		_credentialId(0),
 		_networkId(0),
@@ -69,7 +69,7 @@ public:
 	 * @param tgt Target node whose credential(s) are being revoked
 	 * @param ct Credential type being revoked
 	 */
-	inline Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :
+	ZT_ALWAYS_INLINE Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :
 		_id(i),
 		_credentialId(cid),
 		_networkId(nwid),
@@ -82,16 +82,16 @@ public:
 	{
 	}
 
-	inline uint32_t id() const { return _id; }
-	inline uint32_t credentialId() const { return _credentialId; }
-	inline uint64_t networkId() const { return _networkId; }
-	inline int64_t threshold() const { return _threshold; }
-	inline const Address &target() const { return _target; }
-	inline const Address &signer() const { return _signedBy; }
-	inline Credential::Type type() const { return _type; }
-	inline const uint8_t *signature() const { return _signature; }
-	inline unsigned int signatureLength() const { return _signatureLength; }
-	inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
+	ZT_ALWAYS_INLINE uint32_t id() const { return _id; }
+	ZT_ALWAYS_INLINE uint32_t credentialId() const { return _credentialId; }
+	ZT_ALWAYS_INLINE uint64_t networkId() const { return _networkId; }
+	ZT_ALWAYS_INLINE int64_t threshold() const { return _threshold; }
+	ZT_ALWAYS_INLINE const Address &target() const { return _target; }
+	ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
+	ZT_ALWAYS_INLINE Credential::Type type() const { return _type; }
+	ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
+	ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
+	ZT_ALWAYS_INLINE bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
 
 	/**
 	 * @param signer Signing identity, must have private key
@@ -115,7 +115,7 @@ public:
 	 * @param RR Runtime environment to provide for peer lookup, etc.
 	 * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
 	 */
-	inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
+	ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
 
 	template<unsigned int C>
 	inline void serialize(Buffer<C> &b,const bool forSign = false) const

+ 0 - 1
node/SharedPtr.hpp

@@ -14,7 +14,6 @@
 #ifndef ZT_SHAREDPTR_HPP
 #define ZT_SHAREDPTR_HPP
 
-#include "Mutex.hpp"
 #include "AtomicCounter.hpp"
 
 namespace ZeroTier {

+ 24 - 24
node/Tag.hpp

@@ -52,9 +52,9 @@ class Tag : public Credential
 	friend class Credential;
 
 public:
-	static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; }
+	static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; }
 
-	inline Tag() :
+	ZT_ALWAYS_INLINE Tag() :
 		_id(0),
 		_value(0),
 		_networkId(0),
@@ -70,7 +70,7 @@ public:
 	 * @param id Tag ID
 	 * @param value Tag value
 	 */
-	inline Tag(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) :
+	ZT_ALWAYS_INLINE Tag(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) :
 		_id(id),
 		_value(value),
 		_networkId(nwid),
@@ -81,14 +81,14 @@ public:
 	{
 	}
 
-	inline uint32_t id() const { return _id; }
-	inline const uint32_t &value() const { return _value; }
-	inline uint64_t networkId() const { return _networkId; }
-	inline int64_t timestamp() const { return _ts; }
-	inline const Address &issuedTo() const { return _issuedTo; }
-	inline const Address &signer() const { return _signedBy; }
-	inline const uint8_t *signature() const { return _signature; }
-	inline unsigned int signatureLength() const { return _signatureLength; }
+	ZT_ALWAYS_INLINE uint32_t id() const { return _id; }
+	ZT_ALWAYS_INLINE const uint32_t &value() const { return _value; }
+	ZT_ALWAYS_INLINE uint64_t networkId() const { return _networkId; }
+	ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
+	ZT_ALWAYS_INLINE const Address &issuedTo() const { return _issuedTo; }
+	ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
+	ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
+	ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
 
 	/**
 	 * Sign this tag
@@ -114,7 +114,7 @@ public:
 	 * @param RR Runtime environment to allow identity lookup for signedBy
 	 * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
 	 */
-	inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
+	ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
 
 	template<unsigned int C>
 	inline void serialize(Buffer<C> &b,const bool forSign = false) const
@@ -172,23 +172,23 @@ public:
 	}
 
 	// Provides natural sort order by ID
-	inline bool operator<(const Tag &t) const { return (_id < t._id); }
+	ZT_ALWAYS_INLINE bool operator<(const Tag &t) const { return (_id < t._id); }
 
-	inline bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); }
-	inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); }
+	ZT_ALWAYS_INLINE bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); }
+	ZT_ALWAYS_INLINE bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); }
 
 	// For searching sorted arrays or lists of Tags by ID
 	struct IdComparePredicate
 	{
-		inline bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); }
-		inline bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); }
-		inline bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); }
-		inline bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); }
-		inline bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); }
-		inline bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); }
-		inline bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); }
-		inline bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); }
-		inline bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); }
+		ZT_ALWAYS_INLINE bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); }
+		ZT_ALWAYS_INLINE bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); }
+		ZT_ALWAYS_INLINE bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); }
+		ZT_ALWAYS_INLINE bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); }
+		ZT_ALWAYS_INLINE bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); }
+		ZT_ALWAYS_INLINE bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); }
+		ZT_ALWAYS_INLINE bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); }
+		ZT_ALWAYS_INLINE bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); }
+		ZT_ALWAYS_INLINE bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); }
 	};
 
 private:

+ 40 - 4
node/Topology.hpp

@@ -55,8 +55,6 @@ public:
 	{
 	}
 
-	ZT_ALWAYS_INLINE ~Topology() {}
-
 	/**
 	 * Add a peer to database
 	 *
@@ -173,6 +171,34 @@ public:
 		}
 	}
 
+	/**
+	 * Apply a function or function object to all peers
+	 *
+	 * This locks the peer map during execution, so calls to get() etc. during
+	 * eachPeer() will deadlock.
+	 *
+	 * @param f Function to apply
+	 * @tparam F Function or function object type
+	 */
+	template<typename F>
+	ZT_ALWAYS_INLINE void eachPeerWithRoot(F f)
+	{
+		Mutex::Lock l(_peers_l);
+
+		std::vector<uintptr_t> rootPeerPtrs;
+		for(std::vector< SharedPtr<Peer> >::iterator i(_rootPeers.begin());i!=_rootPeers.end();++i)
+			rootPeerPtrs.push_back((uintptr_t)i->ptr());
+		std::sort(rootPeerPtrs.begin(),rootPeerPtrs.end());
+
+		Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
+		Address *a = (Address *)0;
+		SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+		while (i.next(a,p)) {
+			if (!f(*((const SharedPtr<Peer> *)p),std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)p->ptr())))
+				break;
+		}
+	}
+
 	/**
 	 * Get the best relay to a given address, which may or may not be a root
 	 *
@@ -346,14 +372,24 @@ public:
 		return false;
 	}
 
+	/**
+	 * Sort roots in asecnding order of apparent latency
+	 *
+	 * @param now Current time
+	 */
+	ZT_ALWAYS_INLINE void rankRoots(const int64_t now)
+	{
+		Mutex::Lock l1(_peers_l);
+		std::sort(_rootPeers.begin(),_rootPeers.end(),_RootSortComparisonOperator(now));
+	}
+
 	/**
 	 * Do periodic tasks such as database cleanup
 	 */
-	inline void doPeriodicTasks(const int64_t now)
+	ZT_ALWAYS_INLINE void doPeriodicTasks(const int64_t now)
 	{
 		{
 			Mutex::Lock l1(_peers_l);
-			std::sort(_rootPeers.begin(),_rootPeers.end(),_RootSortComparisonOperator(now));
 			Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
 			Address *a = (Address *)0;
 			SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;

+ 2 - 2
node/Trace.cpp

@@ -13,8 +13,8 @@
 
 //#define ZT_TRACE
 
-#include <stdio.h>
-#include <stdarg.h>
+#include <cstdio>
+#include <cstdarg>
 
 #include "Trace.hpp"
 #include "RuntimeEnvironment.hpp"

+ 35 - 0
node/Utils.hpp

@@ -372,6 +372,41 @@ template<typename T>
 static ZT_ALWAYS_INLINE T ntoh(T n) { return n; }
 #endif
 
+static ZT_ALWAYS_INLINE uint64_t readUInt64(const void *const p)
+{
+#ifdef ZT_NO_TYPE_PUNNING
+	const uint8_t *const b = reinterpret_cast<const uint8_t *>(p);
+	return (
+		((uint64_t)b[0] << 56) |
+		((uint64_t)b[1] << 48) |
+		((uint64_t)b[2] << 40) |
+		((uint64_t)b[3] << 32) |
+		((uint64_t)b[4] << 24) |
+		((uint64_t)b[5] << 16) |
+		((uint64_t)b[6] << 8) |
+		(uint64_t)b[7]);
+#else
+	return ntoh(*reinterpret_cast<const uint64_t *>(p));
+#endif
+}
+
+static ZT_ALWAYS_INLINE void putUInt64(void *const p,const uint64_t i)
+{
+#ifdef ZT_NO_TYPE_PUNNING
+	uint8_t *const b = reinterpret_cast<uint8_t *>(p);
+	p[0] = (uint8_t)(i << 56);
+	p[1] = (uint8_t)(i << 48);
+	p[2] = (uint8_t)(i << 40);
+	p[3] = (uint8_t)(i << 32);
+	p[4] = (uint8_t)(i << 24);
+	p[5] = (uint8_t)(i << 16);
+	p[6] = (uint8_t)(i << 8);
+	p[7] = (uint8_t)i;
+#else
+	*reinterpret_cast<uint64_t *>(p) = Utils::hton(i);
+#endif
+}
+
 } // namespace Utils
 
 } // namespace ZeroTier

+ 4 - 4
selftest.cpp

@@ -11,10 +11,10 @@
  */
 /****/
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
 
 #include <stdexcept>
 #include <iostream>