diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app/config/config.c | 2 | ||||
-rw-r--r-- | src/core/or/circuituse.c | 12 | ||||
-rw-r--r-- | src/feature/hs/hs_circuit.c | 31 | ||||
-rw-r--r-- | src/feature/hs/hs_circuit.h | 1 | ||||
-rw-r--r-- | src/feature/hs/hs_descriptor.c | 1 | ||||
-rw-r--r-- | src/feature/rend/rendclient.c | 13 | ||||
-rw-r--r-- | src/feature/rend/rendcommon.c | 11 | ||||
-rw-r--r-- | src/feature/rend/rendcommon.h | 2 | ||||
-rw-r--r-- | src/lib/evloop/token_bucket.c | 52 | ||||
-rw-r--r-- | src/lib/evloop/token_bucket.h | 29 | ||||
-rw-r--r-- | src/test/include.am | 2 | ||||
-rw-r--r-- | src/test/test.c | 2 | ||||
-rw-r--r-- | src/test/test.h | 2 | ||||
-rw-r--r-- | src/test/test_config.c | 12 | ||||
-rw-r--r-- | src/test/test_hs_circ.c | 70 | ||||
-rw-r--r-- | src/test/test_rebind.py | 7 | ||||
-rwxr-xr-x | src/test/test_rebind.sh | 6 | ||||
-rw-r--r-- | src/test/test_token_bucket.c | 152 | ||||
-rw-r--r-- | src/win32/orconfig.h | 2 |
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" |