|  | @@ -11,6 +11,7 @@
 | 
	
		
			
				|  |  |   * servers.
 | 
	
		
			
				|  |  |   **/
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define ROUTERLIST_PRIVATE
 | 
	
		
			
				|  |  |  #include "or.h"
 | 
	
		
			
				|  |  |  #include "circuitbuild.h"
 | 
	
		
			
				|  |  |  #include "config.h"
 | 
	
	
		
			
				|  | @@ -1647,6 +1648,92 @@ router_get_advertised_bandwidth_capped(const routerinfo_t *router)
 | 
	
		
			
				|  |  |    return result;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/** Given an array of double/uint64_t unions that are currently being used as
 | 
	
		
			
				|  |  | + * doubles, convert them to uint64_t, and try to scale them linearly so as to
 | 
	
		
			
				|  |  | + * much of the range of uint64_t. If <b>total_out</b> is provided, set it to
 | 
	
		
			
				|  |  | + * the sum of all elements in the array _before_ scaling. */
 | 
	
		
			
				|  |  | +/* private */ void
 | 
	
		
			
				|  |  | +scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
 | 
	
		
			
				|  |  | +                            uint64_t *total_out)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  double total = 0.0;
 | 
	
		
			
				|  |  | +  double scale_factor;
 | 
	
		
			
				|  |  | +  int i;
 | 
	
		
			
				|  |  | +  /* big, but far away from overflowing an int64_t */
 | 
	
		
			
				|  |  | +#define SCALE_TO_U64_MAX (INT64_MAX / 4)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (i = 0; i < n_entries; ++i)
 | 
	
		
			
				|  |  | +    total += entries[i].dbl;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  scale_factor = SCALE_TO_U64_MAX / total;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (i = 0; i < n_entries; ++i)
 | 
	
		
			
				|  |  | +    entries[i].u64 = tor_llround(entries[i].dbl * scale_factor);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (total_out)
 | 
	
		
			
				|  |  | +    *total_out = (uint64_t) total;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#undef SCALE_TO_U64_MAX
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** Time-invariant 64-bit greater-than; works on two integers in the range
 | 
	
		
			
				|  |  | + * (0,INT64_MAX). */
 | 
	
		
			
				|  |  | +#if SIZEOF_VOID_P == 8
 | 
	
		
			
				|  |  | +#define gt_i64_timei(a,b) ((a) > (b))
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +static INLINE int
 | 
	
		
			
				|  |  | +gt_i64_timei(uint64_t a, uint64_t b)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  int64_t diff = (int64_t) (b - a);
 | 
	
		
			
				|  |  | +  int res = diff >> 63;
 | 
	
		
			
				|  |  | +  return res & 1;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** Pick a random element of <b>n_entries</b>-element array <b>entries</b>,
 | 
	
		
			
				|  |  | + * choosing each element with a probability proportional to its (uint64_t)
 | 
	
		
			
				|  |  | + * value, and return the index of that element.  If all elements are 0, choose
 | 
	
		
			
				|  |  | + * an index at random. Return -1 on error.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +/* private */ int
 | 
	
		
			
				|  |  | +choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  int i, i_chosen=-1, n_chosen=0;
 | 
	
		
			
				|  |  | +  uint64_t total_so_far = 0;
 | 
	
		
			
				|  |  | +  uint64_t rand_val;
 | 
	
		
			
				|  |  | +  uint64_t total = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (i = 0; i < n_entries; ++i)
 | 
	
		
			
				|  |  | +    total += entries[i].u64;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (n_entries < 1)
 | 
	
		
			
				|  |  | +    return -1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (total == 0)
 | 
	
		
			
				|  |  | +    return crypto_rand_int(n_entries);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  tor_assert(total < INT64_MAX);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  rand_val = crypto_rand_uint64(total);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (i = 0; i < n_entries; ++i) {
 | 
	
		
			
				|  |  | +    total_so_far += entries[i].u64;
 | 
	
		
			
				|  |  | +    if (gt_i64_timei(total_so_far, rand_val)) {
 | 
	
		
			
				|  |  | +      i_chosen = i;
 | 
	
		
			
				|  |  | +      n_chosen++;
 | 
	
		
			
				|  |  | +      /* Set rand_val to INT64_MAX rather than stopping the loop. This way,
 | 
	
		
			
				|  |  | +       * the time we spend in the loop does not leak which element we chose. */
 | 
	
		
			
				|  |  | +      rand_val = INT64_MAX;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  tor_assert(total_so_far == total);
 | 
	
		
			
				|  |  | +  tor_assert(n_chosen == 1);
 | 
	
		
			
				|  |  | +  tor_assert(i_chosen >= 0);
 | 
	
		
			
				|  |  | +  tor_assert(i_chosen < n_entries);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return i_chosen;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** When weighting bridges, enforce these values as lower and upper
 | 
	
		
			
				|  |  |   * bound for believable bandwidth, because there is no way for us
 | 
	
		
			
				|  |  |   * to verify a bridge's bandwidth currently. */
 | 
	
	
		
			
				|  | @@ -1697,16 +1784,10 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
 | 
	
		
			
				|  |  |                                             bandwidth_weight_rule_t rule)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    int64_t weight_scale;
 | 
	
		
			
				|  |  | -  int64_t rand_bw;
 | 
	
		
			
				|  |  |    double Wg = -1, Wm = -1, We = -1, Wd = -1;
 | 
	
		
			
				|  |  |    double Wgb = -1, Wmb = -1, Web = -1, Wdb = -1;
 | 
	
		
			
				|  |  | -  double weighted_bw = 0, unweighted_bw = 0;
 | 
	
		
			
				|  |  | -  double *bandwidths;
 | 
	
		
			
				|  |  | -  double tmp = 0;
 | 
	
		
			
				|  |  | -  unsigned int i;
 | 
	
		
			
				|  |  | -  unsigned int i_chosen;
 | 
	
		
			
				|  |  | -  unsigned int i_has_been_chosen;
 | 
	
		
			
				|  |  | -  int have_unknown = 0; /* true iff sl contains element not in consensus. */
 | 
	
		
			
				|  |  | +  uint64_t weighted_bw = 0;
 | 
	
		
			
				|  |  | +  u64_dbl_t *bandwidths;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Can't choose exit and guard at same time */
 | 
	
		
			
				|  |  |    tor_assert(rule == NO_WEIGHTING ||
 | 
	
	
		
			
				|  | @@ -1787,7 +1868,7 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
 | 
	
		
			
				|  |  |    Web /= weight_scale;
 | 
	
		
			
				|  |  |    Wdb /= weight_scale;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  bandwidths = tor_malloc_zero(sizeof(double)*smartlist_len(sl));
 | 
	
		
			
				|  |  | +  bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Cycle through smartlist and total the bandwidth.
 | 
	
		
			
				|  |  |    SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
 | 
	
	
		
			
				|  | @@ -1810,7 +1891,6 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
 | 
	
		
			
				|  |  |      } else if (node->ri) {
 | 
	
		
			
				|  |  |        /* bridge or other descriptor not in our consensus */
 | 
	
		
			
				|  |  |        this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
 | 
	
		
			
				|  |  | -      have_unknown = 1;
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        /* We can't use this one. */
 | 
	
		
			
				|  |  |        continue;
 | 
	
	
		
			
				|  | @@ -1826,72 +1906,32 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
 | 
	
		
			
				|  |  |      } else { // middle
 | 
	
		
			
				|  |  |        weight = (is_dir ? Wmb*Wm : Wm);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    bandwidths[node_sl_idx] = weight*this_bw;
 | 
	
		
			
				|  |  | -    weighted_bw += weight*this_bw;
 | 
	
		
			
				|  |  | -    unweighted_bw += this_bw;
 | 
	
		
			
				|  |  | +    /* These should be impossible; but overflows here would be bad, so let's
 | 
	
		
			
				|  |  | +     * make sure. */
 | 
	
		
			
				|  |  | +    if (this_bw < 0)
 | 
	
		
			
				|  |  | +      this_bw = 0;
 | 
	
		
			
				|  |  | +    if (weight < 0.0)
 | 
	
		
			
				|  |  | +      weight = 0.0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    bandwidths[node_sl_idx].dbl = weight*this_bw + 0.5;
 | 
	
		
			
				|  |  |      if (is_me)
 | 
	
		
			
				|  |  | -      sl_last_weighted_bw_of_me = weight*this_bw;
 | 
	
		
			
				|  |  | +      sl_last_weighted_bw_of_me = (uint64_t) bandwidths[node_sl_idx].dbl;
 | 
	
		
			
				|  |  |    } SMARTLIST_FOREACH_END(node);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* XXXX this is a kludge to expose these values. */
 | 
	
		
			
				|  |  | -  sl_last_total_weighted_bw = weighted_bw;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    log_debug(LD_CIRC, "Choosing node for rule %s based on weights "
 | 
	
		
			
				|  |  | -            "Wg=%f Wm=%f We=%f Wd=%f with total bw %f",
 | 
	
		
			
				|  |  | +            "Wg=%f Wm=%f We=%f Wd=%f with total bw "U64_FORMAT,
 | 
	
		
			
				|  |  |              bandwidth_weight_rule_to_string(rule),
 | 
	
		
			
				|  |  | -            Wg, Wm, We, Wd, weighted_bw);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* If there is no bandwidth, choose at random */
 | 
	
		
			
				|  |  | -  if (DBL_TO_U64(weighted_bw) == 0) {
 | 
	
		
			
				|  |  | -    /* Don't warn when using bridges/relays not in the consensus */
 | 
	
		
			
				|  |  | -    if (!have_unknown) {
 | 
	
		
			
				|  |  | -#define ZERO_BANDWIDTH_WARNING_INTERVAL (15)
 | 
	
		
			
				|  |  | -      static ratelim_t zero_bandwidth_warning_limit =
 | 
	
		
			
				|  |  | -        RATELIM_INIT(ZERO_BANDWIDTH_WARNING_INTERVAL);
 | 
	
		
			
				|  |  | -      char *msg;
 | 
	
		
			
				|  |  | -      if ((msg = rate_limit_log(&zero_bandwidth_warning_limit,
 | 
	
		
			
				|  |  | -                                approx_time()))) {
 | 
	
		
			
				|  |  | -        log_warn(LD_CIRC,
 | 
	
		
			
				|  |  | -                 "Weighted bandwidth is %f in node selection for rule %s "
 | 
	
		
			
				|  |  | -                 "(unweighted was %f) %s",
 | 
	
		
			
				|  |  | -                 weighted_bw, bandwidth_weight_rule_to_string(rule),
 | 
	
		
			
				|  |  | -                 unweighted_bw, msg);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    tor_free(bandwidths);
 | 
	
		
			
				|  |  | -    return smartlist_choose(sl);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +            Wg, Wm, We, Wd, U64_PRINTF_ARG(weighted_bw));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  rand_bw = crypto_rand_uint64(DBL_TO_U64(weighted_bw));
 | 
	
		
			
				|  |  | -  rand_bw++; /* crypto_rand_uint64() counts from 0, and we need to count
 | 
	
		
			
				|  |  | -              * from 1 below. See bug 1203 for details. */
 | 
	
		
			
				|  |  | +  scale_array_elements_to_u64(bandwidths, smartlist_len(sl),
 | 
	
		
			
				|  |  | +                              &sl_last_total_weighted_bw);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* Last, count through sl until we get to the element we picked */
 | 
	
		
			
				|  |  | -  i_chosen = (unsigned)smartlist_len(sl);
 | 
	
		
			
				|  |  | -  i_has_been_chosen = 0;
 | 
	
		
			
				|  |  | -  tmp = 0.0;
 | 
	
		
			
				|  |  | -  for (i=0; i < (unsigned)smartlist_len(sl); i++) {
 | 
	
		
			
				|  |  | -    tmp += bandwidths[i];
 | 
	
		
			
				|  |  | -    if (tmp >= rand_bw && !i_has_been_chosen) {
 | 
	
		
			
				|  |  | -      i_chosen = i;
 | 
	
		
			
				|  |  | -      i_has_been_chosen = 1;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  i = i_chosen;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (i == (unsigned)smartlist_len(sl)) {
 | 
	
		
			
				|  |  | -    /* This was once possible due to round-off error, but shouldn't be able
 | 
	
		
			
				|  |  | -     * to occur any longer. */
 | 
	
		
			
				|  |  | -    tor_fragile_assert();
 | 
	
		
			
				|  |  | -    --i;
 | 
	
		
			
				|  |  | -    log_warn(LD_BUG, "Round-off error in computing bandwidth had an effect on "
 | 
	
		
			
				|  |  | -             " which router we chose. Please tell the developers. "
 | 
	
		
			
				|  |  | -             "%f " U64_FORMAT " %f", tmp, U64_PRINTF_ARG(rand_bw),
 | 
	
		
			
				|  |  | -             weighted_bw);
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    int idx = choose_array_element_by_weight(bandwidths,
 | 
	
		
			
				|  |  | +                                             smartlist_len(sl));
 | 
	
		
			
				|  |  | +    tor_free(bandwidths);
 | 
	
		
			
				|  |  | +    return idx < 0 ? NULL : smartlist_get(sl, idx);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  tor_free(bandwidths);
 | 
	
		
			
				|  |  | -  return smartlist_get(sl, i);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** Helper function:
 | 
	
	
		
			
				|  | @@ -1912,17 +1952,16 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |                                     bandwidth_weight_rule_t rule)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    unsigned int i;
 | 
	
		
			
				|  |  | -  unsigned int i_chosen;
 | 
	
		
			
				|  |  | -  unsigned int i_has_been_chosen;
 | 
	
		
			
				|  |  | -  int32_t *bandwidths;
 | 
	
		
			
				|  |  | +  u64_dbl_t *bandwidths;
 | 
	
		
			
				|  |  |    int is_exit;
 | 
	
		
			
				|  |  |    int is_guard;
 | 
	
		
			
				|  |  | -  uint64_t total_nonexit_bw = 0, total_exit_bw = 0, total_bw = 0;
 | 
	
		
			
				|  |  | -  uint64_t total_nonguard_bw = 0, total_guard_bw = 0;
 | 
	
		
			
				|  |  | -  uint64_t rand_bw, tmp;
 | 
	
		
			
				|  |  | +  int is_fast;
 | 
	
		
			
				|  |  | +  double total_nonexit_bw = 0, total_exit_bw = 0;
 | 
	
		
			
				|  |  | +  double total_nonguard_bw = 0, total_guard_bw = 0;
 | 
	
		
			
				|  |  |    double exit_weight;
 | 
	
		
			
				|  |  |    double guard_weight;
 | 
	
		
			
				|  |  |    int n_unknown = 0;
 | 
	
		
			
				|  |  | +  bitarray_t *fast_bits;
 | 
	
		
			
				|  |  |    bitarray_t *exit_bits;
 | 
	
		
			
				|  |  |    bitarray_t *guard_bits;
 | 
	
		
			
				|  |  |    int me_idx = -1;
 | 
	
	
		
			
				|  | @@ -1946,10 +1985,9 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* First count the total bandwidth weight, and make a list
 | 
	
		
			
				|  |  | -   * of each value.  <0 means "unknown; no routerinfo."  We use the
 | 
	
		
			
				|  |  | -   * bits of negative values to remember whether the router was fast (-x)&1
 | 
	
		
			
				|  |  | -   * and whether it was an exit (-x)&2 or guard (-x)&4.  Yes, it's a hack. */
 | 
	
		
			
				|  |  | -  bandwidths = tor_malloc(sizeof(int32_t)*smartlist_len(sl));
 | 
	
		
			
				|  |  | +   * of each value.  We use UINT64_MAX to indicate "unknown". */
 | 
	
		
			
				|  |  | +  bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl));
 | 
	
		
			
				|  |  | +  fast_bits = bitarray_init_zero(smartlist_len(sl));
 | 
	
		
			
				|  |  |    exit_bits = bitarray_init_zero(smartlist_len(sl));
 | 
	
		
			
				|  |  |    guard_bits = bitarray_init_zero(smartlist_len(sl));
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1957,7 +1995,6 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |    SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
 | 
	
		
			
				|  |  |      /* first, learn what bandwidth we think i has */
 | 
	
		
			
				|  |  |      int is_known = 1;
 | 
	
		
			
				|  |  | -    int32_t flags = 0;
 | 
	
		
			
				|  |  |      uint32_t this_bw = 0;
 | 
	
		
			
				|  |  |      i = node_sl_idx;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1970,12 +2007,7 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |        if (node->rs->has_bandwidth) {
 | 
	
		
			
				|  |  |          this_bw = kb_to_bytes(node->rs->bandwidth);
 | 
	
		
			
				|  |  |        } else { /* guess */
 | 
	
		
			
				|  |  | -        /* XXX024 once consensuses always list bandwidths, we can take
 | 
	
		
			
				|  |  | -         * this guessing business out. -RD */
 | 
	
		
			
				|  |  |          is_known = 0;
 | 
	
		
			
				|  |  | -        flags = node->rs->is_fast ? 1 : 0;
 | 
	
		
			
				|  |  | -        flags |= is_exit ? 2 : 0;
 | 
	
		
			
				|  |  | -        flags |= is_guard ? 4 : 0;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      } else if (node->ri) {
 | 
	
		
			
				|  |  |        /* Must be a bridge if we're willing to use it */
 | 
	
	
		
			
				|  | @@ -1986,12 +2018,11 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |        bitarray_set(exit_bits, i);
 | 
	
		
			
				|  |  |      if (is_guard)
 | 
	
		
			
				|  |  |        bitarray_set(guard_bits, i);
 | 
	
		
			
				|  |  | +    if (node->is_fast)
 | 
	
		
			
				|  |  | +      bitarray_set(fast_bits, i);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (is_known) {
 | 
	
		
			
				|  |  | -      bandwidths[i] = (int32_t) this_bw;
 | 
	
		
			
				|  |  | -      /* Casting this_bw to int32_t is safe because both kb_to_bytes
 | 
	
		
			
				|  |  | -         and bridge_get_advertised_bandwidth_bounded limit it to below
 | 
	
		
			
				|  |  | -         INT32_MAX. */
 | 
	
		
			
				|  |  | -      tor_assert(bandwidths[i] >= 0);
 | 
	
		
			
				|  |  | +      bandwidths[i].dbl = this_bw;
 | 
	
		
			
				|  |  |        if (is_guard)
 | 
	
		
			
				|  |  |          total_guard_bw += this_bw;
 | 
	
		
			
				|  |  |        else
 | 
	
	
		
			
				|  | @@ -2002,14 +2033,16 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |          total_nonexit_bw += this_bw;
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        ++n_unknown;
 | 
	
		
			
				|  |  | -      bandwidths[node_sl_idx] = -flags;
 | 
	
		
			
				|  |  | +      bandwidths[i].dbl = -1.0;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    } SMARTLIST_FOREACH_END(node);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define EPSILON .1
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    /* Now, fill in the unknown values. */
 | 
	
		
			
				|  |  |    if (n_unknown) {
 | 
	
		
			
				|  |  |      int32_t avg_fast, avg_slow;
 | 
	
		
			
				|  |  | -    if (total_exit_bw+total_nonexit_bw) {
 | 
	
		
			
				|  |  | +    if (total_exit_bw+total_nonexit_bw < EPSILON) {
 | 
	
		
			
				|  |  |        /* if there's some bandwidth, there's at least one known router,
 | 
	
		
			
				|  |  |         * so no worries about div by 0 here */
 | 
	
		
			
				|  |  |        int n_known = smartlist_len(sl)-n_unknown;
 | 
	
	
		
			
				|  | @@ -2020,26 +2053,27 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |        avg_slow = 20000;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      for (i=0; i<(unsigned)smartlist_len(sl); ++i) {
 | 
	
		
			
				|  |  | -      int32_t bw = bandwidths[i];
 | 
	
		
			
				|  |  | -      if (bw>=0)
 | 
	
		
			
				|  |  | +      if (bandwidths[i].dbl >= 0.0)
 | 
	
		
			
				|  |  |          continue;
 | 
	
		
			
				|  |  | -      is_exit = ((-bw)&2);
 | 
	
		
			
				|  |  | -      is_guard = ((-bw)&4);
 | 
	
		
			
				|  |  | -      bandwidths[i] = ((-bw)&1) ? avg_fast : avg_slow;
 | 
	
		
			
				|  |  | +      is_fast = bitarray_is_set(fast_bits, i);
 | 
	
		
			
				|  |  | +      is_exit = bitarray_is_set(exit_bits, i);
 | 
	
		
			
				|  |  | +      is_guard = bitarray_is_set(guard_bits, i);
 | 
	
		
			
				|  |  | +      bandwidths[i].dbl = is_fast ? avg_fast : avg_slow;
 | 
	
		
			
				|  |  |        if (is_exit)
 | 
	
		
			
				|  |  | -        total_exit_bw += bandwidths[i];
 | 
	
		
			
				|  |  | +        total_exit_bw += bandwidths[i].dbl;
 | 
	
		
			
				|  |  |        else
 | 
	
		
			
				|  |  | -        total_nonexit_bw += bandwidths[i];
 | 
	
		
			
				|  |  | +        total_nonexit_bw += bandwidths[i].dbl;
 | 
	
		
			
				|  |  |        if (is_guard)
 | 
	
		
			
				|  |  | -        total_guard_bw += bandwidths[i];
 | 
	
		
			
				|  |  | +        total_guard_bw += bandwidths[i].dbl;
 | 
	
		
			
				|  |  |        else
 | 
	
		
			
				|  |  | -        total_nonguard_bw += bandwidths[i];
 | 
	
		
			
				|  |  | +        total_nonguard_bw += bandwidths[i].dbl;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* If there's no bandwidth at all, pick at random. */
 | 
	
		
			
				|  |  | -  if (!(total_exit_bw+total_nonexit_bw)) {
 | 
	
		
			
				|  |  | +  if (total_exit_bw+total_nonexit_bw < EPSILON) {
 | 
	
		
			
				|  |  |      tor_free(bandwidths);
 | 
	
		
			
				|  |  | +    tor_free(fast_bits);
 | 
	
		
			
				|  |  |      tor_free(exit_bits);
 | 
	
		
			
				|  |  |      tor_free(guard_bits);
 | 
	
		
			
				|  |  |      return smartlist_choose(sl);
 | 
	
	
		
			
				|  | @@ -2054,12 +2088,12 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |       * For detailed derivation of this formula, see
 | 
	
		
			
				|  |  |       *   http://archives.seul.org/or/dev/Jul-2007/msg00056.html
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | -    if (rule == WEIGHT_FOR_EXIT || !total_exit_bw)
 | 
	
		
			
				|  |  | +    if (rule == WEIGHT_FOR_EXIT || total_exit_bw<EPSILON)
 | 
	
		
			
				|  |  |        exit_weight = 1.0;
 | 
	
		
			
				|  |  |      else
 | 
	
		
			
				|  |  |        exit_weight = 1.0 - all_bw/(3.0*exit_bw);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (rule == WEIGHT_FOR_GUARD || !total_guard_bw)
 | 
	
		
			
				|  |  | +    if (rule == WEIGHT_FOR_GUARD || total_guard_bw<EPSILON)
 | 
	
		
			
				|  |  |        guard_weight = 1.0;
 | 
	
		
			
				|  |  |      else
 | 
	
		
			
				|  |  |        guard_weight = 1.0 - all_bw/(3.0*guard_bw);
 | 
	
	
		
			
				|  | @@ -2070,29 +2104,25 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |      if (guard_weight <= 0.0)
 | 
	
		
			
				|  |  |        guard_weight = 0.0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    total_bw = 0;
 | 
	
		
			
				|  |  |      sl_last_weighted_bw_of_me = 0;
 | 
	
		
			
				|  |  |      for (i=0; i < (unsigned)smartlist_len(sl); i++) {
 | 
	
		
			
				|  |  | -      uint64_t bw;
 | 
	
		
			
				|  |  | +      tor_assert(bandwidths[i].dbl >= 0.0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        is_exit = bitarray_is_set(exit_bits, i);
 | 
	
		
			
				|  |  |        is_guard = bitarray_is_set(guard_bits, i);
 | 
	
		
			
				|  |  |        if (is_exit && is_guard)
 | 
	
		
			
				|  |  | -        bw = ((uint64_t)(bandwidths[i] * exit_weight * guard_weight));
 | 
	
		
			
				|  |  | +        bandwidths[i].dbl *= exit_weight * guard_weight;
 | 
	
		
			
				|  |  |        else if (is_guard)
 | 
	
		
			
				|  |  | -        bw = ((uint64_t)(bandwidths[i] * guard_weight));
 | 
	
		
			
				|  |  | +        bandwidths[i].dbl *= guard_weight;
 | 
	
		
			
				|  |  |        else if (is_exit)
 | 
	
		
			
				|  |  | -        bw = ((uint64_t)(bandwidths[i] * exit_weight));
 | 
	
		
			
				|  |  | -      else
 | 
	
		
			
				|  |  | -        bw = bandwidths[i];
 | 
	
		
			
				|  |  | -      total_bw += bw;
 | 
	
		
			
				|  |  | +        bandwidths[i].dbl *= exit_weight;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        if (i == (unsigned) me_idx)
 | 
	
		
			
				|  |  | -        sl_last_weighted_bw_of_me = bw;
 | 
	
		
			
				|  |  | +        sl_last_weighted_bw_of_me = (uint64_t) bandwidths[i].dbl;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* XXXX this is a kludge to expose these values. */
 | 
	
		
			
				|  |  | -  sl_last_total_weighted_bw = total_bw;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +#if 0
 | 
	
		
			
				|  |  |    log_debug(LD_CIRC, "Total weighted bw = "U64_FORMAT
 | 
	
		
			
				|  |  |              ", exit bw = "U64_FORMAT
 | 
	
		
			
				|  |  |              ", nonexit bw = "U64_FORMAT", exit weight = %f "
 | 
	
	
		
			
				|  | @@ -2105,50 +2135,20 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
 | 
	
		
			
				|  |  |              exit_weight, (int)(rule == WEIGHT_FOR_EXIT),
 | 
	
		
			
				|  |  |              U64_PRINTF_ARG(total_guard_bw), U64_PRINTF_ARG(total_nonguard_bw),
 | 
	
		
			
				|  |  |              guard_weight, (int)(rule == WEIGHT_FOR_GUARD));
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* Almost done: choose a random value from the bandwidth weights. */
 | 
	
		
			
				|  |  | -  rand_bw = crypto_rand_uint64(total_bw);
 | 
	
		
			
				|  |  | -  rand_bw++; /* crypto_rand_uint64() counts from 0, and we need to count
 | 
	
		
			
				|  |  | -              * from 1 below. See bug 1203 for details. */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Last, count through sl until we get to the element we picked */
 | 
	
		
			
				|  |  | -  tmp = 0;
 | 
	
		
			
				|  |  | -  i_chosen = (unsigned)smartlist_len(sl);
 | 
	
		
			
				|  |  | -  i_has_been_chosen = 0;
 | 
	
		
			
				|  |  | -  for (i=0; i < (unsigned)smartlist_len(sl); i++) {
 | 
	
		
			
				|  |  | -    is_exit = bitarray_is_set(exit_bits, i);
 | 
	
		
			
				|  |  | -    is_guard = bitarray_is_set(guard_bits, i);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* Weights can be 0 if not counting guards/exits */
 | 
	
		
			
				|  |  | -    if (is_exit && is_guard)
 | 
	
		
			
				|  |  | -      tmp += ((uint64_t)(bandwidths[i] * exit_weight * guard_weight));
 | 
	
		
			
				|  |  | -    else if (is_guard)
 | 
	
		
			
				|  |  | -      tmp += ((uint64_t)(bandwidths[i] * guard_weight));
 | 
	
		
			
				|  |  | -    else if (is_exit)
 | 
	
		
			
				|  |  | -      tmp += ((uint64_t)(bandwidths[i] * exit_weight));
 | 
	
		
			
				|  |  | -    else
 | 
	
		
			
				|  |  | -      tmp += bandwidths[i];
 | 
	
		
			
				|  |  | +  scale_array_elements_to_u64(bandwidths, smartlist_len(sl),
 | 
	
		
			
				|  |  | +                              &sl_last_total_weighted_bw);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (tmp >= rand_bw && !i_has_been_chosen) {
 | 
	
		
			
				|  |  | -      i_chosen = i;
 | 
	
		
			
				|  |  | -      i_has_been_chosen = 1;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    int idx = choose_array_element_by_weight(bandwidths,
 | 
	
		
			
				|  |  | +                                             smartlist_len(sl));
 | 
	
		
			
				|  |  | +    tor_free(bandwidths);
 | 
	
		
			
				|  |  | +    tor_free(fast_bits);
 | 
	
		
			
				|  |  | +    tor_free(exit_bits);
 | 
	
		
			
				|  |  | +    tor_free(guard_bits);
 | 
	
		
			
				|  |  | +    return idx < 0 ? NULL : smartlist_get(sl, idx);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  i = i_chosen;
 | 
	
		
			
				|  |  | -  if (i == (unsigned)smartlist_len(sl)) {
 | 
	
		
			
				|  |  | -    /* This was once possible due to round-off error, but shouldn't be able
 | 
	
		
			
				|  |  | -     * to occur any longer. */
 | 
	
		
			
				|  |  | -    tor_fragile_assert();
 | 
	
		
			
				|  |  | -    --i;
 | 
	
		
			
				|  |  | -    log_warn(LD_BUG, "Round-off error in computing bandwidth had an effect on "
 | 
	
		
			
				|  |  | -             " which router we chose. Please tell the developers. "
 | 
	
		
			
				|  |  | -             U64_FORMAT " " U64_FORMAT " " U64_FORMAT, U64_PRINTF_ARG(tmp),
 | 
	
		
			
				|  |  | -             U64_PRINTF_ARG(rand_bw), U64_PRINTF_ARG(total_bw));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  tor_free(bandwidths);
 | 
	
		
			
				|  |  | -  tor_free(exit_bits);
 | 
	
		
			
				|  |  | -  tor_free(guard_bits);
 | 
	
		
			
				|  |  | -  return smartlist_get(sl, i);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** Choose a random element of status list <b>sl</b>, weighted by
 |