mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 03:53:44 +02:00
RingBuffer<> is now templated with size, buffer is now static.
This commit is contained in:
parent
af3ec000a0
commit
d530356055
6 changed files with 95 additions and 247 deletions
|
@ -123,7 +123,8 @@ public:
|
||||||
_lastComputedThroughputDistCoeff(0.0),
|
_lastComputedThroughputDistCoeff(0.0),
|
||||||
_lastAllocation(0)
|
_lastAllocation(0)
|
||||||
{
|
{
|
||||||
prepareBuffers();
|
memset(_ifname, 0, 16);
|
||||||
|
memset(_addrString, 0, sizeof(_addrString));
|
||||||
}
|
}
|
||||||
|
|
||||||
Path(const int64_t localSocket,const InetAddress &addr) :
|
Path(const int64_t localSocket,const InetAddress &addr) :
|
||||||
|
@ -155,22 +156,11 @@ public:
|
||||||
_lastComputedThroughputDistCoeff(0.0),
|
_lastComputedThroughputDistCoeff(0.0),
|
||||||
_lastAllocation(0)
|
_lastAllocation(0)
|
||||||
{
|
{
|
||||||
prepareBuffers();
|
memset(_ifname, 0, 16);
|
||||||
|
memset(_addrString, 0, sizeof(_addrString));
|
||||||
_phy->getIfName((PhySocket *)((uintptr_t)_localSocket), _ifname, 16);
|
_phy->getIfName((PhySocket *)((uintptr_t)_localSocket), _ifname, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Path()
|
|
||||||
{
|
|
||||||
delete _throughputSamples;
|
|
||||||
delete _latencySamples;
|
|
||||||
delete _packetValiditySamples;
|
|
||||||
delete _throughputDisturbanceSamples;
|
|
||||||
_throughputSamples = NULL;
|
|
||||||
_latencySamples = NULL;
|
|
||||||
_packetValiditySamples = NULL;
|
|
||||||
_throughputDisturbanceSamples = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a packet is received from this remote path, regardless of content
|
* Called when a packet is received from this remote path, regardless of content
|
||||||
*
|
*
|
||||||
|
@ -216,7 +206,7 @@ public:
|
||||||
else {
|
else {
|
||||||
_latency = l;
|
_latency = l;
|
||||||
}
|
}
|
||||||
_latencySamples->push(l);
|
_latencySamples.push(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -345,7 +335,7 @@ public:
|
||||||
_inQoSRecords[packetId] = now;
|
_inQoSRecords[packetId] = now;
|
||||||
_packetsReceivedSinceLastQoS++;
|
_packetsReceivedSinceLastQoS++;
|
||||||
}
|
}
|
||||||
_packetValiditySamples->push(true);
|
_packetValiditySamples.push(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +352,7 @@ public:
|
||||||
int64_t timeSinceThroughputEstimate = (now - _lastThroughputEstimation);
|
int64_t timeSinceThroughputEstimate = (now - _lastThroughputEstimation);
|
||||||
if (timeSinceThroughputEstimate >= ZT_PATH_THROUGHPUT_MEASUREMENT_INTERVAL) {
|
if (timeSinceThroughputEstimate >= ZT_PATH_THROUGHPUT_MEASUREMENT_INTERVAL) {
|
||||||
uint64_t throughput = (float)(_bytesAckedSinceLastThroughputEstimation * 8) / ((float)timeSinceThroughputEstimate / (float)1000);
|
uint64_t throughput = (float)(_bytesAckedSinceLastThroughputEstimation * 8) / ((float)timeSinceThroughputEstimate / (float)1000);
|
||||||
_throughputSamples->push(throughput);
|
_throughputSamples.push(throughput);
|
||||||
_maxLifetimeThroughput = throughput > _maxLifetimeThroughput ? throughput : _maxLifetimeThroughput;
|
_maxLifetimeThroughput = throughput > _maxLifetimeThroughput ? throughput : _maxLifetimeThroughput;
|
||||||
_lastThroughputEstimation = now;
|
_lastThroughputEstimation = now;
|
||||||
_bytesAckedSinceLastThroughputEstimation = 0;
|
_bytesAckedSinceLastThroughputEstimation = 0;
|
||||||
|
@ -564,7 +554,7 @@ public:
|
||||||
* Record an invalid incoming packet. This packet failed MAC/compression/cipher checks and will now
|
* Record an invalid incoming packet. This packet failed MAC/compression/cipher checks and will now
|
||||||
* contribute to a Packet Error Ratio (PER).
|
* contribute to a Packet Error Ratio (PER).
|
||||||
*/
|
*/
|
||||||
inline void recordInvalidPacket() { _packetValiditySamples->push(false); }
|
inline void recordInvalidPacket() { _packetValiditySamples.push(false); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A pointer to a cached copy of the address string for this Path (For debugging only)
|
* @return A pointer to a cached copy of the address string for this Path (For debugging only)
|
||||||
|
@ -582,35 +572,43 @@ public:
|
||||||
*
|
*
|
||||||
* @param now Current time
|
* @param now Current time
|
||||||
*/
|
*/
|
||||||
inline void processBackgroundPathMeasurements(int64_t now) {
|
inline void processBackgroundPathMeasurements(const int64_t now)
|
||||||
|
{
|
||||||
if (now - _lastPathQualityComputeTime > ZT_PATH_QUALITY_COMPUTE_INTERVAL) {
|
if (now - _lastPathQualityComputeTime > ZT_PATH_QUALITY_COMPUTE_INTERVAL) {
|
||||||
Mutex::Lock _l(_statistics_m);
|
Mutex::Lock _l(_statistics_m);
|
||||||
_lastPathQualityComputeTime = now;
|
_lastPathQualityComputeTime = now;
|
||||||
address().toString(_addrString);
|
address().toString(_addrString);
|
||||||
_lastComputedMeanLatency = _latencySamples->mean();
|
_lastComputedMeanLatency = _latencySamples.mean();
|
||||||
_lastComputedPacketDelayVariance = _latencySamples->stddev(); // Similar to "jitter" (SEE: RFC 3393, RFC 4689)
|
_lastComputedPacketDelayVariance = _latencySamples.stddev(); // Similar to "jitter" (SEE: RFC 3393, RFC 4689)
|
||||||
_lastComputedMeanThroughput = (uint64_t)_throughputSamples->mean();
|
_lastComputedMeanThroughput = (uint64_t)_throughputSamples.mean();
|
||||||
|
|
||||||
// If no packet validity samples, assume PER==0
|
// If no packet validity samples, assume PER==0
|
||||||
_lastComputedPacketErrorRatio = 1 - (_packetValiditySamples->count() ? _packetValiditySamples->mean() : 1);
|
_lastComputedPacketErrorRatio = 1 - (_packetValiditySamples.count() ? _packetValiditySamples.mean() : 1);
|
||||||
|
|
||||||
// Compute path stability
|
// Compute path stability
|
||||||
// Normalize measurements with wildly different ranges into a reasonable range
|
// Normalize measurements with wildly different ranges into a reasonable range
|
||||||
float normalized_pdv = Utils::normalize(_lastComputedPacketDelayVariance, 0, ZT_PATH_MAX_PDV, 0, 10);
|
float normalized_pdv = Utils::normalize(_lastComputedPacketDelayVariance, 0, ZT_PATH_MAX_PDV, 0, 10);
|
||||||
float normalized_la = Utils::normalize(_lastComputedMeanLatency, 0, ZT_PATH_MAX_MEAN_LATENCY, 0, 10);
|
float normalized_la = Utils::normalize(_lastComputedMeanLatency, 0, ZT_PATH_MAX_MEAN_LATENCY, 0, 10);
|
||||||
float throughput_cv = _throughputSamples->mean() > 0 ? _throughputSamples->stddev() / _throughputSamples->mean() : 1;
|
float throughput_cv = _throughputSamples.mean() > 0 ? _throughputSamples.stddev() / _throughputSamples.mean() : 1;
|
||||||
|
|
||||||
// Form an exponential cutoff and apply contribution weights
|
// Form an exponential cutoff and apply contribution weights
|
||||||
float pdv_contrib = exp((-1)*normalized_pdv) * ZT_PATH_CONTRIB_PDV;
|
float pdv_contrib = exp((-1)*normalized_pdv) * ZT_PATH_CONTRIB_PDV;
|
||||||
float latency_contrib = exp((-1)*normalized_la) * ZT_PATH_CONTRIB_LATENCY;
|
float latency_contrib = exp((-1)*normalized_la) * ZT_PATH_CONTRIB_LATENCY;
|
||||||
|
|
||||||
// Throughput Disturbance Coefficient
|
// Throughput Disturbance Coefficient
|
||||||
float throughput_disturbance_contrib = exp((-1)*throughput_cv) * ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE;
|
float throughput_disturbance_contrib = exp((-1)*throughput_cv) * ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE;
|
||||||
_throughputDisturbanceSamples->push(throughput_cv);
|
_throughputDisturbanceSamples.push(throughput_cv);
|
||||||
_lastComputedThroughputDistCoeff = _throughputDisturbanceSamples->mean();
|
_lastComputedThroughputDistCoeff = _throughputDisturbanceSamples.mean();
|
||||||
|
|
||||||
// Obey user-defined ignored contributions
|
// Obey user-defined ignored contributions
|
||||||
pdv_contrib = ZT_PATH_CONTRIB_PDV > 0.0 ? pdv_contrib : 1;
|
pdv_contrib = ZT_PATH_CONTRIB_PDV > 0.0 ? pdv_contrib : 1;
|
||||||
latency_contrib = ZT_PATH_CONTRIB_LATENCY > 0.0 ? latency_contrib : 1;
|
latency_contrib = ZT_PATH_CONTRIB_LATENCY > 0.0 ? latency_contrib : 1;
|
||||||
throughput_disturbance_contrib = ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE > 0.0 ? throughput_disturbance_contrib : 1;
|
throughput_disturbance_contrib = ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE > 0.0 ? throughput_disturbance_contrib : 1;
|
||||||
|
|
||||||
// Stability
|
// Stability
|
||||||
_lastComputedStability = pdv_contrib + latency_contrib + throughput_disturbance_contrib;
|
_lastComputedStability = pdv_contrib + latency_contrib + throughput_disturbance_contrib;
|
||||||
_lastComputedStability *= 1 - _lastComputedPacketErrorRatio;
|
_lastComputedStability *= 1 - _lastComputedPacketErrorRatio;
|
||||||
|
|
||||||
// Prevent QoS records from sticking around for too long
|
// Prevent QoS records from sticking around for too long
|
||||||
std::map<uint64_t,uint64_t>::iterator it = _outQoSRecords.begin();
|
std::map<uint64_t,uint64_t>::iterator it = _outQoSRecords.begin();
|
||||||
while (it != _outQoSRecords.end()) {
|
while (it != _outQoSRecords.end()) {
|
||||||
|
@ -647,18 +645,6 @@ public:
|
||||||
*/
|
*/
|
||||||
inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; }
|
inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize statistical buffers
|
|
||||||
*/
|
|
||||||
inline void prepareBuffers() {
|
|
||||||
_throughputSamples = new RingBuffer<uint64_t>(ZT_PATH_QUALITY_METRIC_WIN_SZ);
|
|
||||||
_latencySamples = new RingBuffer<uint32_t>(ZT_PATH_QUALITY_METRIC_WIN_SZ);
|
|
||||||
_packetValiditySamples = new RingBuffer<bool>(ZT_PATH_QUALITY_METRIC_WIN_SZ);
|
|
||||||
_throughputDisturbanceSamples = new RingBuffer<float>(ZT_PATH_QUALITY_METRIC_WIN_SZ);
|
|
||||||
memset(_ifname, 0, 16);
|
|
||||||
memset(_addrString, 0, sizeof(_addrString));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mutex _statistics_m;
|
Mutex _statistics_m;
|
||||||
|
|
||||||
|
@ -672,9 +658,9 @@ private:
|
||||||
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
|
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
|
||||||
AtomicCounter __refCount;
|
AtomicCounter __refCount;
|
||||||
|
|
||||||
std::map<uint64_t, uint64_t> _outQoSRecords; // id:egress_time
|
std::map<uint64_t,uint64_t> _outQoSRecords; // id:egress_time
|
||||||
std::map<uint64_t, uint64_t> _inQoSRecords; // id:now
|
std::map<uint64_t,uint64_t> _inQoSRecords; // id:now
|
||||||
std::map<uint64_t, uint16_t> _inACKRecords; // id:len
|
std::map<uint64_t,uint16_t> _inACKRecords; // id:len
|
||||||
|
|
||||||
int64_t _lastAck;
|
int64_t _lastAck;
|
||||||
int64_t _lastThroughputEstimation;
|
int64_t _lastThroughputEstimation;
|
||||||
|
@ -702,16 +688,14 @@ private:
|
||||||
float _lastComputedThroughputDistCoeff;
|
float _lastComputedThroughputDistCoeff;
|
||||||
unsigned char _lastAllocation;
|
unsigned char _lastAllocation;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// cached human-readable strings for tracing purposes
|
// cached human-readable strings for tracing purposes
|
||||||
char _ifname[16];
|
char _ifname[16];
|
||||||
char _addrString[256];
|
char _addrString[256];
|
||||||
|
|
||||||
RingBuffer<uint64_t> *_throughputSamples;
|
RingBuffer<uint64_t,ZT_PATH_QUALITY_METRIC_WIN_SZ> _throughputSamples;
|
||||||
RingBuffer<uint32_t> *_latencySamples;
|
RingBuffer<uint32_t,ZT_PATH_QUALITY_METRIC_WIN_SZ> _latencySamples;
|
||||||
RingBuffer<bool> *_packetValiditySamples;
|
RingBuffer<bool,ZT_PATH_QUALITY_METRIC_WIN_SZ> _packetValiditySamples;
|
||||||
RingBuffer<float> *_throughputDisturbanceSamples;
|
RingBuffer<float,ZT_PATH_QUALITY_METRIC_WIN_SZ> _throughputDisturbanceSamples;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -76,7 +76,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
|
||||||
Utils::getSecureRandom(&_freeRandomByte, 1);
|
Utils::getSecureRandom(&_freeRandomByte, 1);
|
||||||
if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
|
if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
|
||||||
throw ZT_EXCEPTION_INVALID_ARGUMENT;
|
throw ZT_EXCEPTION_INVALID_ARGUMENT;
|
||||||
_pathChoiceHist = new RingBuffer<int>(ZT_MULTIPATH_PROPORTION_WIN_SZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Peer::received(
|
void Peer::received(
|
||||||
|
@ -471,7 +470,7 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired)
|
||||||
if (_paths[i].p) {
|
if (_paths[i].p) {
|
||||||
if (rf < _paths[i].p->allocation()) {
|
if (rf < _paths[i].p->allocation()) {
|
||||||
bestPath = i;
|
bestPath = i;
|
||||||
_pathChoiceHist->push(bestPath); // Record which path we chose
|
_pathChoiceHist.push(bestPath); // Record which path we chose
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rf -= _paths[i].p->allocation();
|
rf -= _paths[i].p->allocation();
|
||||||
|
@ -500,7 +499,7 @@ char *Peer::interfaceListStr()
|
||||||
float targetAllocation = 1.0 / alivePathCount;
|
float targetAllocation = 1.0 / alivePathCount;
|
||||||
float currentAllocation = 1.0;
|
float currentAllocation = 1.0;
|
||||||
if (alivePathCount > 1) {
|
if (alivePathCount > 1) {
|
||||||
currentAllocation = (float)_pathChoiceHist->countValue(i) / (float)_pathChoiceHist->count();
|
currentAllocation = (float)_pathChoiceHist.countValue(i) / (float)_pathChoiceHist.count();
|
||||||
if (fabs(targetAllocation - currentAllocation) > ZT_PATH_IMBALANCE_THRESHOLD) {
|
if (fabs(targetAllocation - currentAllocation) > ZT_PATH_IMBALANCE_THRESHOLD) {
|
||||||
imbalanced = true;
|
imbalanced = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,11 +60,7 @@ private:
|
||||||
Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
|
Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Peer() {
|
~Peer() { Utils::burn(_key,sizeof(_key)); }
|
||||||
Utils::burn(_key,sizeof(_key));
|
|
||||||
delete _pathChoiceHist;
|
|
||||||
_pathChoiceHist = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new peer
|
* Construct a new peer
|
||||||
|
@ -674,7 +670,7 @@ private:
|
||||||
|
|
||||||
AtomicCounter __refCount;
|
AtomicCounter __refCount;
|
||||||
|
|
||||||
RingBuffer<int> *_pathChoiceHist;
|
RingBuffer<int,ZT_MULTIPATH_PROPORTION_WIN_SZ> _pathChoiceHist;
|
||||||
|
|
||||||
bool _linkIsBalanced;
|
bool _linkIsBalanced;
|
||||||
bool _linkIsRedundant;
|
bool _linkIsRedundant;
|
||||||
|
|
|
@ -18,115 +18,6 @@ Public domain.
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
// "Naive" implementation, which is slower... might still want this on some older
|
|
||||||
// or weird platforms if the later versions have issues.
|
|
||||||
|
|
||||||
static inline void add(unsigned int h[17],const unsigned int c[17])
|
|
||||||
{
|
|
||||||
unsigned int j;
|
|
||||||
unsigned int u;
|
|
||||||
u = 0;
|
|
||||||
for (j = 0;j < 17;++j) { u += h[j] + c[j]; h[j] = u & 255; u >>= 8; }
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void squeeze(unsigned int h[17])
|
|
||||||
{
|
|
||||||
unsigned int j;
|
|
||||||
unsigned int u;
|
|
||||||
u = 0;
|
|
||||||
for (j = 0;j < 16;++j) { u += h[j]; h[j] = u & 255; u >>= 8; }
|
|
||||||
u += h[16]; h[16] = u & 3;
|
|
||||||
u = 5 * (u >> 2);
|
|
||||||
for (j = 0;j < 16;++j) { u += h[j]; h[j] = u & 255; u >>= 8; }
|
|
||||||
u += h[16]; h[16] = u;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const unsigned int minusp[17] = {
|
|
||||||
5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static inline void freeze(unsigned int h[17])
|
|
||||||
{
|
|
||||||
unsigned int horig[17];
|
|
||||||
unsigned int j;
|
|
||||||
unsigned int negative;
|
|
||||||
for (j = 0;j < 17;++j) horig[j] = h[j];
|
|
||||||
add(h,minusp);
|
|
||||||
negative = -(h[16] >> 7);
|
|
||||||
for (j = 0;j < 17;++j) h[j] ^= negative & (horig[j] ^ h[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mulmod(unsigned int h[17],const unsigned int r[17])
|
|
||||||
{
|
|
||||||
unsigned int hr[17];
|
|
||||||
unsigned int i;
|
|
||||||
unsigned int j;
|
|
||||||
unsigned int u;
|
|
||||||
|
|
||||||
for (i = 0;i < 17;++i) {
|
|
||||||
u = 0;
|
|
||||||
for (j = 0;j <= i;++j) u += h[j] * r[i - j];
|
|
||||||
for (j = i + 1;j < 17;++j) u += 320 * h[j] * r[i + 17 - j];
|
|
||||||
hr[i] = u;
|
|
||||||
}
|
|
||||||
for (i = 0;i < 17;++i) h[i] = hr[i];
|
|
||||||
squeeze(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int crypto_onetimeauth(unsigned char *out,const unsigned char *in,unsigned long long inlen,const unsigned char *k)
|
|
||||||
{
|
|
||||||
unsigned int j;
|
|
||||||
unsigned int r[17];
|
|
||||||
unsigned int h[17];
|
|
||||||
unsigned int c[17];
|
|
||||||
|
|
||||||
r[0] = k[0];
|
|
||||||
r[1] = k[1];
|
|
||||||
r[2] = k[2];
|
|
||||||
r[3] = k[3] & 15;
|
|
||||||
r[4] = k[4] & 252;
|
|
||||||
r[5] = k[5];
|
|
||||||
r[6] = k[6];
|
|
||||||
r[7] = k[7] & 15;
|
|
||||||
r[8] = k[8] & 252;
|
|
||||||
r[9] = k[9];
|
|
||||||
r[10] = k[10];
|
|
||||||
r[11] = k[11] & 15;
|
|
||||||
r[12] = k[12] & 252;
|
|
||||||
r[13] = k[13];
|
|
||||||
r[14] = k[14];
|
|
||||||
r[15] = k[15] & 15;
|
|
||||||
r[16] = 0;
|
|
||||||
|
|
||||||
for (j = 0;j < 17;++j) h[j] = 0;
|
|
||||||
|
|
||||||
while (inlen > 0) {
|
|
||||||
for (j = 0;j < 17;++j) c[j] = 0;
|
|
||||||
for (j = 0;(j < 16) && (j < inlen);++j) c[j] = in[j];
|
|
||||||
c[j] = 1;
|
|
||||||
in += j; inlen -= j;
|
|
||||||
add(h,c);
|
|
||||||
mulmod(h,r);
|
|
||||||
}
|
|
||||||
|
|
||||||
freeze(h);
|
|
||||||
|
|
||||||
for (j = 0;j < 16;++j) c[j] = k[j + 16];
|
|
||||||
c[16] = 0;
|
|
||||||
add(h,c);
|
|
||||||
for (j = 0;j < 16;++j) out[j] = h[j];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key)
|
|
||||||
{
|
|
||||||
crypto_onetimeauth((unsigned char *)auth,(const unsigned char *)data,len,(const unsigned char *)key);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
typedef struct poly1305_context {
|
typedef struct poly1305_context {
|
||||||
|
@ -215,8 +106,7 @@ static inline void U64TO8(unsigned char *p, unsigned long long v)
|
||||||
#define U64TO8(p,v) ((*reinterpret_cast<unsigned long long *>(p)) = (v))
|
#define U64TO8(p,v) ((*reinterpret_cast<unsigned long long *>(p)) = (v))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void
|
static inline void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
||||||
poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
|
||||||
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
|
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
|
||||||
unsigned long long t0,t1;
|
unsigned long long t0,t1;
|
||||||
|
|
||||||
|
@ -241,8 +131,7 @@ poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
||||||
st->final = 0;
|
st->final = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
|
||||||
poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
|
|
||||||
const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
|
const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
|
||||||
unsigned long long r0,r1,r2;
|
unsigned long long r0,r1,r2;
|
||||||
unsigned long long s1,s2;
|
unsigned long long s1,s2;
|
||||||
|
@ -293,8 +182,7 @@ poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t by
|
||||||
st->h[2] = h2;
|
st->h[2] = h2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
|
||||||
poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
|
|
||||||
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
|
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
|
||||||
unsigned long long h0,h1,h2,c;
|
unsigned long long h0,h1,h2,c;
|
||||||
unsigned long long g0,g1,g2;
|
unsigned long long g0,g1,g2;
|
||||||
|
@ -582,8 +470,7 @@ poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
|
||||||
|
|
||||||
#endif // MSC/GCC or not
|
#endif // MSC/GCC or not
|
||||||
|
|
||||||
static inline void
|
static inline void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
|
||||||
poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
|
|
||||||
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
|
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
|
|
@ -47,40 +47,28 @@ namespace ZeroTier {
|
||||||
* to reduce the complexity of code needed to interact with this type of buffer.
|
* to reduce the complexity of code needed to interact with this type of buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template <class T>
|
template <class T,size_t S>
|
||||||
class RingBuffer
|
class RingBuffer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
T * buf;
|
T buf[S];
|
||||||
size_t size;
|
|
||||||
size_t begin;
|
size_t begin;
|
||||||
size_t end;
|
size_t end;
|
||||||
bool wrap;
|
bool wrap;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
RingBuffer() :
|
||||||
/**
|
|
||||||
* create a RingBuffer with space for up to size elements.
|
|
||||||
*/
|
|
||||||
explicit RingBuffer(size_t size)
|
|
||||||
: size(size),
|
|
||||||
begin(0),
|
begin(0),
|
||||||
end(0),
|
end(0),
|
||||||
wrap(false)
|
wrap(false)
|
||||||
{
|
{
|
||||||
buf = new T[size];
|
memset(buf,0,sizeof(T)*S);
|
||||||
memset(buf, 0, sizeof(T) * size);
|
|
||||||
}
|
|
||||||
|
|
||||||
~RingBuffer()
|
|
||||||
{
|
|
||||||
delete [] buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A pointer to the underlying buffer
|
* @return A pointer to the underlying buffer
|
||||||
*/
|
*/
|
||||||
T* get_buf()
|
inline T *get_buf()
|
||||||
{
|
{
|
||||||
return buf + begin;
|
return buf + begin;
|
||||||
}
|
}
|
||||||
|
@ -90,17 +78,17 @@ public:
|
||||||
* @param n Number of elements to copy in
|
* @param n Number of elements to copy in
|
||||||
* @return Number of elements we copied in
|
* @return Number of elements we copied in
|
||||||
*/
|
*/
|
||||||
size_t produce(size_t n)
|
inline size_t produce(size_t n)
|
||||||
{
|
{
|
||||||
n = std::min(n, getFree());
|
n = std::min(n, getFree());
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
const size_t first_chunk = std::min(n, size - end);
|
const size_t first_chunk = std::min(n, S - end);
|
||||||
end = (end + first_chunk) % size;
|
end = (end + first_chunk) % S;
|
||||||
if (first_chunk < n) {
|
if (first_chunk < n) {
|
||||||
const size_t second_chunk = n - first_chunk;
|
const size_t second_chunk = n - first_chunk;
|
||||||
end = (end + second_chunk) % size;
|
end = (end + second_chunk) % S;
|
||||||
}
|
}
|
||||||
if (begin == end) {
|
if (begin == end) {
|
||||||
wrap = true;
|
wrap = true;
|
||||||
|
@ -112,17 +100,14 @@ public:
|
||||||
* Fast erase, O(1).
|
* Fast erase, O(1).
|
||||||
* Merely reset the buffer pointer, doesn't erase contents
|
* Merely reset the buffer pointer, doesn't erase contents
|
||||||
*/
|
*/
|
||||||
void reset()
|
inline void reset() { consume(count()); }
|
||||||
{
|
|
||||||
consume(count());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* adjust buffer index pointer as if we copied data out
|
* adjust buffer index pointer as if we copied data out
|
||||||
* @param n Number of elements we copied from the buffer
|
* @param n Number of elements we copied from the buffer
|
||||||
* @return Number of elements actually available from the buffer
|
* @return Number of elements actually available from the buffer
|
||||||
*/
|
*/
|
||||||
size_t consume(size_t n)
|
inline size_t consume(size_t n)
|
||||||
{
|
{
|
||||||
n = std::min(n, count());
|
n = std::min(n, count());
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
@ -131,11 +116,11 @@ public:
|
||||||
if (wrap) {
|
if (wrap) {
|
||||||
wrap = false;
|
wrap = false;
|
||||||
}
|
}
|
||||||
const size_t first_chunk = std::min(n, size - begin);
|
const size_t first_chunk = std::min(n, S - begin);
|
||||||
begin = (begin + first_chunk) % size;
|
begin = (begin + first_chunk) % S;
|
||||||
if (first_chunk < n) {
|
if (first_chunk < n) {
|
||||||
const size_t second_chunk = n - first_chunk;
|
const size_t second_chunk = n - first_chunk;
|
||||||
begin = (begin + second_chunk) % size;
|
begin = (begin + second_chunk) % S;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -144,19 +129,19 @@ public:
|
||||||
* @param data Buffer that is to be written to the ring
|
* @param data Buffer that is to be written to the ring
|
||||||
* @param n Number of elements to write to the buffer
|
* @param n Number of elements to write to the buffer
|
||||||
*/
|
*/
|
||||||
size_t write(const T * data, size_t n)
|
inline size_t write(const T * data, size_t n)
|
||||||
{
|
{
|
||||||
n = std::min(n, getFree());
|
n = std::min(n, getFree());
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
const size_t first_chunk = std::min(n, size - end);
|
const size_t first_chunk = std::min(n, S - end);
|
||||||
memcpy(buf + end, data, first_chunk * sizeof(T));
|
memcpy(buf + end, data, first_chunk * sizeof(T));
|
||||||
end = (end + first_chunk) % size;
|
end = (end + first_chunk) % S;
|
||||||
if (first_chunk < n) {
|
if (first_chunk < n) {
|
||||||
const size_t second_chunk = n - first_chunk;
|
const size_t second_chunk = n - first_chunk;
|
||||||
memcpy(buf + end, data + first_chunk, second_chunk * sizeof(T));
|
memcpy(buf + end, data + first_chunk, second_chunk * sizeof(T));
|
||||||
end = (end + second_chunk) % size;
|
end = (end + second_chunk) % S;
|
||||||
}
|
}
|
||||||
if (begin == end) {
|
if (begin == end) {
|
||||||
wrap = true;
|
wrap = true;
|
||||||
|
@ -169,14 +154,14 @@ public:
|
||||||
*
|
*
|
||||||
* @param value A single value to be placed in the buffer
|
* @param value A single value to be placed in the buffer
|
||||||
*/
|
*/
|
||||||
void push(const T value)
|
inline void push(const T value)
|
||||||
{
|
{
|
||||||
if (count() == size) {
|
if (count() == S) {
|
||||||
consume(1);
|
consume(1);
|
||||||
}
|
}
|
||||||
const size_t first_chunk = std::min((size_t)1, size - end);
|
const size_t first_chunk = std::min((size_t)1, S - end);
|
||||||
*(buf + end) = value;
|
*(buf + end) = value;
|
||||||
end = (end + first_chunk) % size;
|
end = (end + first_chunk) % S;
|
||||||
if (begin == end) {
|
if (begin == end) {
|
||||||
wrap = true;
|
wrap = true;
|
||||||
}
|
}
|
||||||
|
@ -185,14 +170,14 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return The most recently pushed element on the buffer
|
* @return The most recently pushed element on the buffer
|
||||||
*/
|
*/
|
||||||
T get_most_recent() { return *(buf + end); }
|
inline T get_most_recent() { return *(buf + end); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dest Destination buffer
|
* @param dest Destination buffer
|
||||||
* @param n Size (in terms of number of elements) of the destination buffer
|
* @param n Size (in terms of number of elements) of the destination buffer
|
||||||
* @return Number of elements read from the buffer
|
* @return Number of elements read from the buffer
|
||||||
*/
|
*/
|
||||||
size_t read(T * dest, size_t n)
|
inline size_t read(T *dest,size_t n)
|
||||||
{
|
{
|
||||||
n = std::min(n, count());
|
n = std::min(n, count());
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
@ -201,13 +186,13 @@ public:
|
||||||
if (wrap) {
|
if (wrap) {
|
||||||
wrap = false;
|
wrap = false;
|
||||||
}
|
}
|
||||||
const size_t first_chunk = std::min(n, size - begin);
|
const size_t first_chunk = std::min(n, S - begin);
|
||||||
memcpy(dest, buf + begin, first_chunk * sizeof(T));
|
memcpy(dest, buf + begin, first_chunk * sizeof(T));
|
||||||
begin = (begin + first_chunk) % size;
|
begin = (begin + first_chunk) % S;
|
||||||
if (first_chunk < n) {
|
if (first_chunk < n) {
|
||||||
const size_t second_chunk = n - first_chunk;
|
const size_t second_chunk = n - first_chunk;
|
||||||
memcpy(dest + first_chunk, buf + begin, second_chunk * sizeof(T));
|
memcpy(dest + first_chunk, buf + begin, second_chunk * sizeof(T));
|
||||||
begin = (begin + second_chunk) % size;
|
begin = (begin + second_chunk) % S;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -217,34 +202,34 @@ public:
|
||||||
*
|
*
|
||||||
* @return The number of elements in the buffer
|
* @return The number of elements in the buffer
|
||||||
*/
|
*/
|
||||||
size_t count()
|
inline size_t count()
|
||||||
{
|
{
|
||||||
if (end == begin) {
|
if (end == begin) {
|
||||||
return wrap ? size : 0;
|
return wrap ? S : 0;
|
||||||
}
|
}
|
||||||
else if (end > begin) {
|
else if (end > begin) {
|
||||||
return end - begin;
|
return end - begin;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return size + end - begin;
|
return S + end - begin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The number of slots that are unused in the buffer
|
* @return The number of slots that are unused in the buffer
|
||||||
*/
|
*/
|
||||||
size_t getFree() { return size - count(); }
|
inline size_t getFree() { return S - count(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The arithmetic mean of the contents of the buffer
|
* @return The arithmetic mean of the contents of the buffer
|
||||||
*/
|
*/
|
||||||
float mean()
|
inline float mean()
|
||||||
{
|
{
|
||||||
size_t iterator = begin;
|
size_t iterator = begin;
|
||||||
float subtotal = 0;
|
float subtotal = 0;
|
||||||
size_t curr_cnt = count();
|
size_t curr_cnt = count();
|
||||||
for (size_t i=0; i<curr_cnt; i++) {
|
for (size_t i=0; i<curr_cnt; i++) {
|
||||||
iterator = (iterator + size - 1) % curr_cnt;
|
iterator = (iterator + S - 1) % curr_cnt;
|
||||||
subtotal += (float)*(buf + iterator);
|
subtotal += (float)*(buf + iterator);
|
||||||
}
|
}
|
||||||
return curr_cnt ? subtotal / (float)curr_cnt : 0;
|
return curr_cnt ? subtotal / (float)curr_cnt : 0;
|
||||||
|
@ -253,14 +238,14 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return The arithmetic mean of the most recent 'n' elements of the buffer
|
* @return The arithmetic mean of the most recent 'n' elements of the buffer
|
||||||
*/
|
*/
|
||||||
float mean(size_t n)
|
inline float mean(size_t n)
|
||||||
{
|
{
|
||||||
n = n < size ? n : size;
|
n = n < S ? n : S;
|
||||||
size_t iterator = begin;
|
size_t iterator = begin;
|
||||||
float subtotal = 0;
|
float subtotal = 0;
|
||||||
size_t curr_cnt = count();
|
size_t curr_cnt = count();
|
||||||
for (size_t i=0; i<n; i++) {
|
for (size_t i=0; i<n; i++) {
|
||||||
iterator = (iterator + size - 1) % curr_cnt;
|
iterator = (iterator + S - 1) % curr_cnt;
|
||||||
subtotal += (float)*(buf + iterator);
|
subtotal += (float)*(buf + iterator);
|
||||||
}
|
}
|
||||||
return curr_cnt ? subtotal / (float)curr_cnt : 0;
|
return curr_cnt ? subtotal / (float)curr_cnt : 0;
|
||||||
|
@ -269,39 +254,36 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return The sample standard deviation of element values
|
* @return The sample standard deviation of element values
|
||||||
*/
|
*/
|
||||||
float stddev() { return sqrt(variance()); }
|
inline float stddev() { return sqrt(variance()); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The variance of element values
|
* @return The variance of element values
|
||||||
*/
|
*/
|
||||||
float variance()
|
inline float variance()
|
||||||
{
|
{
|
||||||
size_t iterator = begin;
|
size_t iterator = begin;
|
||||||
float cached_mean = mean();
|
float cached_mean = mean();
|
||||||
size_t curr_cnt = count();
|
size_t curr_cnt = count();
|
||||||
if (size) {
|
T sum_of_squared_deviations = 0;
|
||||||
T sum_of_squared_deviations = 0;
|
for (size_t i=0; i<curr_cnt; i++) {
|
||||||
for (size_t i=0; i<curr_cnt; i++) {
|
iterator = (iterator + S - 1) % curr_cnt;
|
||||||
iterator = (iterator + size - 1) % curr_cnt;
|
float deviation = (buf[i] - cached_mean);
|
||||||
float deviation = (buf[i] - cached_mean);
|
sum_of_squared_deviations += (deviation*deviation);
|
||||||
sum_of_squared_deviations += (deviation*deviation);
|
|
||||||
}
|
|
||||||
float variance = (float)sum_of_squared_deviations / (float)(size - 1);
|
|
||||||
return variance;
|
|
||||||
}
|
}
|
||||||
return 0;
|
float variance = (float)sum_of_squared_deviations / (float)(S - 1);
|
||||||
|
return variance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The number of elements of zero value
|
* @return The number of elements of zero value
|
||||||
*/
|
*/
|
||||||
size_t zeroCount()
|
inline size_t zeroCount()
|
||||||
{
|
{
|
||||||
size_t iterator = begin;
|
size_t iterator = begin;
|
||||||
size_t zeros = 0;
|
size_t zeros = 0;
|
||||||
size_t curr_cnt = count();
|
size_t curr_cnt = count();
|
||||||
for (size_t i=0; i<curr_cnt; i++) {
|
for (size_t i=0; i<curr_cnt; i++) {
|
||||||
iterator = (iterator + size - 1) % curr_cnt;
|
iterator = (iterator + S - 1) % curr_cnt;
|
||||||
if (*(buf + iterator) == 0) {
|
if (*(buf + iterator) == 0) {
|
||||||
zeros++;
|
zeros++;
|
||||||
}
|
}
|
||||||
|
@ -313,13 +295,13 @@ public:
|
||||||
* @param value Value to match against in buffer
|
* @param value Value to match against in buffer
|
||||||
* @return The number of values held in the ring buffer which match a given value
|
* @return The number of values held in the ring buffer which match a given value
|
||||||
*/
|
*/
|
||||||
size_t countValue(T value)
|
inline size_t countValue(T value)
|
||||||
{
|
{
|
||||||
size_t iterator = begin;
|
size_t iterator = begin;
|
||||||
size_t cnt = 0;
|
size_t cnt = 0;
|
||||||
size_t curr_cnt = count();
|
size_t curr_cnt = count();
|
||||||
for (size_t i=0; i<curr_cnt; i++) {
|
for (size_t i=0; i<curr_cnt; i++) {
|
||||||
iterator = (iterator + size - 1) % curr_cnt;
|
iterator = (iterator + S - 1) % curr_cnt;
|
||||||
if (*(buf + iterator) == value) {
|
if (*(buf + iterator) == value) {
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
|
@ -330,11 +312,11 @@ public:
|
||||||
/**
|
/**
|
||||||
* Print the contents of the buffer
|
* Print the contents of the buffer
|
||||||
*/
|
*/
|
||||||
void dump()
|
inline void dump()
|
||||||
{
|
{
|
||||||
size_t iterator = begin;
|
size_t iterator = begin;
|
||||||
for (size_t i=0; i<size; i++) {
|
for (size_t i=0; i<S; i++) {
|
||||||
iterator = (iterator + size - 1) % size;
|
iterator = (iterator + S - 1) % S;
|
||||||
if (typeid(T) == typeid(int)) {
|
if (typeid(T) == typeid(int)) {
|
||||||
//DEBUG_INFO("buf[%2zu]=%2d", iterator, (int)*(buf + iterator));
|
//DEBUG_INFO("buf[%2zu]=%2d", iterator, (int)*(buf + iterator));
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,10 +267,10 @@ public:
|
||||||
|
|
||||||
static inline float normalize(float value, int64_t bigMin, int64_t bigMax, int32_t targetMin, int32_t targetMax)
|
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 bigSpan = bigMax - bigMin;
|
||||||
int64_t smallSpan = targetMax - targetMin;
|
int64_t smallSpan = targetMax - targetMin;
|
||||||
float valueScaled = (value - (float)bigMin) / (float)bigSpan;
|
float valueScaled = (value - (float)bigMin) / (float)bigSpan;
|
||||||
return (float)targetMin + valueScaled * (float)smallSpan;
|
return (float)targetMin + valueScaled * (float)smallSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue