Browse Source

More work in progress

Adam Ierymenko 6 years ago
parent
commit
8f5f7f1baa
8 changed files with 210 additions and 186 deletions
  1. 1 1
      node/Membership.hpp
  2. 5 5
      node/Multicaster.hpp
  3. 2 2
      node/Node.cpp
  4. 2 2
      node/Revocation.hpp
  5. 21 13
      node/Str.hpp
  6. 10 23
      node/Topology.hpp
  7. 127 37
      node/Utils.cpp
  8. 42 103
      node/Utils.hpp

+ 1 - 1
node/Membership.hpp

@@ -239,7 +239,7 @@ public:
 	class CapabilityIterator
 	class CapabilityIterator
 	{
 	{
 	public:
 	public:
-		CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
+		inline CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
 			_hti(m._remoteCaps),
 			_hti(m._remoteCaps),
 			_k((uint32_t *)0),
 			_k((uint32_t *)0),
 			_c((Capability *)0),
 			_c((Capability *)0),

+ 5 - 5
node/Multicaster.hpp

@@ -161,8 +161,8 @@ public:
 private:
 private:
 	struct Key
 	struct Key
 	{
 	{
-		Key() : nwid(0),mg() {}
-		Key(uint64_t n,const MulticastGroup &g) : nwid(n),mg(g) {}
+		inline Key() : nwid(0),mg() {}
+		inline Key(uint64_t n,const MulticastGroup &g) : nwid(n),mg(g) {}
 
 
 		uint64_t nwid;
 		uint64_t nwid;
 		MulticastGroup mg;
 		MulticastGroup mg;
@@ -174,8 +174,8 @@ private:
 
 
 	struct MulticastGroupMember
 	struct MulticastGroupMember
 	{
 	{
-		MulticastGroupMember() {}
-		MulticastGroupMember(const Address &a,uint64_t ts) : address(a),timestamp(ts) {}
+		inline MulticastGroupMember() {}
+		inline MulticastGroupMember(const Address &a,uint64_t ts) : address(a),timestamp(ts) {}
 
 
 		inline bool operator<(const MulticastGroupMember &a) const { return (address < a.address); }
 		inline bool operator<(const MulticastGroupMember &a) const { return (address < a.address); }
 		inline bool operator==(const MulticastGroupMember &a) const { return (address == a.address); }
 		inline bool operator==(const MulticastGroupMember &a) const { return (address == a.address); }
@@ -190,7 +190,7 @@ private:
 
 
 	struct MulticastGroupStatus
 	struct MulticastGroupStatus
 	{
 	{
-		MulticastGroupStatus() : lastExplicitGather(0) {}
+		inline MulticastGroupStatus() : lastExplicitGather(0) {}
 
 
 		uint64_t lastExplicitGather;
 		uint64_t lastExplicitGather;
 		std::list<OutboundMulticast> txQueue; // pending outbound multicasts
 		std::list<OutboundMulticast> txQueue; // pending outbound multicasts

+ 2 - 2
node/Node.cpp

@@ -194,7 +194,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
 // those that need pinging.
 // those that need pinging.
 struct _PingPeersThatNeedPing
 struct _PingPeersThatNeedPing
 {
 {
-	_PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector<InetAddress> > &alwaysContact,int64_t now) :
+	inline _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector<InetAddress> > &alwaysContact,int64_t now) :
 		RR(renv),
 		RR(renv),
 		_tPtr(tPtr),
 		_tPtr(tPtr),
 		_alwaysContact(alwaysContact),
 		_alwaysContact(alwaysContact),
@@ -284,7 +284,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
 
 
 			// (1) Get peers we should remain connected to and (2) get networks that need config.
 			// (1) Get peers we should remain connected to and (2) get networks that need config.
 			Hashtable< Address,std::vector<InetAddress> > alwaysContact;
 			Hashtable< Address,std::vector<InetAddress> > alwaysContact;
-			RR->topology->getUpstreamsToContact(alwaysContact);
+			RR->topology->getAlwaysContact(alwaysContact);
 			std::vector< std::pair< SharedPtr<Network>,bool > > networkConfigNeeded;
 			std::vector< std::pair< SharedPtr<Network>,bool > > networkConfigNeeded;
 			{
 			{
 				Mutex::Lock l(_networks_m);
 				Mutex::Lock l(_networks_m);

+ 2 - 2
node/Revocation.hpp

@@ -58,7 +58,7 @@ class Revocation : public Credential
 public:
 public:
 	static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
 	static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
 
 
-	Revocation() :
+	inline Revocation() :
 		_id(0),
 		_id(0),
 		_credentialId(0),
 		_credentialId(0),
 		_networkId(0),
 		_networkId(0),
@@ -80,7 +80,7 @@ public:
 	 * @param tgt Target node whose credential(s) are being revoked
 	 * @param tgt Target node whose credential(s) are being revoked
 	 * @param ct Credential type being revoked
 	 * @param ct Credential type being revoked
 	 */
 	 */
-	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) :
+	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),
 		_id(i),
 		_credentialId(cid),
 		_credentialId(cid),
 		_networkId(nwid),
 		_networkId(nwid),

+ 21 - 13
node/Str.hpp

@@ -37,16 +37,22 @@
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
+/**
+ * A short non-allocating replacement for std::string
+ */
 class Str
 class Str
 {
 {
 public:
 public:
-	Str() { _l = 0; _s[0] = 0; }
-	Str(const Str &s)
+	typedef char * iterator;
+	typedef const char * const_iterator;
+
+	inline Str() { _l = 0; _s[0] = 0; }
+	inline Str(const Str &s)
 	{
 	{
 		_l = s._l;
 		_l = s._l;
 		memcpy(_s,s._s,_l+1);
 		memcpy(_s,s._s,_l+1);
 	}
 	}
-	Str(const char *s)
+	inline Str(const char *s)
 	{
 	{
 		_l = 0;
 		_l = 0;
 		_s[0] = 0;
 		_s[0] = 0;
@@ -75,7 +81,11 @@ public:
 
 
 	inline void clear() { _l = 0; _s[0] = 0; }
 	inline void clear() { _l = 0; _s[0] = 0; }
 	inline const char *c_str() const { return _s; }
 	inline const char *c_str() const { return _s; }
-	inline unsigned int length() const { return _l; }
+	inline unsigned int length() const { return (unsigned int)_l; }
+	inline iterator begin() { return (iterator)_s; }
+	inline iterator end() { return (iterator)(_s + (unsigned long)_l); }
+	inline const_iterator begin() const { return (const_iterator)_s; }
+	inline const_iterator end() const { return (const_iterator)(_s + (unsigned long)_l); }
 
 
 	inline Str &operator<<(const char *s)
 	inline Str &operator<<(const char *s)
 	{
 	{
@@ -83,8 +93,8 @@ public:
 			unsigned long l = _l;
 			unsigned long l = _l;
 			while (*s) {
 			while (*s) {
 				if (unlikely(l >= ZT_STR_CAPACITY)) {
 				if (unlikely(l >= ZT_STR_CAPACITY)) {
-					_s[l] = 0;
-					_l = (uint8_t)l;
+					_s[ZT_STR_CAPACITY] = 0;
+					_l = ZT_STR_CAPACITY;
 					throw ZT_EXCEPTION_OUT_OF_BOUNDS;
 					throw ZT_EXCEPTION_OUT_OF_BOUNDS;
 				}
 				}
 				_s[l++] = *s;
 				_s[l++] = *s;
@@ -97,14 +107,12 @@ public:
 	inline Str &operator<<(const Str &s) { return ((*this) << s._s); }
 	inline Str &operator<<(const Str &s) { return ((*this) << s._s); }
 	inline Str &operator<<(const char c)
 	inline Str &operator<<(const char c)
 	{
 	{
-		if (likely(c != 0)) {
-			if (unlikely(_l >= ZT_STR_CAPACITY)) {
-				_s[_l] = 0;
-				throw ZT_EXCEPTION_OUT_OF_BOUNDS;
-			}
-			_s[_l++] = c;
-			_s[_l] = 0;
+		if (unlikely(_l >= ZT_STR_CAPACITY)) {
+			_s[ZT_STR_CAPACITY] = 0;
+			throw ZT_EXCEPTION_OUT_OF_BOUNDS;
 		}
 		}
+		_s[(unsigned long)(_l++)] = c;
+		_s[(unsigned long)_l] = 0;
 	}
 	}
 	inline Str &operator<<(const unsigned long n)
 	inline Str &operator<<(const unsigned long n)
 	{
 	{

+ 10 - 23
node/Topology.hpp

@@ -95,13 +95,9 @@ public:
 	{
 	{
 		if (zta == RR->identity.address())
 		if (zta == RR->identity.address())
 			return SharedPtr<Peer>();
 			return SharedPtr<Peer>();
-		{
-			Mutex::Lock _l(_peers_m);
-			const SharedPtr<Peer> *const ap = _peers.get(zta);
-			if (ap)
-				return *ap;
-		}
-		return SharedPtr<Peer>();
+		Mutex::Lock _l(_peers_m);
+		const SharedPtr<Peer> *const ap = _peers.get(zta);
+		return ((ap) ? *ap : SharedPtr<Peer>());
 	}
 	}
 
 
 	/**
 	/**
@@ -121,7 +117,7 @@ public:
 		}
 		}
 		return Identity();
 		return Identity();
 	}
 	}
-	
+
 	/**
 	/**
 	 * Get a peer only if it is presently in memory (no disk cache)
 	 * Get a peer only if it is presently in memory (no disk cache)
 	 *
 	 *
@@ -157,38 +153,29 @@ public:
 		return p;
 		return p;
 	}
 	}
 
 
-	/**
-	 * Get the current best upstream peer
-	 *
-	 * @return Upstream or NULL if none available
-	 */
 	inline SharedPtr<Peer> getUpstreamPeer() const
 	inline SharedPtr<Peer> getUpstreamPeer() const
 	{
 	{
+		// TODO
 		return SharedPtr<Peer>();
 		return SharedPtr<Peer>();
 	}
 	}
 
 
 	inline bool isUpstream(const Identity &id) const
 	inline bool isUpstream(const Identity &id) const
 	{
 	{
+		// TODO
 		return false;
 		return false;
 	}
 	}
-	
+
 	inline ZT_PeerRole role(const Address &ztaddr) const
 	inline ZT_PeerRole role(const Address &ztaddr) const
 	{
 	{
+		// TODO
 		return ZT_PEER_ROLE_LEAF;
 		return ZT_PEER_ROLE_LEAF;
 	}
 	}
 
 
-	/**
-	 * Gets upstreams to contact and their stable endpoints (if known)
-	 *
-	 * @param eps Hash table to fill with addresses and their stable endpoints
-	 */
-	inline void getUpstreamsToContact(Hashtable< Address,std::vector<InetAddress> > &eps) const
+	inline void getAlwaysContact(Hashtable< Address,std::vector<InetAddress> > &eps) const
 	{
 	{
+		// TODO
 	}
 	}
 
 
-	/**
-	 * @return Vector of active upstream addresses (including roots)
-	 */
 	inline std::vector<Address> upstreamAddresses() const
 	inline std::vector<Address> upstreamAddresses() const
 	{
 	{
 		// TODO
 		// TODO

+ 127 - 37
node/Utils.cpp

@@ -85,6 +85,71 @@ char *Utils::decimal(unsigned long n,char s[24])
 	return s;
 	return s;
 }
 }
 
 
+unsigned int Utils::unhex(const char *h,void *buf,unsigned int buflen)
+{
+	unsigned int l = 0;
+	while (l < buflen) {
+		uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
+		if (!hc) break;
+
+		uint8_t c = 0;
+		if ((hc >= 48)&&(hc <= 57)) // 0..9
+			c = hc - 48;
+		else if ((hc >= 97)&&(hc <= 102)) // a..f
+			c = hc - 87;
+		else if ((hc >= 65)&&(hc <= 70)) // A..F
+			c = hc - 55;
+
+		hc = *(reinterpret_cast<const uint8_t *>(h++));
+		if (!hc) break;
+
+		c <<= 4;
+		if ((hc >= 48)&&(hc <= 57))
+			c |= hc - 48;
+		else if ((hc >= 97)&&(hc <= 102))
+			c |= hc - 87;
+		else if ((hc >= 65)&&(hc <= 70))
+			c |= hc - 55;
+
+		reinterpret_cast<uint8_t *>(buf)[l++] = c;
+	}
+	return l;
+}
+
+unsigned int Utils::unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen)
+{
+	unsigned int l = 0;
+	const char *hend = h + hlen;
+	while (l < buflen) {
+		if (h == hend) break;
+		uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
+		if (!hc) break;
+
+		uint8_t c = 0;
+		if ((hc >= 48)&&(hc <= 57))
+			c = hc - 48;
+		else if ((hc >= 97)&&(hc <= 102))
+			c = hc - 87;
+		else if ((hc >= 65)&&(hc <= 70))
+			c = hc - 55;
+
+		if (h == hend) break;
+		hc = *(reinterpret_cast<const uint8_t *>(h++));
+		if (!hc) break;
+
+		c <<= 4;
+		if ((hc >= 48)&&(hc <= 57))
+			c |= hc - 48;
+		else if ((hc >= 97)&&(hc <= 102))
+			c |= hc - 87;
+		else if ((hc >= 65)&&(hc <= 70))
+			c |= hc - 55;
+
+		reinterpret_cast<uint8_t *>(buf)[l++] = c;
+	}
+	return l;
+}
+
 void Utils::getSecureRandom(void *buf,unsigned int bytes)
 void Utils::getSecureRandom(void *buf,unsigned int bytes)
 {
 {
 	static Mutex globalLock;
 	static Mutex globalLock;
@@ -105,8 +170,12 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
 	if (!s20Initialized) {
 	if (!s20Initialized) {
 		s20Initialized = true;
 		s20Initialized = true;
 		uint64_t s20Key[4];
 		uint64_t s20Key[4];
-		s20Key[0] = (uint64_t)time(0); // system clock
+		s20Key[0] = (uint64_t)time(nullptr);
+#ifdef __WINDOWS__
 		s20Key[1] = (uint64_t)buf; // address of buf
 		s20Key[1] = (uint64_t)buf; // address of buf
+#else
+		s20Key[1] = (uint64_t)getpid();
+#endif
 		s20Key[2] = (uint64_t)s20Key; // address of s20Key[]
 		s20Key[2] = (uint64_t)s20Key; // address of s20Key[]
 		s20Key[3] = (uint64_t)&s20; // address of s20
 		s20Key[3] = (uint64_t)&s20; // address of s20
 		s20.init(s20Key,s20Key);
 		s20.init(s20Key,s20Key);
@@ -171,6 +240,42 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
 #endif // __WINDOWS__ or not
 #endif // __WINDOWS__ or not
 }
 }
 
 
+int Utils::b32e(const uint8_t *data,int length,char *result,int bufSize)
+{
+  if (length < 0 || length > (1 << 28)) {
+		result[0] = (char)0;
+    return -1;
+	}
+	int count = 0;
+  if (length > 0) {
+    int buffer = data[0];
+    int next = 1;
+    int bitsLeft = 8;
+    while (count < bufSize && (bitsLeft > 0 || next < length)) {
+      if (bitsLeft < 5) {
+        if (next < length) {
+          buffer <<= 8;
+          buffer |= data[next++] & 0xFF;
+          bitsLeft += 8;
+        } else {
+          int pad = 5 - bitsLeft;
+          buffer <<= pad;
+          bitsLeft += pad;
+        }
+      }
+      int index = 0x1F & (buffer >> (bitsLeft - 5));
+      bitsLeft -= 5;
+      result[count++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[index];
+    }
+  }
+  if (count < bufSize) {
+		result[count] = (char)0;
+		return count;
+	}
+	result[0] = (char)0;
+	return -1;
+}
+
 int Utils::b32d(const char *encoded,uint8_t *result,int bufSize)
 int Utils::b32d(const char *encoded,uint8_t *result,int bufSize)
 {
 {
   int buffer = 0;
   int buffer = 0;
@@ -211,42 +316,6 @@ int Utils::b32d(const char *encoded,uint8_t *result,int bufSize)
   return count;
   return count;
 }
 }
 
 
-int Utils::b32e(const uint8_t *data,int length,char *result,int bufSize)
-{
-  if (length < 0 || length > (1 << 28)) {
-		result[0] = (char)0;
-    return -1;
-	}
-	int count = 0;
-  if (length > 0) {
-    int buffer = data[0];
-    int next = 1;
-    int bitsLeft = 8;
-    while (count < bufSize && (bitsLeft > 0 || next < length)) {
-      if (bitsLeft < 5) {
-        if (next < length) {
-          buffer <<= 8;
-          buffer |= data[next++] & 0xFF;
-          bitsLeft += 8;
-        } else {
-          int pad = 5 - bitsLeft;
-          buffer <<= pad;
-          bitsLeft += pad;
-        }
-      }
-      int index = 0x1F & (buffer >> (bitsLeft - 5));
-      bitsLeft -= 5;
-      result[count++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[index];
-    }
-  }
-  if (count < bufSize) {
-		result[count] = (char)0;
-		return count;
-	}
-	result[0] = (char)0;
-	return -1;
-}
-
 unsigned int Utils::b64e(const uint8_t *in,unsigned int inlen,char *out,unsigned int outlen)
 unsigned int Utils::b64e(const uint8_t *in,unsigned int inlen,char *out,unsigned int outlen)
 {
 {
 	static const char base64en[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' };
 	static const char base64en[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' };
@@ -326,4 +395,25 @@ unsigned int Utils::b64d(const char *in,unsigned char *out,unsigned int outlen)
 	return j;
 	return j;
 }
 }
 
 
+#define ROL64(x,k) (((x) << (k)) | ((x) >> (64 - (k))))
+uint64_t Utils::random()
+{
+	// https://en.wikipedia.org/wiki/Xorshift#xoshiro256**
+	static Mutex l;
+	static uint64_t s[4] = { Utils::getSecureRandom64(),Utils::getSecureRandom64(),Utils::getSecureRandom64(),Utils::getSecureRandom64() };
+
+	l.lock();
+	const uint64_t result = ROL64(s[1] * 5,7) * 9;
+	const uint64_t t = s[1] << 17;
+	s[2] ^= s[0];
+	s[3] ^= s[1];
+	s[1] ^= s[2];
+	s[0] ^= s[3];
+	s[2] ^= t;
+	s[3] = ROL64(s[3],45);
+	l.unlock();
+
+	return result;
+}
+
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 42 - 103
node/Utils.hpp

@@ -48,6 +48,11 @@ namespace ZeroTier {
 class Utils
 class Utils
 {
 {
 public:
 public:
+	/**
+	 * Hexadecimal characters 0-f
+	 */
+	static const char HEXCHARS[16];
+
 	/**
 	/**
 	 * Perform a time-invariant binary comparison
 	 * Perform a time-invariant binary comparison
 	 *
 	 *
@@ -65,7 +70,7 @@ public:
 	}
 	}
 
 
 	/**
 	/**
-	 * Securely zero memory, avoiding compiler optimizations and such
+	 * Zero memory, ensuring to avoid any compiler optimizations or other things that may stop this.
 	 */
 	 */
 	static void burn(void *ptr,unsigned int len);
 	static void burn(void *ptr,unsigned int len);
 
 
@@ -158,78 +163,8 @@ public:
 		return save;
 		return save;
 	}
 	}
 
 
-	static inline unsigned int unhex(const char *h,void *buf,unsigned int buflen)
-	{
-		unsigned int l = 0;
-		while (l < buflen) {
-			uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
-			if (!hc) break;
-
-			uint8_t c = 0;
-			if ((hc >= 48)&&(hc <= 57)) // 0..9
-				c = hc - 48;
-			else if ((hc >= 97)&&(hc <= 102)) // a..f
-				c = hc - 87;
-			else if ((hc >= 65)&&(hc <= 70)) // A..F
-				c = hc - 55;
-
-			hc = *(reinterpret_cast<const uint8_t *>(h++));
-			if (!hc) break;
-
-			c <<= 4;
-			if ((hc >= 48)&&(hc <= 57))
-				c |= hc - 48;
-			else if ((hc >= 97)&&(hc <= 102))
-				c |= hc - 87;
-			else if ((hc >= 65)&&(hc <= 70))
-				c |= hc - 55;
-
-			reinterpret_cast<uint8_t *>(buf)[l++] = c;
-		}
-		return l;
-	}
-
-	static inline unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen)
-	{
-		unsigned int l = 0;
-		const char *hend = h + hlen;
-		while (l < buflen) {
-			if (h == hend) break;
-			uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
-			if (!hc) break;
-
-			uint8_t c = 0;
-			if ((hc >= 48)&&(hc <= 57))
-				c = hc - 48;
-			else if ((hc >= 97)&&(hc <= 102))
-				c = hc - 87;
-			else if ((hc >= 65)&&(hc <= 70))
-				c = hc - 55;
-
-			if (h == hend) break;
-			hc = *(reinterpret_cast<const uint8_t *>(h++));
-			if (!hc) break;
-
-			c <<= 4;
-			if ((hc >= 48)&&(hc <= 57))
-				c |= hc - 48;
-			else if ((hc >= 97)&&(hc <= 102))
-				c |= hc - 87;
-			else if ((hc >= 65)&&(hc <= 70))
-				c |= hc - 55;
-
-			reinterpret_cast<uint8_t *>(buf)[l++] = c;
-		}
-		return l;
-	}
-
-	static inline float normalize(float value, int64_t bigMin, int64_t bigMax, int32_t targetMin, int32_t targetMax)
-	{
-		int64_t bigSpan = bigMax - bigMin;
-		int64_t smallSpan = targetMax - targetMin;
-		float valueScaled = (value - (float)bigMin) / (float)bigSpan;
-		return (float)targetMin + valueScaled * (float)smallSpan;
-	}
+	static unsigned int unhex(const char *h,void *buf,unsigned int buflen);
+	static unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen);
 
 
 	/**
 	/**
 	 * Generate secure random bytes
 	 * Generate secure random bytes
@@ -242,13 +177,36 @@ public:
 	 */
 	 */
 	static void getSecureRandom(void *buf,unsigned int bytes);
 	static void getSecureRandom(void *buf,unsigned int bytes);
 
 
-	static int b32d(const char *encoded, uint8_t *result, int bufSize);
+	/**
+	 * Get a 64-bit unsigned secure random number
+	 */
+	static inline uint64_t getSecureRandom64()
+	{
+		uint64_t x;
+		getSecureRandom(&x,sizeof(x));
+		return x;
+	}
+
 	static int b32e(const uint8_t *data,int length,char *result,int bufSize);
 	static int b32e(const uint8_t *data,int length,char *result,int bufSize);
+	static int b32d(const char *encoded, uint8_t *result, int bufSize);
 
 
 	static inline unsigned int b64MaxEncodedSize(const unsigned int s) { return ((((s + 2) / 3) * 4) + 1); }
 	static inline unsigned int b64MaxEncodedSize(const unsigned int s) { return ((((s + 2) / 3) * 4) + 1); }
 	static unsigned int b64e(const uint8_t *in,unsigned int inlen,char *out,unsigned int outlen);
 	static unsigned int b64e(const uint8_t *in,unsigned int inlen,char *out,unsigned int outlen);
 	static unsigned int b64d(const char *in,uint8_t *out,unsigned int outlen);
 	static unsigned int b64d(const char *in,uint8_t *out,unsigned int outlen);
 
 
+	/**
+	 * Get a non-cryptographic random integer
+	 */
+	static uint64_t random();
+
+	static inline float normalize(float value, int64_t bigMin, int64_t bigMax, int32_t targetMin, int32_t targetMax)
+	{
+		int64_t bigSpan = bigMax - bigMin;
+		int64_t smallSpan = targetMax - targetMin;
+		float valueScaled = (value - (float)bigMin) / (float)bigSpan;
+		return (float)targetMin + valueScaled * (float)smallSpan;
+	}
+
 	/**
 	/**
 	 * Tokenize a string (alias for strtok_r or strtok_s depending on platform)
 	 * Tokenize a string (alias for strtok_r or strtok_s depending on platform)
 	 *
 	 *
@@ -350,23 +308,8 @@ public:
 		return (T)(v * ((~((T)0))/((T)255))) >> ((sizeof(T) - 1) * 8);
 		return (T)(v * ((~((T)0))/((T)255))) >> ((sizeof(T) - 1) * 8);
 	}
 	}
 
 
-	/**
-	 * Check if a memory buffer is all-zero
-	 *
-	 * @param p Memory to scan
-	 * @param len Length of memory
-	 * @return True if memory is all zero
-	 */
-	static inline bool isZero(const void *p,unsigned int len)
-	{
-		for(unsigned int i=0;i<len;++i) {
-			if (((const unsigned char *)p)[i])
-				return false;
-		}
-		return true;
-	}
-
 	// Byte swappers for big/little endian conversion
 	// Byte swappers for big/little endian conversion
+#if __BYTE_ORDER == __LITTLE_ENDIAN
 	static inline uint8_t hton(uint8_t n) { return n; }
 	static inline uint8_t hton(uint8_t n) { return n; }
 	static inline int8_t hton(int8_t n) { return n; }
 	static inline int8_t hton(int8_t n) { return n; }
 	static inline uint16_t hton(uint16_t n) { return htons(n); }
 	static inline uint16_t hton(uint16_t n) { return htons(n); }
@@ -375,7 +318,6 @@ public:
 	static inline int32_t hton(int32_t n) { return (int32_t)htonl((uint32_t)n); }
 	static inline int32_t hton(int32_t n) { return (int32_t)htonl((uint32_t)n); }
 	static inline uint64_t hton(uint64_t n)
 	static inline uint64_t hton(uint64_t n)
 	{
 	{
-#if __BYTE_ORDER == __LITTLE_ENDIAN
 #if defined(__GNUC__)
 #if defined(__GNUC__)
 #if defined(__FreeBSD__)
 #if defined(__FreeBSD__)
 		return bswap64(n);
 		return bswap64(n);
@@ -393,13 +335,15 @@ public:
 			((n & 0x00FF000000000000ULL) >> 40) |
 			((n & 0x00FF000000000000ULL) >> 40) |
 			((n & 0xFF00000000000000ULL) >> 56)
 			((n & 0xFF00000000000000ULL) >> 56)
 		);
 		);
-#endif
-#else
-		return n;
 #endif
 #endif
 	}
 	}
 	static inline int64_t hton(int64_t n) { return (int64_t)hton((uint64_t)n); }
 	static inline int64_t hton(int64_t n) { return (int64_t)hton((uint64_t)n); }
+#else
+	template<typename T>
+	static inline T hton(T n) { return n; }
+#endif
 
 
+#if __BYTE_ORDER == __LITTLE_ENDIAN
 	static inline uint8_t ntoh(uint8_t n) { return n; }
 	static inline uint8_t ntoh(uint8_t n) { return n; }
 	static inline int8_t ntoh(int8_t n) { return n; }
 	static inline int8_t ntoh(int8_t n) { return n; }
 	static inline uint16_t ntoh(uint16_t n) { return ntohs(n); }
 	static inline uint16_t ntoh(uint16_t n) { return ntohs(n); }
@@ -408,7 +352,6 @@ public:
 	static inline int32_t ntoh(int32_t n) { return (int32_t)ntohl((uint32_t)n); }
 	static inline int32_t ntoh(int32_t n) { return (int32_t)ntohl((uint32_t)n); }
 	static inline uint64_t ntoh(uint64_t n)
 	static inline uint64_t ntoh(uint64_t n)
 	{
 	{
-#if __BYTE_ORDER == __LITTLE_ENDIAN
 #if defined(__GNUC__)
 #if defined(__GNUC__)
 #if defined(__FreeBSD__)
 #if defined(__FreeBSD__)
 		return bswap64(n);
 		return bswap64(n);
@@ -426,17 +369,13 @@ public:
 			((n & 0x00FF000000000000ULL) >> 40) |
 			((n & 0x00FF000000000000ULL) >> 40) |
 			((n & 0xFF00000000000000ULL) >> 56)
 			((n & 0xFF00000000000000ULL) >> 56)
 		);
 		);
-#endif
-#else
-		return n;
 #endif
 #endif
 	}
 	}
 	static inline int64_t ntoh(int64_t n) { return (int64_t)ntoh((uint64_t)n); }
 	static inline int64_t ntoh(int64_t n) { return (int64_t)ntoh((uint64_t)n); }
-
-	/**
-	 * Hexadecimal characters 0-f
-	 */
-	static const char HEXCHARS[16];
+#else
+	template<typename T>
+	static inline T ntoh(T n) { return n; }
+#endif
 };
 };
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier