diff --git a/node/Membership.hpp b/node/Membership.hpp index 1cc06970e..3fc29056a 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -239,7 +239,7 @@ public: class CapabilityIterator { public: - CapabilityIterator(Membership &m,const NetworkConfig &nconf) : + inline CapabilityIterator(Membership &m,const NetworkConfig &nconf) : _hti(m._remoteCaps), _k((uint32_t *)0), _c((Capability *)0), diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 971f84af4..56e840de4 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -161,8 +161,8 @@ public: private: 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; MulticastGroup mg; @@ -174,8 +174,8 @@ private: 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); } @@ -190,7 +190,7 @@ private: struct MulticastGroupStatus { - MulticastGroupStatus() : lastExplicitGather(0) {} + inline MulticastGroupStatus() : lastExplicitGather(0) {} uint64_t lastExplicitGather; std::list txQueue; // pending outbound multicasts diff --git a/node/Node.cpp b/node/Node.cpp index 1218c0491..217dd33fd 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -194,7 +194,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame( // those that need pinging. struct _PingPeersThatNeedPing { - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &alwaysContact,int64_t now) : + inline _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &alwaysContact,int64_t now) : RR(renv), _tPtr(tPtr), _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. Hashtable< Address,std::vector > alwaysContact; - RR->topology->getUpstreamsToContact(alwaysContact); + RR->topology->getAlwaysContact(alwaysContact); std::vector< std::pair< SharedPtr,bool > > networkConfigNeeded; { Mutex::Lock l(_networks_m); diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 94ba64596..5c126e9b3 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -58,7 +58,7 @@ class Revocation : public Credential public: static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; } - Revocation() : + inline Revocation() : _id(0), _credentialId(0), _networkId(0), @@ -80,7 +80,7 @@ public: * @param tgt Target node whose credential(s) are 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), _credentialId(cid), _networkId(nwid), diff --git a/node/Str.hpp b/node/Str.hpp index 83af51500..7f2974461 100644 --- a/node/Str.hpp +++ b/node/Str.hpp @@ -37,16 +37,22 @@ namespace ZeroTier { +/** + * A short non-allocating replacement for std::string + */ class Str { 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; memcpy(_s,s._s,_l+1); } - Str(const char *s) + inline Str(const char *s) { _l = 0; _s[0] = 0; @@ -75,7 +81,11 @@ public: inline void clear() { _l = 0; _s[0] = 0; } 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) { @@ -83,8 +93,8 @@ public: unsigned long l = _l; while (*s) { 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; } _s[l++] = *s; @@ -97,14 +107,12 @@ public: inline Str &operator<<(const Str &s) { return ((*this) << s._s); } 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) { diff --git a/node/Topology.hpp b/node/Topology.hpp index 8d093d362..650cb44e6 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -95,13 +95,9 @@ public: { if (zta == RR->identity.address()) return SharedPtr(); - { - Mutex::Lock _l(_peers_m); - const SharedPtr *const ap = _peers.get(zta); - if (ap) - return *ap; - } - return SharedPtr(); + Mutex::Lock _l(_peers_m); + const SharedPtr *const ap = _peers.get(zta); + return ((ap) ? *ap : SharedPtr()); } /** @@ -121,7 +117,7 @@ public: } return Identity(); } - + /** * Get a peer only if it is presently in memory (no disk cache) * @@ -157,38 +153,29 @@ public: return p; } - /** - * Get the current best upstream peer - * - * @return Upstream or NULL if none available - */ inline SharedPtr getUpstreamPeer() const { + // TODO return SharedPtr(); } inline bool isUpstream(const Identity &id) const { + // TODO return false; } - + inline ZT_PeerRole role(const Address &ztaddr) const { + // TODO 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 > &eps) const + inline void getAlwaysContact(Hashtable< Address,std::vector > &eps) const { + // TODO } - /** - * @return Vector of active upstream addresses (including roots) - */ inline std::vector
upstreamAddresses() const { // TODO diff --git a/node/Utils.cpp b/node/Utils.cpp index 3c924518f..694e54e1b 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -85,6 +85,71 @@ char *Utils::decimal(unsigned long n,char s[24]) 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(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(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(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(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(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(buf)[l++] = c; + } + return l; +} + void Utils::getSecureRandom(void *buf,unsigned int bytes) { static Mutex globalLock; @@ -105,8 +170,12 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) if (!s20Initialized) { s20Initialized = true; 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 +#else + s20Key[1] = (uint64_t)getpid(); +#endif s20Key[2] = (uint64_t)s20Key; // address of s20Key[] s20Key[3] = (uint64_t)&s20; // address of s20 s20.init(s20Key,s20Key); @@ -171,6 +240,42 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) #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 buffer = 0; @@ -211,42 +316,6 @@ int Utils::b32d(const char *encoded,uint8_t *result,int bufSize) 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) { 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; } +#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 diff --git a/node/Utils.hpp b/node/Utils.hpp index 5ecb2c2c0..e701ff651 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -48,6 +48,11 @@ namespace ZeroTier { class Utils { public: + /** + * Hexadecimal characters 0-f + */ + static const char HEXCHARS[16]; + /** * 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); @@ -158,78 +163,8 @@ public: 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(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(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(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(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(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(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 @@ -242,13 +177,36 @@ public: */ 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 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 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); + /** + * 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) * @@ -350,23 +308,8 @@ public: 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> 40) | ((n & 0xFF00000000000000ULL) >> 56) ); -#endif -#else - return n; #endif } static inline int64_t hton(int64_t n) { return (int64_t)hton((uint64_t)n); } +#else + template + 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 int8_t ntoh(int8_t n) { return 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 uint64_t ntoh(uint64_t n) { -#if __BYTE_ORDER == __LITTLE_ENDIAN #if defined(__GNUC__) #if defined(__FreeBSD__) return bswap64(n); @@ -426,17 +369,13 @@ public: ((n & 0x00FF000000000000ULL) >> 40) | ((n & 0xFF00000000000000ULL) >> 56) ); -#endif -#else - return n; #endif } 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 + static inline T ntoh(T n) { return n; } +#endif }; } // namespace ZeroTier