summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/config/config.c2
-rw-r--r--src/core/or/circuituse.c12
-rw-r--r--src/feature/hs/hs_circuit.c31
-rw-r--r--src/feature/hs/hs_circuit.h1
-rw-r--r--src/feature/hs/hs_descriptor.c1
-rw-r--r--src/feature/rend/rendclient.c13
-rw-r--r--src/feature/rend/rendcommon.c11
-rw-r--r--src/feature/rend/rendcommon.h2
-rw-r--r--src/lib/evloop/token_bucket.c52
-rw-r--r--src/lib/evloop/token_bucket.h29
-rw-r--r--src/test/include.am2
-rw-r--r--src/test/test.c2
-rw-r--r--src/test/test.h2
-rw-r--r--src/test/test_config.c12
-rw-r--r--src/test/test_hs_circ.c70
-rw-r--r--src/test/test_rebind.py7
-rwxr-xr-xsrc/test/test_rebind.sh6
-rw-r--r--src/test/test_token_bucket.c152
-rw-r--r--src/win32/orconfig.h2
19 files changed, 271 insertions, 138 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 4cbe81026c..a061871748 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -7091,7 +7091,7 @@ parse_port_config(smartlist_t *out,
if (!strcasecmpstart(elt, "SessionGroup=")) {
int group = (int)tor_parse_long(elt+strlen("SessionGroup="),
10, 0, INT_MAX, &ok, NULL);
- if (!ok || !allow_no_stream_options) {
+ if (!ok || allow_no_stream_options) {
log_warn(LD_CONFIG, "Invalid %sPort option '%s'",
portname, escaped(elt));
goto err;
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index b3d5c6bb81..18b419e99d 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -3068,12 +3068,6 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
if (circ->purpose == new_purpose) return;
- /* Take specific actions if we are repurposing a hidden service circuit. */
- if (circuit_purpose_is_hidden_service(circ->purpose) &&
- !circuit_purpose_is_hidden_service(new_purpose)) {
- hs_circ_repurpose(circ);
- }
-
if (CIRCUIT_IS_ORIGIN(circ)) {
char old_purpose_desc[80] = "";
@@ -3088,6 +3082,12 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
circ->purpose,
circuit_purpose_to_string(new_purpose),
new_purpose);
+
+ /* Take specific actions if we are repurposing a hidden service circuit. */
+ if (circuit_purpose_is_hidden_service(circ->purpose) &&
+ !circuit_purpose_is_hidden_service(new_purpose)) {
+ hs_circ_cleanup(circ);
+ }
}
old_purpose = circ->purpose;
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index 79377eb731..a6e86c5ab3 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -25,7 +25,6 @@
#include "feature/nodelist/describe.h"
#include "feature/nodelist/nodelist.h"
#include "feature/rend/rendservice.h"
-#include "feature/rend/rendcommon.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -1193,33 +1192,3 @@ hs_circ_cleanup(circuit_t *circ)
hs_circuitmap_remove_circuit(circ);
}
}
-
-/* The given circuit will be repurposed so take the appropriate actions. A
- * cleanup from the HS maps and of all HS related structures is done.
- *
- * Once this function returns, the circuit can be safely repurposed. */
-void
-hs_circ_repurpose(circuit_t *circ)
-{
- origin_circuit_t *origin_circ;
-
- tor_assert(circ);
-
- /* Only repurposing an origin circuit is possible for HS. */
- if (!CIRCUIT_IS_ORIGIN(circ)) {
- return;
- }
- origin_circ = TO_ORIGIN_CIRCUIT(circ);
-
- /* First, cleanup the circuit from the HS maps. */
- hs_circ_cleanup(circ);
-
- /* Depending on the version, different cleanup is done. */
- if (origin_circ->rend_data) {
- /* v2. */
- rend_circ_cleanup(origin_circ);
- } else if (origin_circ->hs_ident) {
- /* v3. */
- hs_ident_circuit_free(origin_circ->hs_ident);
- }
-}
diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h
index 0786f3ee45..b8d8b25add 100644
--- a/src/feature/hs/hs_circuit.h
+++ b/src/feature/hs/hs_circuit.h
@@ -16,7 +16,6 @@
/* Cleanup function when the circuit is closed or/and freed. */
void hs_circ_cleanup(circuit_t *circ);
-void hs_circ_repurpose(circuit_t *circ);
/* Circuit API. */
int hs_circ_service_intro_has_opened(hs_service_t *service,
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c
index 52dc8690c3..a8796c0029 100644
--- a/src/feature/hs/hs_descriptor.c
+++ b/src/feature/hs/hs_descriptor.c
@@ -1968,6 +1968,7 @@ decode_intro_points(const hs_descriptor_t *desc,
SMARTLIST_FOREACH(intro_points, char *, a, tor_free(a));
smartlist_free(intro_points);
}
+
/* Return 1 iff the given base64 encoded signature in b64_sig from the encoded
* descriptor in encoded_desc validates the descriptor content. */
STATIC int
diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c
index f84d221b1a..5bdd4d453e 100644
--- a/src/feature/rend/rendclient.c
+++ b/src/feature/rend/rendclient.c
@@ -403,14 +403,23 @@ rend_client_introduction_acked(origin_circuit_t *circ,
} else {
log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
}
+ /* Save the rend data digest to a temporary object so that we don't access
+ * it after we mark the circuit for close. */
+ const uint8_t *rend_digest_tmp = NULL;
+ size_t digest_len;
+ uint8_t *cached_rend_digest = NULL;
+ rend_digest_tmp = rend_data_get_pk_digest(circ->rend_data, &digest_len);
+ cached_rend_digest = tor_malloc_zero(digest_len);
+ memcpy(cached_rend_digest, rend_digest_tmp, digest_len);
+
/* close the circuit: we won't need it anymore. */
circuit_change_purpose(TO_CIRCUIT(circ),
CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
/* close any other intros launched in parallel */
- rend_client_close_other_intros(rend_data_get_pk_digest(circ->rend_data,
- NULL));
+ rend_client_close_other_intros(cached_rend_digest);
+ tor_free(cached_rend_digest); /* free the temporary digest */
} else {
/* It's a NAK; the introduction point didn't relay our request. */
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING);
diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c
index 265ee368f1..777de2984c 100644
--- a/src/feature/rend/rendcommon.c
+++ b/src/feature/rend/rendcommon.c
@@ -1046,14 +1046,3 @@ rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc,
match:
return 1;
}
-
-/* Cleanup the given circuit of all HS v2 data structure. */
-void
-rend_circ_cleanup(origin_circuit_t *circ)
-{
- tor_assert(circ);
-
- /* Both fields are set to NULL with these. */
- crypto_pk_free(circ->intro_key);
- rend_data_free(circ->rend_data);
-}
diff --git a/src/feature/rend/rendcommon.h b/src/feature/rend/rendcommon.h
index c9a04846d7..f136863c7a 100644
--- a/src/feature/rend/rendcommon.h
+++ b/src/feature/rend/rendcommon.h
@@ -71,8 +71,6 @@ int rend_non_anonymous_mode_enabled(const or_options_t *options);
void assert_circ_anonymity_ok(const origin_circuit_t *circ,
const or_options_t *options);
-void rend_circ_cleanup(origin_circuit_t *circ);
-
#ifdef RENDCOMMON_PRIVATE
STATIC int
diff --git a/src/lib/evloop/token_bucket.c b/src/lib/evloop/token_bucket.c
index ee6d631e3b..ec62d1b018 100644
--- a/src/lib/evloop/token_bucket.c
+++ b/src/lib/evloop/token_bucket.c
@@ -256,3 +256,55 @@ token_bucket_rw_dec(token_bucket_rw_t *bucket,
flags |= TB_WRITE;
return flags;
}
+
+/** Initialize a token bucket in <b>bucket</b>, set up to allow <b>rate</b>
+ * per second, with a maximum burst of <b>burst</b>. The bucket is created
+ * such that <b>now_ts</b> is the current timestamp. The bucket starts out
+ * full. */
+void
+token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate,
+ uint32_t burst, uint32_t now_ts)
+{
+ memset(bucket, 0, sizeof(token_bucket_ctr_t));
+ token_bucket_ctr_adjust(bucket, rate, burst);
+ token_bucket_ctr_reset(bucket, now_ts);
+}
+
+/** Change the configured rate and burst of the given token bucket object in
+ * <b>bucket</b>. */
+void
+token_bucket_ctr_adjust(token_bucket_ctr_t *bucket, uint32_t rate,
+ uint32_t burst)
+{
+ token_bucket_cfg_init(&bucket->cfg, rate, burst);
+ token_bucket_raw_adjust(&bucket->counter, &bucket->cfg);
+}
+
+/** Reset <b>bucket</b> to be full, as of timestamp <b>now_ts</b>. */
+void
+token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts)
+{
+ token_bucket_raw_reset(&bucket->counter, &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>. */
+void
+token_bucket_ctr_refill(token_bucket_ctr_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;
+ }
+
+ token_bucket_raw_refill_steps(&bucket->counter, &bucket->cfg,
+ elapsed_ticks);
+ bucket->last_refilled_at_timestamp = now_ts;
+}
diff --git a/src/lib/evloop/token_bucket.h b/src/lib/evloop/token_bucket.h
index 1ce6f1bf94..dde9bd65a4 100644
--- a/src/lib/evloop/token_bucket.h
+++ b/src/lib/evloop/token_bucket.h
@@ -103,6 +103,35 @@ token_bucket_rw_get_write(const token_bucket_rw_t *bucket)
return token_bucket_raw_get(&bucket->write_bucket);
}
+/**
+ * A specialized bucket containing a single counter.
+ */
+
+typedef struct token_bucket_ctr_t {
+ token_bucket_cfg_t cfg;
+ token_bucket_raw_t counter;
+ uint32_t last_refilled_at_timestamp;
+} token_bucket_ctr_t;
+
+void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate,
+ uint32_t burst, uint32_t now_ts);
+void token_bucket_ctr_adjust(token_bucket_ctr_t *bucket, uint32_t rate,
+ uint32_t burst);
+void token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts);
+void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts);
+
+static inline bool
+token_bucket_ctr_dec(token_bucket_ctr_t *bucket, ssize_t n)
+{
+ return token_bucket_raw_dec(&bucket->counter, n);
+}
+
+static inline size_t
+token_bucket_ctr_get(const token_bucket_ctr_t *bucket)
+{
+ return token_bucket_raw_get(&bucket->counter);
+}
+
#ifdef TOKEN_BUCKET_PRIVATE
/* To avoid making the rates too small, we consider units of "steps",
diff --git a/src/test/include.am b/src/test/include.am
index fdfe96c559..624bca66d9 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -145,7 +145,6 @@ src_test_test_SOURCES += \
src/test/test_hs_common.c \
src/test/test_hs_config.c \
src/test/test_hs_cell.c \
- src/test/test_hs_circ.c \
src/test/test_hs_ntor.c \
src/test/test_hs_service.c \
src/test/test_hs_client.c \
@@ -194,6 +193,7 @@ src_test_test_SOURCES += \
src/test/test_status.c \
src/test/test_storagedir.c \
src/test/test_threads.c \
+ src/test/test_token_bucket.c \
src/test/test_tortls.c \
src/test/test_util.c \
src/test/test_util_format.c \
diff --git a/src/test/test.c b/src/test/test.c
index d7682b6619..cc08531702 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -871,7 +871,6 @@ struct testgroup_t testgroups[] = {
{ "guardfraction/", guardfraction_tests },
{ "hs_cache/", hs_cache },
{ "hs_cell/", hs_cell_tests },
- { "hs_circ/", hs_circ_tests },
{ "hs_client/", hs_client_tests },
{ "hs_common/", hs_common_tests },
{ "hs_config/", hs_config_tests },
@@ -917,6 +916,7 @@ struct testgroup_t testgroups[] = {
{ "socks/", socks_tests },
{ "status/" , status_tests },
{ "storagedir/", storagedir_tests },
+ { "token_bucket/", token_bucket_tests },
{ "tortls/", tortls_tests },
#ifndef ENABLE_NSS
{ "tortls/openssl/", tortls_openssl_tests },
diff --git a/src/test/test.h b/src/test/test.h
index b108d795ea..85e8b07ff7 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -221,7 +221,6 @@ extern struct testcase_t guardfraction_tests[];
extern struct testcase_t handle_tests[];
extern struct testcase_t hs_cache[];
extern struct testcase_t hs_cell_tests[];
-extern struct testcase_t hs_circ_tests[];
extern struct testcase_t hs_client_tests[];
extern struct testcase_t hs_common_tests[];
extern struct testcase_t hs_config_tests[];
@@ -273,6 +272,7 @@ extern struct testcase_t sr_tests[];
extern struct testcase_t status_tests[];
extern struct testcase_t storagedir_tests[];
extern struct testcase_t thread_tests[];
+extern struct testcase_t token_bucket_tests[];
extern struct testcase_t tortls_openssl_tests[];
extern struct testcase_t tortls_tests[];
extern struct testcase_t util_format_tests[];
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 12b78f806a..a415ca4480 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -4569,16 +4569,14 @@ test_config_parse_port_config__ports__ports_given(void *data)
"127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
- // TODO: this seems wrong. Shouldn't it be the other way around?
- // Potential bug.
- // Test failure for a SessionGroup argument with valid value but with stream
- // options allowed
+ // Test failure for a SessionGroup argument with valid value but with no
+ // stream options allowed
config_free_lines(config_port_invalid); config_port_invalid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123");
ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
- "127.0.0.44", 0, 0);
+ "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
// Test failure for more than one SessionGroup argument
@@ -4588,7 +4586,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123 "
"SessionGroup=321");
ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
- "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
+ "127.0.0.44", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test success with a sessiongroup options
@@ -4597,7 +4595,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 SessionGroup=1111122");
ret = parse_port_config(slout, config_port_valid, "DNS", 0,
- "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
+ "127.0.0.44", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
diff --git a/src/test/test_hs_circ.c b/src/test/test_hs_circ.c
deleted file mode 100644
index af28af2573..0000000000
--- a/src/test/test_hs_circ.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file test_hs_circ.c
- * \brief Test hidden service circuit functionality.
- */
-
-#define CIRCUITLIST_PRIVATE
-
-#include "test/test.h"
-#include "test/test_helpers.h"
-#include "test/log_test_helpers.h"
-
-#include "core/or/circuitbuild.h"
-#include "core/or/circuitlist.h"
-#include "core/or/circuituse.h"
-#include "core/or/origin_circuit_st.h"
-
-#include "feature/hs/hs_circuit.h"
-#include "feature/hs/hs_circuitmap.h"
-
-static void
-test_circuit_repurpose(void *arg)
-{
- origin_circuit_t *intro_circ = NULL;
- const origin_circuit_t *search;
- ed25519_keypair_t kp;
-
- (void) arg;
-
- hs_init();
-
- intro_circ = origin_circuit_init(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, 0);
- tt_assert(intro_circ);
- ed25519_keypair_generate(&kp, 0);
-
- /* Register circuit in global map and make sure it is actually there. */
- hs_circuitmap_register_intro_circ_v3_service_side(intro_circ,
- &kp.pubkey);
- tt_assert(TO_CIRCUIT(intro_circ)->hs_token);
- search = hs_circuitmap_get_intro_circ_v3_service_side(&kp.pubkey);
- tt_mem_op(search, OP_EQ, intro_circ, sizeof(origin_circuit_t));
-
- /* Setup circuit HS ident. We don't care about the service pubkey. */
- intro_circ->hs_ident = hs_ident_circuit_new(&kp.pubkey,
- HS_IDENT_CIRCUIT_INTRO);
- tt_assert(intro_circ->hs_ident);
-
- /* Trigger a repurpose. State should be cleaned up. */
- hs_circ_repurpose(TO_CIRCUIT(intro_circ));
-
- /* Removed from map. */
- search = hs_circuitmap_get_intro_circ_v3_service_side(&kp.pubkey);
- tt_assert(!search);
- /* HS identifier has been removed. */
- tt_assert(!intro_circ->hs_ident);
-
- done:
- circuit_free_(TO_CIRCUIT(intro_circ));
- hs_free_all();
-}
-
-struct testcase_t hs_circ_tests[] = {
- { "repurpose", test_circuit_repurpose, TT_FORK,
- NULL, NULL },
-
- END_OF_TESTCASES
-};
-
diff --git a/src/test/test_rebind.py b/src/test/test_rebind.py
index 7b12626a91..232b200326 100644
--- a/src/test/test_rebind.py
+++ b/src/test/test_rebind.py
@@ -16,6 +16,10 @@ def fail(msg):
logging.error('FAIL')
sys.exit(msg)
+def skip(msg):
+ logging.warning('SKIP: {}'.format(msg))
+ sys.exit(77)
+
def try_connecting_to_socksport():
socks_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
e = socks_socket.connect_ex(('127.0.0.1', socks_port))
@@ -66,6 +70,9 @@ if sys.hexversion < 0x02070000:
if sys.hexversion > 0x03000000 and sys.hexversion < 0x03010000:
fail("ERROR: unsupported Python3 version (should be >= 3.1)")
+if 'TOR_SKIP_TEST_REBIND' in os.environ:
+ skip('$TOR_SKIP_TEST_REBIND is set')
+
control_port = pick_random_port()
socks_port = pick_random_port()
diff --git a/src/test/test_rebind.sh b/src/test/test_rebind.sh
index a8f07c7c1e..e0d8394d38 100755
--- a/src/test/test_rebind.sh
+++ b/src/test/test_rebind.sh
@@ -7,7 +7,7 @@ if test "$UNAME_OS" = 'CYGWIN' || \
test "$UNAME_OS" = 'MSYS' || \
test "$UNAME_OS" = 'MINGW'; then
if test "$APPVEYOR" = 'True'; then
- echo "This test is disabled on Windows CI, as it requires firewall examptions. Skipping." >&2
+ echo "This test is disabled on Windows CI, as it requires firewall exemptions. Skipping." >&2
exit 77
fi
fi
@@ -32,6 +32,6 @@ elif [ ! -d "$tmpdir" ]; then
exit 3
fi
-"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/test_rebind.py" "${TESTING_TOR_BINARY}" "$tmpdir" || exitcode=1
+"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/test_rebind.py" "${TESTING_TOR_BINARY}" "$tmpdir"
-exit ${exitcode}
+exit $?
diff --git a/src/test/test_token_bucket.c b/src/test/test_token_bucket.c
new file mode 100644
index 0000000000..d3ce591388
--- /dev/null
+++ b/src/test/test_token_bucket.c
@@ -0,0 +1,152 @@
+/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_bwmgt.c
+ * \brief tests for bandwidth management / token bucket functions
+ */
+
+#define TOKEN_BUCKET_PRIVATE
+
+#include "core/or/or.h"
+#include "test/test.h"
+
+#include "lib/evloop/token_bucket.h"
+
+// an imaginary time, in timestamp units. Chosen so it will roll over.
+static const uint32_t START_TS = UINT32_MAX - 1000;
+static const uint32_t RATE = 10;
+static const uint32_t BURST = 50;
+
+static void
+test_token_bucket_ctr_init(void *arg)
+{
+ (void) arg;
+ token_bucket_ctr_t tb;
+
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST);
+ tt_uint_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS);
+ tt_int_op(tb.counter.bucket, OP_EQ, BURST);
+
+ done:
+ ;
+}
+
+static void
+test_token_bucket_ctr_adjust(void *arg)
+{
+ (void) arg;
+ token_bucket_ctr_t tb;
+
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+
+ /* Increase burst. */
+ token_bucket_ctr_adjust(&tb, RATE, BURST * 2);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST * 2);
+
+ /* Decrease burst but still above bucket value. */
+ token_bucket_ctr_adjust(&tb, RATE, BURST + 10);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST + 10);
+
+ /* Decrease burst below bucket value. */
+ token_bucket_ctr_adjust(&tb, RATE, BURST - 1);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST - 1);
+
+ /* Change rate. */
+ token_bucket_ctr_adjust(&tb, RATE * 2, BURST);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE * 2);
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST);
+
+ done:
+ ;
+}
+
+static void
+test_token_bucket_ctr_dec(void *arg)
+{
+ (void) arg;
+ token_bucket_ctr_t tb;
+
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+
+ /* Simple decrement by one. */
+ tt_uint_op(0, OP_EQ, token_bucket_ctr_dec(&tb, 1));
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
+
+ /* Down to 0. Becomes empty. */
+ tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST - 1));
+ tt_uint_op(tb.counter.bucket, OP_EQ, 0);
+
+ /* Reset and try to underflow. */
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+ tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST + 1));
+ tt_int_op(tb.counter.bucket, OP_EQ, -1);
+
+ /* Keep underflowing shouldn't flag the bucket as empty. */
+ tt_uint_op(false, OP_EQ, token_bucket_ctr_dec(&tb, BURST));
+ tt_int_op(tb.counter.bucket, OP_EQ, (int32_t) ((BURST + 1) * -1));
+
+ done:
+ ;
+}
+
+static void
+test_token_bucket_ctr_refill(void *arg)
+{
+ (void) arg;
+ token_bucket_ctr_t tb;
+
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+
+ /* Reduce of half the bucket and let a single second go before refill. */
+ token_bucket_ctr_dec(&tb, BURST / 2);
+ tt_int_op(tb.counter.bucket, OP_EQ, BURST / 2);
+ token_bucket_ctr_refill(&tb, START_TS + 1);
+ tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 1);
+
+ /* No time change, nothing should move. */
+ token_bucket_ctr_refill(&tb, START_TS + 1);
+ tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 1);
+
+ /* Add 99 seconds, bucket should be back to a full BURST. */
+ token_bucket_ctr_refill(&tb, START_TS + 99);
+ tt_int_op(tb.counter.bucket, OP_EQ, BURST);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 99);
+
+ /* Empty bucket at once. */
+ token_bucket_ctr_dec(&tb, BURST);
+ tt_int_op(tb.counter.bucket, OP_EQ, 0);
+ /* On second passes. */
+ token_bucket_ctr_refill(&tb, START_TS + 100);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 100);
+ tt_int_op(tb.counter.bucket, OP_EQ, RATE);
+ /* A second second passes. */
+ token_bucket_ctr_refill(&tb, START_TS + 101);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 101);
+ tt_int_op(tb.counter.bucket, OP_EQ, RATE * 2);
+
+ done:
+ ;
+}
+
+#define TOKEN_BUCKET(name) \
+ { #name, test_token_bucket_ ## name , 0, NULL, NULL }
+
+struct testcase_t token_bucket_tests[] = {
+ TOKEN_BUCKET(ctr_init),
+ TOKEN_BUCKET(ctr_adjust),
+ TOKEN_BUCKET(ctr_dec),
+ TOKEN_BUCKET(ctr_refill),
+ END_OF_TESTCASES
+};
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index a3daa98de0..25bfb9ada5 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -218,7 +218,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.4.1.2-alpha"
+#define VERSION "0.4.2.0-alpha-dev"