aboutsummaryrefslogtreecommitdiff
path: root/src/common/token_bucket.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-07-05 15:13:44 -0400
committerNick Mathewson <nickm@torproject.org>2018-07-05 15:22:17 -0400
commit1e417b7275028a50227f57fb71d04c1837ec4b2c (patch)
tree3cbf379caf8367391980abf3a562b20eb4d63052 /src/common/token_bucket.c
parent947de40d198d83e561320afe5d0146f43dc9192a (diff)
downloadtor-1e417b7275028a50227f57fb71d04c1837ec4b2c.tar.gz
tor-1e417b7275028a50227f57fb71d04c1837ec4b2c.zip
All remaining files in src/common belong to the event loop.
Diffstat (limited to 'src/common/token_bucket.c')
-rw-r--r--src/common/token_bucket.c258
1 files changed, 0 insertions, 258 deletions
diff --git a/src/common/token_bucket.c b/src/common/token_bucket.c
deleted file mode 100644
index f7b092f612..0000000000
--- a/src/common/token_bucket.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/* Copyright (c) 2018-2018, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file token_bucket.c
- * \brief Functions to use and manipulate token buckets, used for
- * rate-limiting on connections and globally.
- *
- * Tor uses these token buckets to keep track of bandwidth usage, and
- * sometimes other things too.
- *
- * There are two layers of abstraction here: "raw" token buckets, in which all
- * the pieces are decoupled, and "read-write" token buckets, which combine all
- * the moving parts into one.
- *
- * Token buckets may become negative.
- **/
-
-#define TOKEN_BUCKET_PRIVATE
-
-#include "common/token_bucket.h"
-#include "lib/log/util_bug.h"
-#include "lib/intmath/cmp.h"
-#include "lib/time/compat_time.h"
-
-#include <string.h>
-
-/**
- * Set the <b>rate</b> and <b>burst</b> value in a token_bucket_cfg.
- *
- * Note that the <b>rate</b> value is in arbitrary units, but those units will
- * determine the units of token_bucket_raw_dec(), token_bucket_raw_refill, and
- * so on.
- */
-void
-token_bucket_cfg_init(token_bucket_cfg_t *cfg,
- uint32_t rate,
- uint32_t burst)
-{
- tor_assert_nonfatal(rate > 0);
- tor_assert_nonfatal(burst > 0);
- if (burst > TOKEN_BUCKET_MAX_BURST)
- burst = TOKEN_BUCKET_MAX_BURST;
-
- cfg->rate = rate;
- cfg->burst = burst;
-}
-
-/**
- * Initialize a raw token bucket and its associated timestamp to the "full"
- * state, according to <b>cfg</b>.
- */
-void
-token_bucket_raw_reset(token_bucket_raw_t *bucket,
- const token_bucket_cfg_t *cfg)
-{
- bucket->bucket = cfg->burst;
-}
-
-/**
- * Adust a preexisting token bucket to respect the new configuration
- * <b>cfg</b>, by decreasing its current level if needed. */
-void
-token_bucket_raw_adjust(token_bucket_raw_t *bucket,
- const token_bucket_cfg_t *cfg)
-{
- bucket->bucket = MIN(bucket->bucket, cfg->burst);
-}
-
-/**
- * Given an amount of <b>elapsed</b> time units, and a bucket configuration
- * <b>cfg</b>, refill the level of <b>bucket</b> accordingly. Note that the
- * units of time in <b>elapsed</b> must correspond to those used to set the
- * rate in <b>cfg</b>, or the result will be illogical.
- */
-int
-token_bucket_raw_refill_steps(token_bucket_raw_t *bucket,
- const token_bucket_cfg_t *cfg,
- const uint32_t elapsed)
-{
- const int was_empty = (bucket->bucket <= 0);
- /* The casts here prevent an underflow.
- *
- * Note that even if the bucket value is negative, subtracting it from
- * "burst" will still produce a correct result. If this result is
- * ridiculously high, then the "elapsed > gap / rate" check below
- * should catch it. */
- const size_t gap = ((size_t)cfg->burst) - ((size_t)bucket->bucket);
-
- if (elapsed > gap / cfg->rate) {
- bucket->bucket = cfg->burst;
- } else {
- bucket->bucket += cfg->rate * elapsed;
- }
-
- return was_empty && bucket->bucket > 0;
-}
-
-/**
- * Decrement a provided bucket by <b>n</b> units. Note that <b>n</b>
- * must be nonnegative.
- */
-int
-token_bucket_raw_dec(token_bucket_raw_t *bucket,
- ssize_t n)
-{
- if (BUG(n < 0))
- return 0;
- const int becomes_empty = bucket->bucket > 0 && n >= bucket->bucket;
- bucket->bucket -= n;
- return becomes_empty;
-}
-
-/** Convert a rate in bytes per second to a rate in bytes per step */
-STATIC uint32_t
-rate_per_sec_to_rate_per_step(uint32_t rate)
-{
- /*
- The precise calculation we'd want to do is
-
- (rate / 1000) * to_approximate_msec(TICKS_PER_STEP). But to minimize
- rounding error, we do it this way instead, and divide last.
- */
- uint64_t units = (uint64_t) rate * TICKS_PER_STEP;
- uint32_t val = (uint32_t)
- (monotime_coarse_stamp_units_to_approx_msec(units) / 1000);
- return val ? val : 1;
-}
-
-/**
- * Initialize a token bucket in *<b>bucket</b>, set up to allow <b>rate</b>
- * bytes per second, with a maximum burst of <b>burst</b> bytes. The bucket
- * is created such that <b>now_ts</b> is the current timestamp. The bucket
- * starts out full.
- */
-void
-token_bucket_rw_init(token_bucket_rw_t *bucket,
- uint32_t rate,
- uint32_t burst,
- uint32_t now_ts)
-{
- memset(bucket, 0, sizeof(token_bucket_rw_t));
- token_bucket_rw_adjust(bucket, rate, burst);
- token_bucket_rw_reset(bucket, now_ts);
-}
-
-/**
- * Change the configured rate (in bytes per second) and burst (in bytes)
- * for the token bucket in *<b>bucket</b>.
- */
-void
-token_bucket_rw_adjust(token_bucket_rw_t *bucket,
- uint32_t rate,
- uint32_t burst)
-{
- token_bucket_cfg_init(&bucket->cfg,
- rate_per_sec_to_rate_per_step(rate),
- burst);
- token_bucket_raw_adjust(&bucket->read_bucket, &bucket->cfg);
- token_bucket_raw_adjust(&bucket->write_bucket, &bucket->cfg);
-}
-
-/**
- * Reset <b>bucket</b> to be full, as of timestamp <b>now_ts</b>.
- */
-void
-token_bucket_rw_reset(token_bucket_rw_t *bucket,
- uint32_t now_ts)
-{
- token_bucket_raw_reset(&bucket->read_bucket, &bucket->cfg);
- token_bucket_raw_reset(&bucket->write_bucket, &bucket->cfg);
- bucket->last_refilled_at_timestamp = now_ts;
-}
-
-/**
- * Refill <b>bucket</b> as appropriate, given that the current timestamp
- * is <b>now_ts</b>.
- *
- * Return a bitmask containing TB_READ iff read bucket was empty and became
- * nonempty, and TB_WRITE iff the write bucket was empty and became nonempty.
- */
-int
-token_bucket_rw_refill(token_bucket_rw_t *bucket,
- uint32_t now_ts)
-{
- const uint32_t elapsed_ticks =
- (now_ts - bucket->last_refilled_at_timestamp);
- if (elapsed_ticks > UINT32_MAX-(300*1000)) {
- /* Either about 48 days have passed since the last refill, or the
- * monotonic clock has somehow moved backwards. (We're looking at you,
- * Windows.). We accept up to a 5 minute jump backwards as
- * "unremarkable".
- */
- return 0;
- }
- const uint32_t elapsed_steps = elapsed_ticks / TICKS_PER_STEP;
-
- if (!elapsed_steps) {
- /* Note that if less than one whole step elapsed, we don't advance the
- * time in last_refilled_at. That's intentional: we want to make sure
- * that we add some bytes to it eventually. */
- return 0;
- }
-
- int flags = 0;
- if (token_bucket_raw_refill_steps(&bucket->read_bucket,
- &bucket->cfg, elapsed_steps))
- flags |= TB_READ;
- if (token_bucket_raw_refill_steps(&bucket->write_bucket,
- &bucket->cfg, elapsed_steps))
- flags |= TB_WRITE;
-
- bucket->last_refilled_at_timestamp = now_ts;
- return flags;
-}
-
-/**
- * Decrement the read token bucket in <b>bucket</b> by <b>n</b> bytes.
- *
- * Return true if the bucket was nonempty and became empty; return false
- * otherwise.
- */
-int
-token_bucket_rw_dec_read(token_bucket_rw_t *bucket,
- ssize_t n)
-{
- return token_bucket_raw_dec(&bucket->read_bucket, n);
-}
-
-/**
- * Decrement the write token bucket in <b>bucket</b> by <b>n</b> bytes.
- *
- * Return true if the bucket was nonempty and became empty; return false
- * otherwise.
- */
-int
-token_bucket_rw_dec_write(token_bucket_rw_t *bucket,
- ssize_t n)
-{
- return token_bucket_raw_dec(&bucket->write_bucket, n);
-}
-
-/**
- * As token_bucket_rw_dec_read and token_bucket_rw_dec_write, in a single
- * operation. Return a bitmask of TB_READ and TB_WRITE to indicate
- * which buckets became empty.
- */
-int
-token_bucket_rw_dec(token_bucket_rw_t *bucket,
- ssize_t n_read, ssize_t n_written)
-{
- int flags = 0;
- if (token_bucket_rw_dec_read(bucket, n_read))
- flags |= TB_READ;
- if (token_bucket_rw_dec_write(bucket, n_written))
- flags |= TB_WRITE;
- return flags;
-}