#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 *);
* 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;
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 "
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 */
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 */
}
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
* 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;
}
{
channelpadding_decision_t decision;
channel_t *chans[CHANNELS_TO_TEST];
- int64_t new_time;
(void)arg;
tor_libevent_postfork();
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);
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);
/* 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);
* 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);
/* 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);
}
// 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);
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();
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);
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);
// 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);
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);
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);
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);
// 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;
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);
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)
/* 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);
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);
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);
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);
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);
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);
/* 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);
/* 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);
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);
/* 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);
/* 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);
// 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);
/* 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);
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);
/* 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);
* 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);
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);