/** * Shuffle the build times array. * * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle */ static void circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, build_time_t *raw_times, uint32_t num_times) { uint32_t n = num_times; if (num_times > CBT_NCIRCUITS_TO_OBSERVE) { log_notice(LD_CIRC, "The number of circuit times that this Tor version " "uses to calculate build times is less than the number stored " "in your state file. Decreasing the circuit time history from " "%lu to %d.", (unsigned long)num_times, CBT_NCIRCUITS_TO_OBSERVE); } if (n > INT_MAX-1) { log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build " "observations in your state file. That's far too many; probably " "there's a bug here.", (unsigned long)n); n = INT_MAX-1; } /* This code can only be run on a compact array */ while (n-- > 1) { int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */ build_time_t tmp = raw_times[k]; raw_times[k] = raw_times[n]; raw_times[n] = tmp; } /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */ for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) { circuit_build_times_add_time(cbt, raw_times[n]); } }
/** * Store a timeout as a synthetic value. * * Returns true if the store was successful and we should possibly * update our timeout estimate. */ int circuit_build_times_count_close(circuit_build_times_t *cbt, int did_onehop, time_t start_time) { if (circuit_build_times_disabled()) { cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); return 0; } /* Record this force-close to help determine if the network is dead */ circuit_build_times_network_close(cbt, did_onehop, start_time); /* Only count timeouts if network is live.. */ if (!circuit_build_times_network_check_live(cbt)) { return 0; } circuit_build_times_add_time(cbt, CBT_BUILD_ABANDONED); return 1; }
static void test_circuit_timeout(void *arg) { /* Plan: * 1. Generate 1000 samples * 2. Estimate parameters * 3. If difference, repeat * 4. Save state * 5. load state * 6. Estimate parameters * 7. compare differences */ circuit_build_times_t initial; circuit_build_times_t estimate; circuit_build_times_t final; double timeout1, timeout2; or_state_t *state=NULL; int i, runs; double close_ms; (void)arg; initialize_periodic_events(); circuit_build_times_init(&initial); circuit_build_times_init(&estimate); circuit_build_times_init(&final); state = or_state_new(); circuitbuild_running_unit_tests(); #define timeout0 (build_time_t)(30*1000.0) initial.Xm = 3000; circuit_build_times_initial_alpha(&initial, CBT_DEFAULT_QUANTILE_CUTOFF/100.0, timeout0); close_ms = MAX(circuit_build_times_calculate_timeout(&initial, CBT_DEFAULT_CLOSE_QUANTILE/100.0), CBT_DEFAULT_TIMEOUT_INITIAL_VALUE); do { for (i=0; i < CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE; i++) { build_time_t sample = circuit_build_times_generate_sample(&initial,0,1); if (sample > close_ms) { circuit_build_times_add_time(&estimate, CBT_BUILD_ABANDONED); } else { circuit_build_times_add_time(&estimate, sample); } } circuit_build_times_update_alpha(&estimate); timeout1 = circuit_build_times_calculate_timeout(&estimate, CBT_DEFAULT_QUANTILE_CUTOFF/100.0); circuit_build_times_set_timeout(&estimate); log_notice(LD_CIRC, "Timeout1 is %f, Xm is %d", timeout1, estimate.Xm); /* 2% error */ } while (fabs(circuit_build_times_cdf(&initial, timeout0) - circuit_build_times_cdf(&initial, timeout1)) > 0.02); tt_int_op(estimate.total_build_times, OP_LE, CBT_NCIRCUITS_TO_OBSERVE); circuit_build_times_update_state(&estimate, state); circuit_build_times_free_timeouts(&final); tt_int_op(circuit_build_times_parse_state(&final, state), OP_EQ, 0); circuit_build_times_update_alpha(&final); timeout2 = circuit_build_times_calculate_timeout(&final, CBT_DEFAULT_QUANTILE_CUTOFF/100.0); circuit_build_times_set_timeout(&final); log_notice(LD_CIRC, "Timeout2 is %f, Xm is %d", timeout2, final.Xm); /* 5% here because some accuracy is lost due to histogram conversion */ tt_assert(fabs(circuit_build_times_cdf(&initial, timeout0) - circuit_build_times_cdf(&initial, timeout2)) < 0.05); for (runs = 0; runs < 50; runs++) { int build_times_idx = 0; int total_build_times = 0; final.close_ms = final.timeout_ms = CBT_DEFAULT_TIMEOUT_INITIAL_VALUE; estimate.close_ms = estimate.timeout_ms = CBT_DEFAULT_TIMEOUT_INITIAL_VALUE; for (i = 0; i < CBT_DEFAULT_RECENT_CIRCUITS*2; i++) { circuit_build_times_network_circ_success(&estimate); circuit_build_times_add_time(&estimate, circuit_build_times_generate_sample(&estimate, 0, CBT_DEFAULT_QUANTILE_CUTOFF/100.0)); circuit_build_times_network_circ_success(&estimate); circuit_build_times_add_time(&final, circuit_build_times_generate_sample(&final, 0, CBT_DEFAULT_QUANTILE_CUTOFF/100.0)); } tt_assert(!circuit_build_times_network_check_changed(&estimate)); tt_assert(!circuit_build_times_network_check_changed(&final)); /* Reset liveness to be non-live */ final.liveness.network_last_live = 0;