tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

commit 69a320ce5d84308c8749e9311ad6888d5aae5d3b
parent d43dc120e88a61911b1bd06dc67f7da8de971a03
Author: Nick Mathewson <nickm@torproject.org>
Date:   Wed, 20 Dec 2017 09:15:30 -0500

Merge branch 'xfer_time_coarse'

Diffstat:
Achanges/bug24613 | 4++++
Msrc/common/compat_time.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/common/compat_time.h | 22++++++++++++++++++++++
Msrc/or/channel.c | 12++++++------
Msrc/or/channel.h | 11+++++------
Msrc/or/channelpadding.c | 54+++++++++++++++++++++++++++++-------------------------
Msrc/test/test_channel.c | 6+++---
Msrc/test/test_channelpadding.c | 112++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/test/test_util.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 292 insertions(+), 81 deletions(-)

diff --git a/changes/bug24613 b/changes/bug24613 @@ -0,0 +1,4 @@ + o Minor features (performance, 32-bit): + - Improve performance on 32-bit systems by avoiding 64-bit division + to calculate the current timestamp in milliseconds for channel + padding computations. Implements ticket 24613. diff --git a/src/common/compat_time.c b/src/common/compat_time.c @@ -351,6 +351,20 @@ monotime_coarse_to_stamp(const monotime_coarse_t *t) return (uint32_t)(t->abstime_ >> monotime_shift); } +int +monotime_is_zero(const monotime_t *val) +{ + return val->abstime_ == 0; +} + +void +monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) +{ + const uint64_t nsec = msec * ONE_MILLION; + const uint64_t ticks = (nsec * mach_time_info.denom) / mach_time_info.numer; + out->abstime_ = val->abstime_ + ticks; +} + /* end of "__APPLE__" */ #elif defined(HAVE_CLOCK_GETTIME) @@ -441,6 +455,25 @@ monotime_coarse_to_stamp(const monotime_coarse_t *t) return (sec * STAMP_TICKS_PER_SECOND) + (nsec >> 20); } +int +monotime_is_zero(const monotime_t *val) +{ + return val->ts_.tv_sec == 0 && val->ts_.tv_nsec == 0; +} + +void +monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) +{ + const uint32_t sec = msec / 1000; + const uint32_t msec_remainder = msec % 1000; + out->ts_.tv_sec = val->ts_.tv_sec + sec; + out->ts_.tv_nsec = val->ts_.tv_nsec + (msec_remainder * ONE_MILLION); + if (out->ts_.tv_nsec > ONE_BILLION) { + out->ts_.tv_nsec -= ONE_BILLION; + out->ts_.tv_sec += 1; + } +} + /* end of "HAVE_CLOCK_GETTIME" */ #elif defined (_WIN32) @@ -581,6 +614,32 @@ monotime_coarse_to_stamp(const monotime_coarse_t *t) return (uint32_t) t->tick_count_; } +int +monotime_is_zero(const monotime_t *val) +{ + return val->pcount_ == 0; +} + +int +monotime_coarse_is_zero(const monotime_coarse_t *val) +{ + return val->tick_count_ == 0; +} + +void +monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) +{ + const uint64_t nsec = msec * ONE_MILLION; + const uint64_t ticks = (nsec * nsec_per_tick_denom) / nsec_per_tick_numer; + out->pcount_ = val->pcount_ + ticks; +} + +void +monotime_coarse_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) +{ + out->tick_count_ = val->tick_count_ + msec; +} + /* end of "_WIN32" */ #elif defined(MONOTIME_USING_GETTIMEOFDAY) @@ -628,6 +687,25 @@ monotime_coarse_to_stamp(const monotime_coarse_t *t) return (sec * STAMP_TICKS_PER_SECOND) | (nsec >> 10); } +int +monotime_is_zero(const monotime_t *val) +{ + return val->tv_.tv_sec == 0 && val->tv_.tv_usec == 0; +} + +void +monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) +{ + const uint32_t sec = msec / 1000; + const uint32_t msec_remainder = msec % 1000; + out->tv_.tv_sec = val->tv_.tv_sec + sec; + out->tv_.tv_usec = val->tv_.tv_nsec + (msec_remainder * 1000); + if (out->tv_.tv_usec > ONE_MILLION) { + out->tv_.tv_usec -= ONE_MILLION; + out->tv_.tv_sec += 1; + } +} + /* end of "MONOTIME_USING_GETTIMEOFDAY" */ #else #error "No way to implement monotonic timers." @@ -650,6 +728,19 @@ monotime_init(void) } } +void +monotime_zero(monotime_t *out) +{ + memset(out, 0, sizeof(*out)); +} +#ifdef MONOTIME_COARSE_TYPE_IS_DIFFERENT +void +monotime_coarse_zero(monotime_coarse_t *out) +{ + memset(out, 0, sizeof(*out)); +} +#endif + int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end) diff --git a/src/common/compat_time.h b/src/common/compat_time.h @@ -105,6 +105,21 @@ uint64_t monotime_absolute_usec(void); */ uint64_t monotime_absolute_msec(void); +/** + * Set <b>out</b> to zero. + */ +void monotime_zero(monotime_t *out); +/** + * Return true iff <b>out</b> is zero + */ +int monotime_is_zero(const monotime_t *out); + +/** + * Set <b>out</b> to N milliseconds after <b>val</b>. + */ +/* XXXX We should add a more generic function here if we ever need to */ +void monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec); + #if defined(MONOTIME_COARSE_FN_IS_DIFFERENT) /** * Set <b>out</b> to the current coarse time. @@ -144,10 +159,17 @@ int64_t monotime_coarse_diff_usec(const monotime_coarse_t *start, const monotime_coarse_t *end); int64_t monotime_coarse_diff_msec(const monotime_coarse_t *start, const monotime_coarse_t *end); +void monotime_coarse_zero(monotime_coarse_t *out); +int monotime_coarse_is_zero(const monotime_coarse_t *val); +void monotime_coarse_add_msec(monotime_coarse_t *out, + const monotime_coarse_t *val, uint32_t msec); #else /* !(defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)) */ #define monotime_coarse_diff_nsec monotime_diff_nsec #define monotime_coarse_diff_usec monotime_diff_usec #define monotime_coarse_diff_msec monotime_diff_msec +#define monotime_coarse_zero monotime_zero +#define monotime_coarse_is_zero monotime_is_zero +#define monotime_coarse_add_msec monotime_add_msec #endif /* defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) */ void tor_gettimeofday(struct timeval *timeval); diff --git a/src/or/channel.c b/src/or/channel.c @@ -3241,12 +3241,12 @@ channel_timestamp_active(channel_t *chan) time_t now = time(NULL); tor_assert(chan); - chan->timestamp_xfer_ms = monotime_coarse_absolute_msec(); + monotime_coarse_get(&chan->timestamp_xfer); chan->timestamp_active = now; /* Clear any potential netflow padding timer. We're active */ - chan->next_padding_time_ms = 0; + monotime_coarse_zero(&chan->next_padding_time); } /** @@ -3311,13 +3311,13 @@ channel_timestamp_recv(channel_t *chan) { time_t now = time(NULL); tor_assert(chan); - chan->timestamp_xfer_ms = monotime_coarse_absolute_msec(); + monotime_coarse_get(&chan->timestamp_xfer); chan->timestamp_active = now; chan->timestamp_recv = now; /* Clear any potential netflow padding timer. We're active */ - chan->next_padding_time_ms = 0; + monotime_coarse_zero(&chan->next_padding_time); } /** @@ -3332,13 +3332,13 @@ channel_timestamp_xmit(channel_t *chan) time_t now = time(NULL); tor_assert(chan); - chan->timestamp_xfer_ms = monotime_coarse_absolute_msec(); + monotime_coarse_get(&chan->timestamp_xfer); chan->timestamp_active = now; chan->timestamp_xmit = now; /* Clear any potential netflow padding timer. We're active */ - chan->next_padding_time_ms = 0; + monotime_coarse_zero(&chan->next_padding_time); } /*************************************************************** diff --git a/src/or/channel.h b/src/or/channel.h @@ -88,10 +88,9 @@ struct channel_s { * Used to decide what channels to pad, and when. */ channel_usage_info_t channel_usage; - /** When should we send a cell for netflow padding, in absolute - * milliseconds since monotime system start. 0 means no padding - * is scheduled. */ - uint64_t next_padding_time_ms; + /** When should we send a cell for netflow padding? 0 means no padding is + * scheduled. */ + monotime_coarse_t next_padding_time; /** The callback pointer for the padding callbacks */ tor_timer_t *padding_timer; @@ -158,7 +157,7 @@ struct channel_s { time_t timestamp_active; /* Any activity */ /** - * This is a high-resolution monotonic timestamp that marks when we + * This is a monotonic timestamp that marks when we * believe the channel has actually sent or received data to/from * the wire. Right now, it is used to determine when we should send * a padding cell for channelpadding. @@ -167,7 +166,7 @@ struct channel_s { * accurately reflect actual network data transfer? Or might this be * very wrong wrt when bytes actually go on the wire? */ - uint64_t timestamp_xfer_ms; + monotime_coarse_t timestamp_xfer; /* Methods implemented by the lower layer */ diff --git a/src/or/channelpadding.c b/src/or/channelpadding.c @@ -23,7 +23,8 @@ #include <event2/event.h> #include "rendservice.h" -STATIC int channelpadding_get_netflow_inactive_timeout_ms(const channel_t *); +STATIC int32_t channelpadding_get_netflow_inactive_timeout_ms( + const channel_t *); STATIC int channelpadding_send_disable_command(channel_t *); STATIC int64_t channelpadding_compute_time_until_pad_for_netflow(channel_t *); @@ -165,7 +166,7 @@ channelpadding_new_consensus_params(networkstatus_t *ns) * Returns the next timeout period (in milliseconds) after which we should * send a padding packet, or 0 if padding is disabled. */ -STATIC int +STATIC int32_t channelpadding_get_netflow_inactive_timeout_ms(const channel_t *chan) { int low_timeout = consensus_nf_ito_low; @@ -377,15 +378,16 @@ channelpadding_send_padding_cell_for_callback(channel_t *chan) chan->pending_padding_callback = 0; - if (!chan->next_padding_time_ms || + if (monotime_coarse_is_zero(&chan->next_padding_time) || chan->has_queued_writes(chan)) { /* We must have been active before the timer fired */ - chan->next_padding_time_ms = 0; + monotime_coarse_zero(&chan->next_padding_time); return; } { - uint64_t now = monotime_coarse_absolute_msec(); + monotime_coarse_t now; + monotime_coarse_get(&now); log_fn(LOG_INFO,LD_OR, "Sending netflow keepalive on "U64_FORMAT" to %s (%s) after " @@ -393,12 +395,13 @@ channelpadding_send_padding_cell_for_callback(channel_t *chan) U64_PRINTF_ARG(chan->global_identifier), safe_str_client(chan->get_remote_descr(chan, 0)), safe_str_client(hex_str(chan->identity_digest, DIGEST_LEN)), - U64_PRINTF_ARG(now - chan->timestamp_xfer_ms), - U64_PRINTF_ARG(now - chan->next_padding_time_ms)); + I64_PRINTF_ARG(monotime_coarse_diff_msec(&chan->timestamp_xfer,&now)), + I64_PRINTF_ARG( + monotime_coarse_diff_msec(&chan->next_padding_time,&now))); } /* Clear the timer */ - chan->next_padding_time_ms = 0; + monotime_coarse_zero(&chan->next_padding_time); /* Send the padding cell. This will cause the channel to get a * fresh timestamp_active */ @@ -500,38 +503,42 @@ channelpadding_schedule_padding(channel_t *chan, int in_ms) STATIC int64_t channelpadding_compute_time_until_pad_for_netflow(channel_t *chan) { - uint64_t long_now = monotime_coarse_absolute_msec(); + monotime_coarse_t now; + monotime_coarse_get(&now); - if (!chan->next_padding_time_ms) { + if (monotime_coarse_is_zero(&chan->next_padding_time)) { /* If the below line or crypto_rand_int() shows up on a profile, * we can avoid getting a timeout until we're at least nf_ito_lo * from a timeout window. That will prevent us from setting timers * on connections that were active up to 1.5 seconds ago. * Idle connections should only call this once every 5.5s on average * though, so that might be a micro-optimization for little gain. */ - int64_t padding_timeout = + int32_t padding_timeout = channelpadding_get_netflow_inactive_timeout_ms(chan); if (!padding_timeout) return CHANNELPADDING_TIME_DISABLED; - chan->next_padding_time_ms = padding_timeout - + chan->timestamp_xfer_ms; + monotime_coarse_add_msec(&chan->next_padding_time, + &chan->timestamp_xfer, + padding_timeout); } + const int64_t ms_till_pad = + monotime_coarse_diff_msec(&now, &chan->next_padding_time); + /* If the next padding time is beyond the maximum possible consensus value, * then this indicates a clock jump, so just send padding now. This is * better than using monotonic time because we want to avoid the situation * where we wait around forever for monotonic time to move forward after * a clock jump far into the past. */ - if (chan->next_padding_time_ms > long_now + - DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX) { + if (ms_till_pad > DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX) { tor_fragile_assert(); log_warn(LD_BUG, "Channel padding timeout scheduled "I64_FORMAT"ms in the future. " "Did the monotonic clock just jump?", - I64_PRINTF_ARG(chan->next_padding_time_ms - long_now)); + I64_PRINTF_ARG(ms_till_pad)); return 0; /* Clock jumped: Send padding now */ } @@ -540,11 +547,8 @@ channelpadding_compute_time_until_pad_for_netflow(channel_t *chan) from now which we should send padding, so we can schedule a callback then. */ - if (long_now + - (TOR_HOUSEKEEPING_CALLBACK_MSEC + TOR_HOUSEKEEPING_CALLBACK_SLACK_MSEC) - >= chan->next_padding_time_ms) { - int64_t ms_until_pad_for_netflow = chan->next_padding_time_ms - - long_now; + if (ms_till_pad < (TOR_HOUSEKEEPING_CALLBACK_MSEC + + TOR_HOUSEKEEPING_CALLBACK_SLACK_MSEC)) { /* If the padding time is in the past, that means that libevent delayed * calling the once-per-second callback due to other work taking too long. * See https://bugs.torproject.org/22212 and @@ -554,16 +558,16 @@ channelpadding_compute_time_until_pad_for_netflow(channel_t *chan) * and allowed a router to emit a netflow frame, just so we don't forget * about it entirely.. */ #define NETFLOW_MISSED_WINDOW (150000 - DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH) - if (ms_until_pad_for_netflow < 0) { - int severity = (ms_until_pad_for_netflow < -NETFLOW_MISSED_WINDOW) + if (ms_till_pad < 0) { + int severity = (ms_till_pad < -NETFLOW_MISSED_WINDOW) ? LOG_NOTICE : LOG_INFO; log_fn(severity, LD_OR, "Channel padding timeout scheduled "I64_FORMAT"ms in the past. ", - I64_PRINTF_ARG(-ms_until_pad_for_netflow)); + I64_PRINTF_ARG(-ms_till_pad)); return 0; /* Clock jumped: Send padding now */ } - return ms_until_pad_for_netflow; + return ms_till_pad; } return CHANNELPADDING_TIME_LATER; } diff --git a/src/test/test_channel.c b/src/test/test_channel.c @@ -703,7 +703,7 @@ test_channel_inbound_cell(void *arg) old_count = test_chan_fixed_cells_recved; channel_process_cell(chan, cell); tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count); - tt_u64_op(chan->timestamp_xfer_ms, OP_EQ, 0); + tt_assert(monotime_coarse_is_zero(&chan->timestamp_xfer)); tt_u64_op(chan->timestamp_active, OP_EQ, 0); tt_u64_op(chan->timestamp_recv, OP_EQ, 0); @@ -716,10 +716,10 @@ test_channel_inbound_cell(void *arg) channel_process_cell(chan, cell); tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count + 1); /* We should have a series of timestamp set. */ - tt_u64_op(chan->timestamp_xfer_ms, OP_NE, 0); + tt_assert(!monotime_coarse_is_zero(&chan->timestamp_xfer)); tt_u64_op(chan->timestamp_active, OP_NE, 0); tt_u64_op(chan->timestamp_recv, OP_NE, 0); - tt_u64_op(chan->next_padding_time_ms, OP_EQ, 0); + tt_assert(monotime_is_zero(&chan->next_padding_time)); tt_u64_op(chan->n_cells_recved, OP_EQ, 1); tt_u64_op(chan->n_bytes_recved, OP_EQ, get_cell_network_size(0)); diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c @@ -279,7 +279,6 @@ test_channelpadding_timers(void *arg) { channelpadding_decision_t decision; channel_t *chans[CHANNELS_TO_TEST]; - int64_t new_time; (void)arg; tor_libevent_postfork(); @@ -289,8 +288,9 @@ test_channelpadding_timers(void *arg) monotime_init(); monotime_enable_test_mocking(); - monotime_set_mock_time_nsec(1); - monotime_coarse_set_mock_time_nsec(1); + uint64_t nsec_mock = 1; + monotime_set_mock_time_nsec(nsec_mock); + monotime_coarse_set_mock_time_nsec(nsec_mock); timers_initialize(); channelpadding_new_consensus_params(NULL); @@ -304,11 +304,14 @@ test_channelpadding_timers(void *arg) tried_to_write_cell = 0; int i = 0; + monotime_coarse_t now; + monotime_coarse_get(&now); + /* This loop fills our timerslot array with timers of increasing time * until they fire */ for (; i < CHANNELPADDING_MAX_TIMERS; i++) { - chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() - + 10 + i*4; + monotime_coarse_add_msec(&chans[i]->next_padding_time, + &now, 10 + i*4); decision = channelpadding_decide_to_pad_channel(chans[i]); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chans[i]->pending_padding_callback); @@ -318,7 +321,8 @@ test_channelpadding_timers(void *arg) /* This loop should add timers to the first position in the timerslot * array, since its timeout is before all other timers. */ for (; i < CHANNELS_TO_TEST/3; i++) { - chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() + 1; + monotime_coarse_add_msec(&chans[i]->next_padding_time, + &now, 1); decision = channelpadding_decide_to_pad_channel(chans[i]); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chans[i]->pending_padding_callback); @@ -329,8 +333,8 @@ test_channelpadding_timers(void *arg) * pseudorandom pattern. It ensures that the lists can grow with multiple * timers in them. */ for (; i < CHANNELS_TO_TEST/2; i++) { - chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() + 10 + - i*3 % CHANNELPADDING_MAX_TIMERS; + monotime_coarse_add_msec(&chans[i]->next_padding_time, + &now, 10 + i*3 % CHANNELPADDING_MAX_TIMERS); decision = channelpadding_decide_to_pad_channel(chans[i]); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chans[i]->pending_padding_callback); @@ -340,8 +344,8 @@ test_channelpadding_timers(void *arg) /* This loop should add timers to the last position in the timerslot * array, since its timeout is after all other timers. */ for (; i < CHANNELS_TO_TEST; i++) { - chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() + 500 + - i % CHANNELPADDING_MAX_TIMERS; + monotime_coarse_add_msec(&chans[i]->next_padding_time, + &now, 500 + i % CHANNELPADDING_MAX_TIMERS); decision = channelpadding_decide_to_pad_channel(chans[i]); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chans[i]->pending_padding_callback); @@ -349,9 +353,9 @@ test_channelpadding_timers(void *arg) } // Wait for the timers and then kill the event loop. - new_time = (monotime_coarse_absolute_msec()+1001)*NSEC_PER_MSEC; - monotime_coarse_set_mock_time_nsec(new_time); - monotime_set_mock_time_nsec(new_time); + nsec_mock += 1001 * NSEC_PER_MSEC; + monotime_coarse_set_mock_time_nsec(nsec_mock); + monotime_set_mock_time_nsec(nsec_mock); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, CHANNELS_TO_TEST); @@ -388,6 +392,7 @@ test_channelpadding_killonehop(void *arg) monotime_enable_test_mocking(); monotime_set_mock_time_nsec(1); monotime_coarse_set_mock_time_nsec(1); + new_time = 1; timers_initialize(); setup_mock_consensus(); @@ -401,9 +406,12 @@ test_channelpadding_killonehop(void *arg) smartlist_clear(current_md_consensus->net_params); channelpadding_new_consensus_params(current_md_consensus); + monotime_coarse_t now; + monotime_coarse_get(&now); + tried_to_write_cell = 0; get_options_mutable()->Tor2webMode = 1; - client_relay3->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&client_relay3->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(client_relay3); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(client_relay3->pending_padding_callback); @@ -413,9 +421,10 @@ test_channelpadding_killonehop(void *arg) tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!client_relay3->pending_padding_callback); @@ -427,7 +436,7 @@ test_channelpadding_killonehop(void *arg) // Before the client tries to pad, the relay will still pad: tried_to_write_cell = 0; - relay3_client->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&relay3_client->next_padding_time, &now, 100); get_options_mutable()->ORPort_set = 1; get_options_mutable()->Tor2webMode = 0; decision = channelpadding_decide_to_pad_channel(relay3_client); @@ -435,9 +444,10 @@ test_channelpadding_killonehop(void *arg) tt_assert(relay3_client->pending_padding_callback); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!client_relay3->pending_padding_callback); @@ -474,7 +484,8 @@ test_channelpadding_killonehop(void *arg) get_options_mutable()->ORPort_set = 0; get_options_mutable()->HiddenServiceSingleHopMode = 1; get_options_mutable()->HiddenServiceNonAnonymousMode = 1; - client_relay3->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + + monotime_coarse_add_msec(&client_relay3->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(client_relay3); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(client_relay3->pending_padding_callback); @@ -484,9 +495,10 @@ test_channelpadding_killonehop(void *arg) tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101 * NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!client_relay3->pending_padding_callback); @@ -498,7 +510,7 @@ test_channelpadding_killonehop(void *arg) // Before the client tries to pad, the relay will still pad: tried_to_write_cell = 0; - relay3_client->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&relay3_client->next_padding_time, &now, 100); get_options_mutable()->ORPort_set = 1; get_options_mutable()->HiddenServiceSingleHopMode = 0; get_options_mutable()->HiddenServiceNonAnonymousMode = 0; @@ -507,9 +519,10 @@ test_channelpadding_killonehop(void *arg) tt_assert(relay3_client->pending_padding_callback); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101 * NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!client_relay3->pending_padding_callback); @@ -573,6 +586,9 @@ test_channelpadding_consensus(void *arg) monotime_enable_test_mocking(); monotime_set_mock_time_nsec(1); monotime_coarse_set_mock_time_nsec(1); + new_time = 1; + monotime_coarse_t now; + monotime_coarse_get(&now); timers_initialize(); if (!connection_array) @@ -586,7 +602,7 @@ test_channelpadding_consensus(void *arg) /* Test 1: Padding can be completely disabled via consensus */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); @@ -596,9 +612,10 @@ test_channelpadding_consensus(void *arg) tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!chan->pending_padding_callback); @@ -628,7 +645,7 @@ test_channelpadding_consensus(void *arg) tt_i64_op(val, OP_EQ, 0); val = channelpadding_compute_time_until_pad_for_netflow(chan); tt_i64_op(val, OP_EQ, -2); - tt_assert(!chan->next_padding_time_ms); + tt_assert(monotime_coarse_is_zero(&chan->next_padding_time)); smartlist_clear(current_md_consensus->net_params); @@ -641,7 +658,7 @@ test_channelpadding_consensus(void *arg) channelpadding_new_consensus_params(current_md_consensus); tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); @@ -653,9 +670,10 @@ test_channelpadding_consensus(void *arg) tt_i64_op(val, OP_LE, 200); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+201)*NSEC_PER_MSEC; + new_time += 201*NSEC_PER_MSEC; monotime_set_mock_time_nsec(new_time); monotime_coarse_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!chan->pending_padding_callback); @@ -944,6 +962,9 @@ test_channelpadding_decide_to_pad_channel(void *arg) monotime_enable_test_mocking(); monotime_set_mock_time_nsec(1); monotime_coarse_set_mock_time_nsec(1); + new_time = 1; + monotime_coarse_t now; + monotime_coarse_get(&now); timers_initialize(); setup_full_capture_of_logs(LOG_WARN); channelpadding_new_consensus_params(NULL); @@ -960,7 +981,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #2a: > 1.1s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 1200; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 1200); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER); tt_assert(!chan->pending_padding_callback); @@ -968,23 +989,27 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #2b: >= 1.0s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 1000; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 1000); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); tt_int_op(tried_to_write_cell, OP_EQ, 0); + // Set up a timer for the <0 case below. + monotime_coarse_t now_minus_100s; + monotime_coarse_add_msec(&now_minus_100s, &now, 900); // Wait for the timer from case #2b - new_time = (monotime_coarse_absolute_msec() + 1000)*NSEC_PER_MSEC; + new_time += 1000*NSEC_PER_MSEC; monotime_set_mock_time_nsec(new_time); monotime_coarse_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!chan->pending_padding_callback); /* Test case #2c: > 0.1s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); @@ -995,16 +1020,17 @@ test_channelpadding_decide_to_pad_channel(void *arg) tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); tt_assert(!chan->pending_padding_callback); /* Test case #2e: 0s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec(); + monotime_coarse_add_msec(&chan->next_padding_time, &now, 0); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SENT); tt_int_op(tried_to_write_cell, OP_EQ, 1); @@ -1012,7 +1038,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #2f: <0s until timeout */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() - 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now_minus_100s, 0); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SENT); tt_int_op(tried_to_write_cell, OP_EQ, 1); @@ -1020,7 +1046,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #3: Channel that sends a packet while timeout is scheduled */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1031,9 +1057,10 @@ test_channelpadding_decide_to_pad_channel(void *arg) // We don't expect any timer callbacks here. Make a dummy one to be sure. // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1041,7 +1068,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #4: Channel that closes while a timeout is scheduled */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1051,9 +1078,10 @@ test_channelpadding_decide_to_pad_channel(void *arg) chan->state = CHANNEL_STATE_MAINT; // We don't expect any timer callbacks here. Make a dummy one to be sure. - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1062,16 +1090,17 @@ test_channelpadding_decide_to_pad_channel(void *arg) /* Test case #5: Make sure previous test case didn't break everything */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_assert(chan->pending_padding_callback); tt_int_op(tried_to_write_cell, OP_EQ, 0); // Wait for the timer - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time += 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 1); @@ -1090,7 +1119,7 @@ test_channelpadding_decide_to_pad_channel(void *arg) * It must be last. */ tried_to_write_cell = 0; - chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100; + monotime_coarse_add_msec(&chan->next_padding_time, &now, 100); decision = channelpadding_decide_to_pad_channel(chan); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_int_op(tried_to_write_cell, OP_EQ, 0); @@ -1100,9 +1129,10 @@ test_channelpadding_decide_to_pad_channel(void *arg) free_fake_channeltls((channel_tls_t*)chan); // We don't expect any timer callbacks here. Make a dummy one to be sure. - new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC; + new_time = 101*NSEC_PER_MSEC; monotime_coarse_set_mock_time_nsec(new_time); monotime_set_mock_time_nsec(new_time); + monotime_coarse_get(&now); timers_run_pending(); tt_int_op(tried_to_write_cell, OP_EQ, 0); diff --git a/src/test/test_util.c b/src/test/test_util.c @@ -5926,6 +5926,65 @@ test_util_monotonic_time_ratchet(void *arg) } static void +test_util_monotonic_time_zero(void *arg) +{ + (void) arg; + monotime_t t1; + monotime_coarse_t ct1; + monotime_init(); + /* Check 1: The current time is not zero. */ + monotime_get(&t1); + monotime_coarse_get(&ct1); + tt_assert(!monotime_is_zero(&t1)); + tt_assert(!monotime_coarse_is_zero(&ct1)); + + /* Check 2: The _zero() makes the time zero. */ + monotime_zero(&t1); + monotime_coarse_zero(&ct1); + tt_assert(monotime_is_zero(&t1)); + tt_assert(monotime_coarse_is_zero(&ct1)); + done: + ; +} + +static void +test_util_monotonic_time_add_msec(void *arg) +{ + (void) arg; + monotime_t t1, t2; + monotime_coarse_t ct1, ct2; + monotime_init(); + + monotime_get(&t1); + monotime_coarse_get(&ct1); + + /* adding zero does nothing */ + monotime_add_msec(&t2, &t1, 0); + monotime_coarse_add_msec(&ct2, &ct1, 0); + tt_i64_op(monotime_diff_msec(&t1, &t2), OP_EQ, 0); + tt_i64_op(monotime_coarse_diff_msec(&ct1, &ct2), OP_EQ, 0); + + /* Add 1337 msec; see if the diff function agree */ + monotime_add_msec(&t2, &t1, 1337); + monotime_coarse_add_msec(&ct2, &ct1, 1337); + tt_i64_op(monotime_diff_msec(&t1, &t2), OP_EQ, 1337); + tt_i64_op(monotime_coarse_diff_msec(&ct1, &ct2), OP_EQ, 1337); + + /* Add 1337 msec twice more; make sure that any second rollover issues + * worked. */ + monotime_add_msec(&t2, &t2, 1337); + monotime_coarse_add_msec(&ct2, &ct2, 1337); + monotime_add_msec(&t2, &t2, 1337); + monotime_coarse_add_msec(&ct2, &ct2, 1337); + tt_i64_op(monotime_diff_msec(&t1, &t2), OP_EQ, 1337*3); + tt_i64_op(monotime_coarse_diff_msec(&ct1, &ct2), OP_EQ, 1337*3); + + + done: + ; +} + +static void test_util_htonll(void *arg) { (void)arg; @@ -6158,6 +6217,8 @@ struct testcase_t util_tests[] = { UTIL_TEST(calloc_check, 0), UTIL_TEST(monotonic_time, 0), UTIL_TEST(monotonic_time_ratchet, TT_FORK), + UTIL_TEST(monotonic_time_zero, 0), + UTIL_TEST(monotonic_time_add_msec, 0), UTIL_TEST(htonll, 0), UTIL_TEST(get_unquoted_path, 0), END_OF_TESTCASES