Yet more minor refactoring and redesign Meter to be more thread-safe.

This commit is contained in:
Adam Ierymenko 2020-02-14 11:34:47 -08:00
parent e236d6f743
commit e5c7366e71
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
10 changed files with 131 additions and 80 deletions

View file

@ -353,53 +353,72 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
const __m128i h = _aes._k.ni.h; const __m128i h = _aes._k.ni.h;
y = _mm_xor_si128(y,_mm_set_epi64x(0LL,(long long)Utils::hton((uint64_t)_len << 3U))); y = _mm_xor_si128(y,_mm_set_epi64x(0LL,(long long)Utils::hton((uint64_t)_len << 3U)));
y = _mm_shuffle_epi8(y,s_shuf); y = _mm_shuffle_epi8(y,s_shuf);
__m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i *>(_iv)),k[0]); __m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i *>(_iv)),k[0]);
__m128i t1 = _mm_clmulepi64_si128(h,y,0x00); __m128i t1 = _mm_clmulepi64_si128(h,y,0x00);
__m128i t2 = _mm_clmulepi64_si128(h,y,0x01); __m128i t2 = _mm_clmulepi64_si128(h,y,0x01);
__m128i t3 = _mm_clmulepi64_si128(h,y,0x10); __m128i t3 = _mm_clmulepi64_si128(h,y,0x10);
__m128i t4 = _mm_clmulepi64_si128(h,y,0x11); __m128i t4 = _mm_clmulepi64_si128(h,y,0x11);
encIV = _mm_aesenc_si128(encIV,k[1]); encIV = _mm_aesenc_si128(encIV,k[1]);
encIV = _mm_aesenc_si128(encIV,k[2]);
t2 = _mm_xor_si128(t2,t3); t2 = _mm_xor_si128(t2,t3);
t3 = _mm_slli_si128(t2,8); t3 = _mm_slli_si128(t2,8);
encIV = _mm_aesenc_si128(encIV,k[2]);
t2 = _mm_srli_si128(t2,8); t2 = _mm_srli_si128(t2,8);
t1 = _mm_xor_si128(t1,t3); t1 = _mm_xor_si128(t1,t3);
encIV = _mm_aesenc_si128(encIV,k[3]); encIV = _mm_aesenc_si128(encIV,k[3]);
t4 = _mm_xor_si128(t4,t2); t4 = _mm_xor_si128(t4,t2);
__m128i t5 = _mm_srli_epi32(t1,31); __m128i t5 = _mm_srli_epi32(t1,31);
encIV = _mm_aesenc_si128(encIV,k[4]);
t1 = _mm_slli_epi32(t1,1); t1 = _mm_slli_epi32(t1,1);
__m128i t6 = _mm_srli_epi32(t4,31); __m128i t6 = _mm_srli_epi32(t4,31);
encIV = _mm_aesenc_si128(encIV,k[5]);
encIV = _mm_aesenc_si128(encIV,k[4]);
t4 = _mm_slli_epi32(t4,1); t4 = _mm_slli_epi32(t4,1);
t3 = _mm_srli_si128(t5,12); t3 = _mm_srli_si128(t5,12);
encIV = _mm_aesenc_si128(encIV,k[6]);
t6 = _mm_slli_si128(t6,4); t6 = _mm_slli_si128(t6,4);
t5 = _mm_slli_si128(t5,4); t5 = _mm_slli_si128(t5,4);
encIV = _mm_aesenc_si128(encIV,k[7]);
encIV = _mm_aesenc_si128(encIV,k[5]);
t1 = _mm_or_si128(t1,t5); t1 = _mm_or_si128(t1,t5);
t4 = _mm_or_si128(t4,t6); t4 = _mm_or_si128(t4,t6);
encIV = _mm_aesenc_si128(encIV,k[8]);
encIV = _mm_aesenc_si128(encIV,k[6]);
encIV = _mm_aesenc_si128(encIV,k[7]);
t4 = _mm_or_si128(t4,t3); t4 = _mm_or_si128(t4,t3);
t5 = _mm_slli_epi32(t1,31); t5 = _mm_slli_epi32(t1,31);
encIV = _mm_aesenc_si128(encIV,k[9]);
t6 = _mm_slli_epi32(t1,30); t6 = _mm_slli_epi32(t1,30);
t3 = _mm_slli_epi32(t1,25); t3 = _mm_slli_epi32(t1,25);
encIV = _mm_aesenc_si128(encIV,k[10]);
encIV = _mm_aesenc_si128(encIV,k[8]);
encIV = _mm_aesenc_si128(encIV,k[9]);
t5 = _mm_xor_si128(t5,t6); t5 = _mm_xor_si128(t5,t6);
t5 = _mm_xor_si128(t5,t3); t5 = _mm_xor_si128(t5,t3);
encIV = _mm_aesenc_si128(encIV,k[10]);
encIV = _mm_aesenc_si128(encIV,k[11]); encIV = _mm_aesenc_si128(encIV,k[11]);
t6 = _mm_srli_si128(t5,4); t6 = _mm_srli_si128(t5,4);
t4 = _mm_xor_si128(t4,t6); t4 = _mm_xor_si128(t4,t6);
encIV = _mm_aesenc_si128(encIV,k[12]);
t5 = _mm_slli_si128(t5,12); t5 = _mm_slli_si128(t5,12);
t1 = _mm_xor_si128(t1,t5); t1 = _mm_xor_si128(t1,t5);
encIV = _mm_aesenc_si128(encIV,k[13]);
t4 = _mm_xor_si128(t4,t1); t4 = _mm_xor_si128(t4,t1);
t5 = _mm_srli_epi32(t1,1); t5 = _mm_srli_epi32(t1,1);
t2 = _mm_srli_epi32(t1,2); t2 = _mm_srli_epi32(t1,2);
t3 = _mm_srli_epi32(t1,7); t3 = _mm_srli_epi32(t1,7);
encIV = _mm_aesenc_si128(encIV,k[12]);
encIV = _mm_aesenc_si128(encIV,k[13]);
encIV = _mm_aesenclast_si128(encIV,k[14]); encIV = _mm_aesenclast_si128(encIV,k[14]);
t4 = _mm_xor_si128(t4,t2); t4 = _mm_xor_si128(t4,t2);
t4 = _mm_xor_si128(t4,t3); t4 = _mm_xor_si128(t4,t3);
t4 = _mm_xor_si128(t4,t5); t4 = _mm_xor_si128(t4,t5);

View file

@ -79,7 +79,7 @@ namespace ZeroTier {
*/ */
class Buf class Buf
{ {
friend class SharedPtr< Buf >; friend class SharedPtr<Buf>;
public: public:
// New and delete operators that allocate Buf instances from a shared lock-free memory pool. // New and delete operators that allocate Buf instances from a shared lock-free memory pool.

View file

@ -750,7 +750,7 @@ FORCE_INLINE int LZ4_decompress_generic(
} // anonymous namespace } // anonymous namespace
int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) noexcept
{ {
#if (HEAPMODE) #if (HEAPMODE)
void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
@ -767,7 +767,7 @@ int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutp
return result; return result;
} }
int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) noexcept
{ {
return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0);
} }

View file

@ -18,8 +18,8 @@
namespace ZeroTier { namespace ZeroTier {
int LZ4_compress_fast(const char *source,char *dest,int inputSize,int maxOutputSize,int acceleration = 1); int LZ4_compress_fast(const char *source,char *dest,int inputSize,int maxOutputSize,int acceleration = 1) noexcept;
int LZ4_decompress_safe(const char *source,char *dest,int compressedSize,int maxDecompressedSize); int LZ4_decompress_safe(const char *source,char *dest,int compressedSize,int maxDecompressedSize) noexcept;
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -15,7 +15,7 @@
namespace ZeroTier { namespace ZeroTier {
bool Locator::sign(const int64_t ts,const Identity &id) bool Locator::sign(const int64_t ts,const Identity &id) noexcept
{ {
uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX]; uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
if (!id.hasPrivate()) if (!id.hasPrivate())
@ -28,7 +28,7 @@ bool Locator::sign(const int64_t ts,const Identity &id)
return (_signatureLength > 0); return (_signatureLength > 0);
} }
bool Locator::verify(const Identity &id) const bool Locator::verify(const Identity &id) const noexcept
{ {
if ((_ts == 0)||(_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)) if ((_ts == 0)||(_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return false; return false;
@ -37,7 +37,7 @@ bool Locator::verify(const Identity &id) const
return id.verify(signData,signLen,_signature,_signatureLength); return id.verify(signData,signLen,_signature,_signatureLength);
} }
int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature) const int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature) const noexcept
{ {
if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)) if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return -1; return -1;
@ -69,7 +69,7 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud
return p; return p;
} }
int Locator::unmarshal(const uint8_t *restrict data,const int len) int Locator::unmarshal(const uint8_t *restrict data,const int len) noexcept
{ {
if (len <= (8 + 2 + 48)) if (len <= (8 + 2 + 48))
return -1; return -1;

View file

@ -37,42 +37,42 @@ namespace ZeroTier {
class Locator : public TriviallyCopyable class Locator : public TriviallyCopyable
{ {
public: public:
ZT_ALWAYS_INLINE Locator() { this->clear(); } ZT_ALWAYS_INLINE Locator() noexcept { memoryZero(this); }
/** /**
* Zero the Locator data structure * Zero the Locator data structure
*/ */
ZT_ALWAYS_INLINE void clear() { memset(reinterpret_cast<void *>(this),0,sizeof(Locator)); } ZT_ALWAYS_INLINE void clear() noexcept { memoryZero(this); }
/** /**
* @return Timestamp (a.k.a. revision number) set by Location signer * @return Timestamp (a.k.a. revision number) set by Location signer
*/ */
ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; } ZT_ALWAYS_INLINE int64_t timestamp() const noexcept { return _ts; }
/** /**
* @return True if locator is signed * @return True if locator is signed
*/ */
ZT_ALWAYS_INLINE bool isSigned() const { return (_signatureLength > 0); } ZT_ALWAYS_INLINE bool isSigned() const noexcept { return (_signatureLength > 0); }
/** /**
* @return Length of signature in bytes or 0 if none * @return Length of signature in bytes or 0 if none
*/ */
ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; } ZT_ALWAYS_INLINE unsigned int signatureLength() const noexcept { return _signatureLength; }
/** /**
* @return Pointer to signature bytes * @return Pointer to signature bytes
*/ */
ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; } ZT_ALWAYS_INLINE const uint8_t *signature() const noexcept { return _signature; }
/** /**
* @return Number of endpoints in this locator * @return Number of endpoints in this locator
*/ */
ZT_ALWAYS_INLINE unsigned int endpointCount() const { return _endpointCount; } ZT_ALWAYS_INLINE unsigned int endpointCount() const noexcept { return _endpointCount; }
/** /**
* @return Pointer to array of endpoints * @return Pointer to array of endpoints
*/ */
ZT_ALWAYS_INLINE const Endpoint *endpoints() const { return _at; } ZT_ALWAYS_INLINE const Endpoint *endpoints() const noexcept { return _at; }
/** /**
* Add an endpoint to this locator * Add an endpoint to this locator
@ -83,7 +83,7 @@ public:
* @param ep Endpoint to add * @param ep Endpoint to add
* @return True if endpoint was added (or already present), false if locator is full * @return True if endpoint was added (or already present), false if locator is full
*/ */
ZT_ALWAYS_INLINE bool add(const Endpoint &ep) ZT_ALWAYS_INLINE bool add(const Endpoint &ep) noexcept
{ {
if (_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS) if (_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS)
return false; return false;
@ -100,7 +100,7 @@ public:
* @param id Identity that includes private key * @param id Identity that includes private key
* @return True if signature successful * @return True if signature successful
*/ */
bool sign(int64_t ts,const Identity &id); bool sign(int64_t ts,const Identity &id) noexcept;
/** /**
* Verify this Locator's validity and signature * Verify this Locator's validity and signature
@ -108,13 +108,13 @@ public:
* @param id Identity corresponding to hash * @param id Identity corresponding to hash
* @return True if valid and signature checks out * @return True if valid and signature checks out
*/ */
bool verify(const Identity &id) const; bool verify(const Identity &id) const noexcept;
explicit ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); } explicit ZT_ALWAYS_INLINE operator bool() const noexcept { return (_ts != 0); }
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_LOCATOR_MARSHAL_SIZE_MAX; } static constexpr int marshalSizeMax() noexcept { return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],bool excludeSignature = false) const; int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],bool excludeSignature = false) const noexcept;
int unmarshal(const uint8_t *restrict data,int len); int unmarshal(const uint8_t *restrict data,int len) noexcept;
private: private:
int64_t _ts; int64_t _ts;

View file

@ -17,7 +17,6 @@
#include "RuntimeEnvironment.hpp" #include "RuntimeEnvironment.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "Topology.hpp" #include "Topology.hpp"
#include "Switch.hpp"
#include "Node.hpp" #include "Node.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -33,6 +32,10 @@ Membership::Membership() :
{ {
} }
Membership::~Membership()
{
}
void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf) void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf)
{ {
const Capability *sendCaps[ZT_MAX_NETWORK_CAPABILITIES]; const Capability *sendCaps[ZT_MAX_NETWORK_CAPABILITIES];
@ -218,7 +221,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
} }
} }
bool Membership::_isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const bool Membership::_isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const noexcept
{ {
if ((ip.isV6())&&(nconf.ndpEmulation())) { if ((ip.isV6())&&(nconf.ndpEmulation())) {
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt())); const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));

View file

@ -49,6 +49,7 @@ public:
}; };
Membership(); Membership();
~Membership();
/** /**
* Send COM and other credentials to this peer * Send COM and other credentials to this peer
@ -64,7 +65,7 @@ public:
/** /**
* @return Time we last pushed credentials to this member * @return Time we last pushed credentials to this member
*/ */
ZT_ALWAYS_INLINE int64_t lastPushedCredentials() const { return _lastPushedCredentials; } ZT_ALWAYS_INLINE int64_t lastPushedCredentials() const noexcept { return _lastPushedCredentials; }
/** /**
* Check whether the peer represented by this Membership should be allowed on this network at all * Check whether the peer represented by this Membership should be allowed on this network at all
@ -72,7 +73,7 @@ public:
* @param nconf Our network config * @param nconf Our network config
* @return True if this peer is allowed on this network at all * @return True if this peer is allowed on this network at all
*/ */
ZT_ALWAYS_INLINE bool isAllowedOnNetwork(const NetworkConfig &nconf) const ZT_ALWAYS_INLINE bool isAllowedOnNetwork(const NetworkConfig &nconf) const noexcept
{ {
if (nconf.isPublic()) return true; // public network if (nconf.isPublic()) return true; // public network
if (_com.timestamp() <= _comRevocationThreshold) return false; // COM has been revoked if (_com.timestamp() <= _comRevocationThreshold) return false; // COM has been revoked
@ -88,7 +89,7 @@ public:
* @return True if this peer has a certificate of ownership for the given resource * @return True if this peer has a certificate of ownership for the given resource
*/ */
template<typename T> template<typename T>
ZT_ALWAYS_INLINE bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const ZT_ALWAYS_INLINE bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const noexcept
{ {
if (_isUnspoofableAddress(nconf,r)) if (_isUnspoofableAddress(nconf,r))
return true; return true;
@ -109,7 +110,7 @@ public:
* @param id Tag ID * @param id Tag ID
* @return Pointer to tag or NULL if not found * @return Pointer to tag or NULL if not found
*/ */
ZT_ALWAYS_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 noexcept
{ {
const Tag *const t = _remoteTags.get(id); const Tag *const t = _remoteTags.get(id);
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0); return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
@ -138,13 +139,13 @@ private:
// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT // 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 // address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to
// always return true for them. A certificate is not required for these. // always return true for them. A certificate is not required for these.
ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; } ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const noexcept { return false; }
bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const; bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const noexcept;
// This compares the remote credential's timestamp to the timestamp in our network config // This compares the remote credential's timestamp to the timestamp in our network config
// plus or minus the permitted maximum timestamp delta. // plus or minus the permitted maximum timestamp delta.
template<typename C> template<typename C>
ZT_ALWAYS_INLINE bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const ZT_ALWAYS_INLINE bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const noexcept
{ {
const int64_t ts = remoteCredential.timestamp(); const int64_t ts = remoteCredential.timestamp();
if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) { if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) {
@ -190,7 +191,7 @@ public:
class CapabilityIterator class CapabilityIterator
{ {
public: public:
ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) : ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) noexcept :
_hti(m._remoteCaps), _hti(m._remoteCaps),
_k(nullptr), _k(nullptr),
_c(nullptr), _c(nullptr),
@ -199,7 +200,7 @@ public:
{ {
} }
ZT_ALWAYS_INLINE Capability *next() ZT_ALWAYS_INLINE Capability *next() noexcept
{ {
while (_hti.next(_k,_c)) { while (_hti.next(_k,_c)) {
if (_m._isCredentialTimestampValid(_nconf,*_c)) if (_m._isCredentialTimestampValid(_nconf,*_c))

View file

@ -17,58 +17,79 @@
#include "Constants.hpp" #include "Constants.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#define ZT_METER_HISTORY_LENGTH 4 #include <algorithm>
#define ZT_METER_HISTORY_TICK_DURATION 1000
namespace ZeroTier { namespace ZeroTier {
/** /**
* Transfer rate meter (thread-safe) * Transfer rate and total transferred amount meter
*
* @tparam TUNIT Unit of time in milliseconds (default: 1000 for one second)
* @tparam LSIZE Log size in units of time (default: 60 for one minute worth of data)
*/ */
template<int64_t TUNIT = 1000,unsigned long LSIZE = 60>
class Meter class Meter
{ {
public: public:
ZT_ALWAYS_INLINE Meter() noexcept /**
{ * Create and initialize a new meter
for(int i=0;i<ZT_METER_HISTORY_LENGTH;++i) *
_history[i] = 0.0; * @param now Start time
_ts = 0; */
_count = 0; ZT_ALWAYS_INLINE Meter(const int64_t now) noexcept : startTime(now) {}
}
/**
* Add a measurement
*
* @tparam I Type of 'count' (usually inferred)
* @param now Current time
* @param count Count of items (usually bytes)
*/
template<typename I> template<typename I>
ZT_ALWAYS_INLINE void log(const int64_t now,I count) noexcept ZT_ALWAYS_INLINE void log(const int64_t now,I count) noexcept
{ {
const int64_t since = now - _ts; _total += (uint64_t)count;
if (since >= ZT_METER_HISTORY_TICK_DURATION) {
_ts = now; // We log by choosing a log bucket based on the current time in units modulo
_history[++_hptr % ZT_METER_HISTORY_LENGTH] = (double)_count / ((double)since / 1000.0); // the log size and then if it's a new bucket setting it or otherwise adding
_count = (uint64_t)count; // to it.
} else { const unsigned long bucket = ((unsigned int)((uint64_t)(now / TUNIT))) % LSIZE;
_count += (uint64_t)count; const unsigned long prevBucket = _bucket.exchange(bucket);
} if (prevBucket != bucket)
_counts[bucket].store((uint64_t)count);
else _counts[bucket].fetch_add((uint64_t)count);
} }
ZT_ALWAYS_INLINE double perSecond(const int64_t now) const noexcept /**
* Get rate per TUNIT time
*
* @param now Current time
* @return Count per TUNIT time (rate)
*/
ZT_ALWAYS_INLINE double rate(const int64_t now) const noexcept
{ {
double r = 0.0,n = 0.0; // Rate is computed by looking back at N buckets where N is the smaller of
const int64_t since = (now - _ts); // the size of the log or the number of units since the start time.
if (since >= ZT_METER_HISTORY_TICK_DURATION) { const unsigned long lookback = std::min((unsigned long)((now - startTime) / TUNIT),LSIZE);
r += (double)_count / ((double)since / 1000.0); if (lookback == 0)
n += 1.0; return 0.0;
} unsigned long bi = ((unsigned int)((uint64_t)(now / TUNIT)));
for(int i=0;i<ZT_METER_HISTORY_LENGTH;++i) { double sum = 0.0;
r += _history[i]; for(unsigned long l=0;l<lookback;++l)
n += 1.0; sum += (double)_counts[bi-- % LSIZE].load();
} return sum / (double)lookback;
return r / n;
} }
/**
* @return Total count since meter was created
*/
ZT_ALWAYS_INLINE uint64_t total() const noexcept { return _total.load(); }
private: private:
volatile double _history[ZT_METER_HISTORY_LENGTH]; const int64_t startTime;
volatile int64_t _ts; std::atomic<uint64_t> _total;
volatile uint64_t _count; std::atomic<uint64_t> _counts[LSIZE];
std::atomic<unsigned int> _hptr; std::atomic<unsigned long> _bucket;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -263,6 +263,13 @@ namespace Protocol {
*/ */
enum Verb enum Verb
{ {
/**
* No operation
*
* This packet does nothing, but it is sometimes sent as a probe to
* trigger a HELLO exchange as the code will attempt HELLO when it
* receives a packet from an unidentified source.
*/
VERB_NOP = 0x00, VERB_NOP = 0x00,
/** /**
@ -280,8 +287,8 @@ enum Verb
* <[2] 16-bit length of meta-data dictionary> * <[2] 16-bit length of meta-data dictionary>
* <[...] meta-data dictionary> * <[...] meta-data dictionary>
* <[2] 16-bit length of any additional fields> * <[2] 16-bit length of any additional fields>
* <[48] HMAC-SHA384 of full plaintext payload>
* [... end encrypted region ...] * [... end encrypted region ...]
* <[48] HMAC-SHA384 of full plaintext payload>
* *
* HELLO is sent with authentication but without the usual encryption so * HELLO is sent with authentication but without the usual encryption so
* that peers can exchange identities. * that peers can exchange identities.