/* ZNetBandwidthMeter.cpp Author: Patrick Baggett Created: 7/10/2013 Purpose: ** NOT PART OF PUBLIC SDK ** This class is not part of the public SDK; its fields and methods are not present in the documentation and cannot be guaranteed in future revisions. ** NOT PART OF PUBLIC SDK ** Bandwidth metering using a simple token bucket algorithm. A single value is metered, so a incoming / outgoing each need an instance. License: Copyright 2013, 762 Studios */ #include /*************************************************************************/ void ZNetBandwidthMeter::SetLimit(uint32_t newLimit) { limit = newLimit; //Clamp existing token bucket if(tokens > newLimit) tokens = newLimit; } /*************************************************************************/ void ZNetBandwidthMeter::Reset(uint64_t newStartTime) { lastTime = newStartTime; tokens = limit; } /*************************************************************************/ bool ZNetBandwidthMeter::TryAllocate(uint32_t bytes) { if(bytes <= tokens) { tokens -= bytes; return true; } //Not enough return false; } /*************************************************************************/ void ZNetBandwidthMeter::Update(uint64_t newTime) { //Sanity check -- the time _did_ monotonically increase, right? if(newTime > lastTime) { uint32_t delta = (uint32_t)(newTime - lastTime); //If less than a second has passed... if(delta < 1000) { //We could do: delta / 1000.0 * limit, but that involves int -> float conversions //instead we do u32 x u32 = u64 multiply and divide by 1000, keeping it all in fixed //point happiness. Because delta < 1000, dividing by 1000 should put it back in the //range of a u32. uint32_t amount = (uint64_t)delta * (uint64_t)limit / 1000; //Add newly generated tokens, but clamp to the limit. tokens += amount; if(tokens > limit) tokens = limit; } else //More than a second, so restore all tokens tokens = limit; //Save this as the new time lastTime = newTime; } }