|  | @@ -2030,9 +2030,10 @@ compute_weighted_bandwidths(const smartlist_t *sl,
 | 
	
		
			
				|  |  |    if (Wg < 0 || Wm < 0 || We < 0 || Wd < 0 || Wgb < 0 || Wmb < 0 || Wdb < 0
 | 
	
		
			
				|  |  |        || Web < 0) {
 | 
	
		
			
				|  |  |      log_debug(LD_CIRC,
 | 
	
		
			
				|  |  | -              "Got negative bandwidth weights. Defaulting to old selection"
 | 
	
		
			
				|  |  | +              "Got negative bandwidth weights. Defaulting to naive selection"
 | 
	
		
			
				|  |  |                " algorithm.");
 | 
	
		
			
				|  |  | -    return -1; // Use old algorithm.
 | 
	
		
			
				|  |  | +    Wg = Wm = We = Wd = weight_scale;
 | 
	
		
			
				|  |  | +    Wgb = Wmb = Web = Wdb = weight_scale;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    Wg /= weight_scale;
 | 
	
	
		
			
				|  | @@ -2048,6 +2049,7 @@ compute_weighted_bandwidths(const smartlist_t *sl,
 | 
	
		
			
				|  |  |    bandwidths = tor_calloc(smartlist_len(sl), sizeof(u64_dbl_t));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Cycle through smartlist and total the bandwidth.
 | 
	
		
			
				|  |  | +  static int warned_missing_bw = 0;
 | 
	
		
			
				|  |  |    SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
 | 
	
		
			
				|  |  |      int is_exit = 0, is_guard = 0, is_dir = 0, this_bw = 0;
 | 
	
		
			
				|  |  |      double weight = 1;
 | 
	
	
		
			
				|  | @@ -2056,15 +2058,18 @@ compute_weighted_bandwidths(const smartlist_t *sl,
 | 
	
		
			
				|  |  |      is_dir = node_is_dir(node);
 | 
	
		
			
				|  |  |      if (node->rs) {
 | 
	
		
			
				|  |  |        if (!node->rs->has_bandwidth) {
 | 
	
		
			
				|  |  | -        tor_free(bandwidths);
 | 
	
		
			
				|  |  |          /* This should never happen, unless all the authorites downgrade
 | 
	
		
			
				|  |  |           * to 0.2.0 or rogue routerstatuses get inserted into our consensus. */
 | 
	
		
			
				|  |  | -        log_warn(LD_BUG,
 | 
	
		
			
				|  |  | -                 "Consensus is not listing bandwidths. Defaulting back to "
 | 
	
		
			
				|  |  | -                 "old router selection algorithm.");
 | 
	
		
			
				|  |  | -        return -1;
 | 
	
		
			
				|  |  | +        if (! warned_missing_bw) {
 | 
	
		
			
				|  |  | +          log_warn(LD_BUG,
 | 
	
		
			
				|  |  | +                 "Consensus is missing some bandwidths. Using a naive "
 | 
	
		
			
				|  |  | +                 "router selection algorithm");
 | 
	
		
			
				|  |  | +          warned_missing_bw = 1;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        this_bw = 30000; /* Chosen arbitrarily */
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        this_bw = kb_to_bytes(node->rs->bandwidth_kb);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      this_bw = kb_to_bytes(node->rs->bandwidth_kb);
 | 
	
		
			
				|  |  |      } else if (node->ri) {
 | 
	
		
			
				|  |  |        /* bridge or other descriptor not in our consensus */
 | 
	
		
			
				|  |  |        this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
 | 
	
	
		
			
				|  | @@ -2141,226 +2146,13 @@ frac_nodes_with_descriptors(const smartlist_t *sl,
 | 
	
		
			
				|  |  |    return present / total;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/** Helper function:
 | 
	
		
			
				|  |  | - * choose a random node_t element of smartlist <b>sl</b>, weighted by
 | 
	
		
			
				|  |  | - * the advertised bandwidth of each element.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * If <b>rule</b>==WEIGHT_FOR_EXIT. we're picking an exit node: consider all
 | 
	
		
			
				|  |  | - * nodes' bandwidth equally regardless of their Exit status, since there may
 | 
	
		
			
				|  |  | - * be some in the list because they exit to obscure ports. If
 | 
	
		
			
				|  |  | - * <b>rule</b>==NO_WEIGHTING, we're picking a non-exit node: weight
 | 
	
		
			
				|  |  | - * exit-node's bandwidth less depending on the smallness of the fraction of
 | 
	
		
			
				|  |  | - * Exit-to-total bandwidth.  If <b>rule</b>==WEIGHT_FOR_GUARD, we're picking a
 | 
	
		
			
				|  |  | - * guard node: consider all guard's bandwidth equally. Otherwise, weight
 | 
	
		
			
				|  |  | - * guards proportionally less.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -static const node_t *
 | 
	
		
			
				|  |  | -smartlist_choose_node_by_bandwidth(const smartlist_t *sl,
 | 
	
		
			
				|  |  | -                                   bandwidth_weight_rule_t rule)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  unsigned int i;
 | 
	
		
			
				|  |  | -  u64_dbl_t *bandwidths;
 | 
	
		
			
				|  |  | -  int is_exit;
 | 
	
		
			
				|  |  | -  int is_guard;
 | 
	
		
			
				|  |  | -  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;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // This function does not support WEIGHT_FOR_DIR
 | 
	
		
			
				|  |  | -  // or WEIGHT_FOR_MID
 | 
	
		
			
				|  |  | -  if (rule == WEIGHT_FOR_DIR || rule == WEIGHT_FOR_MID) {
 | 
	
		
			
				|  |  | -    rule = NO_WEIGHTING;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Can't choose exit and guard at same time */
 | 
	
		
			
				|  |  | -  tor_assert(rule == NO_WEIGHTING ||
 | 
	
		
			
				|  |  | -             rule == WEIGHT_FOR_EXIT ||
 | 
	
		
			
				|  |  | -             rule == WEIGHT_FOR_GUARD);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (smartlist_len(sl) == 0) {
 | 
	
		
			
				|  |  | -    log_info(LD_CIRC,
 | 
	
		
			
				|  |  | -             "Empty routerlist passed in to old node selection for rule %s",
 | 
	
		
			
				|  |  | -             bandwidth_weight_rule_to_string(rule));
 | 
	
		
			
				|  |  | -    return NULL;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* First count the total bandwidth weight, and make a list
 | 
	
		
			
				|  |  | -   * of each value.  We use UINT64_MAX to indicate "unknown". */
 | 
	
		
			
				|  |  | -  bandwidths = tor_calloc(smartlist_len(sl), sizeof(u64_dbl_t));
 | 
	
		
			
				|  |  | -  fast_bits = bitarray_init_zero(smartlist_len(sl));
 | 
	
		
			
				|  |  | -  exit_bits = bitarray_init_zero(smartlist_len(sl));
 | 
	
		
			
				|  |  | -  guard_bits = bitarray_init_zero(smartlist_len(sl));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Iterate over all the routerinfo_t or routerstatus_t, and */
 | 
	
		
			
				|  |  | -  SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
 | 
	
		
			
				|  |  | -    /* first, learn what bandwidth we think i has */
 | 
	
		
			
				|  |  | -    int is_known = 1;
 | 
	
		
			
				|  |  | -    uint32_t this_bw = 0;
 | 
	
		
			
				|  |  | -    i = node_sl_idx;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    is_exit = node_is_good_exit(node);
 | 
	
		
			
				|  |  | -    is_guard = node->is_possible_guard;
 | 
	
		
			
				|  |  | -    if (node->rs) {
 | 
	
		
			
				|  |  | -      if (node->rs->has_bandwidth) {
 | 
	
		
			
				|  |  | -        this_bw = kb_to_bytes(node->rs->bandwidth_kb);
 | 
	
		
			
				|  |  | -      } else { /* guess */
 | 
	
		
			
				|  |  | -        is_known = 0;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    } else if (node->ri) {
 | 
	
		
			
				|  |  | -      /* Must be a bridge if we're willing to use it */
 | 
	
		
			
				|  |  | -      this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (is_exit)
 | 
	
		
			
				|  |  | -      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].dbl = this_bw;
 | 
	
		
			
				|  |  | -      if (is_guard)
 | 
	
		
			
				|  |  | -        total_guard_bw += this_bw;
 | 
	
		
			
				|  |  | -      else
 | 
	
		
			
				|  |  | -        total_nonguard_bw += this_bw;
 | 
	
		
			
				|  |  | -      if (is_exit)
 | 
	
		
			
				|  |  | -        total_exit_bw += this_bw;
 | 
	
		
			
				|  |  | -      else
 | 
	
		
			
				|  |  | -        total_nonexit_bw += this_bw;
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      ++n_unknown;
 | 
	
		
			
				|  |  | -      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 < 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;
 | 
	
		
			
				|  |  | -      avg_fast = avg_slow = (int32_t)
 | 
	
		
			
				|  |  | -        ((total_exit_bw+total_nonexit_bw)/((uint64_t) n_known));
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      avg_fast = 40000;
 | 
	
		
			
				|  |  | -      avg_slow = 20000;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    for (i=0; i<(unsigned)smartlist_len(sl); ++i) {
 | 
	
		
			
				|  |  | -      if (bandwidths[i].dbl >= 0.0)
 | 
	
		
			
				|  |  | -        continue;
 | 
	
		
			
				|  |  | -      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].dbl;
 | 
	
		
			
				|  |  | -      else
 | 
	
		
			
				|  |  | -        total_nonexit_bw += bandwidths[i].dbl;
 | 
	
		
			
				|  |  | -      if (is_guard)
 | 
	
		
			
				|  |  | -        total_guard_bw += bandwidths[i].dbl;
 | 
	
		
			
				|  |  | -      else
 | 
	
		
			
				|  |  | -        total_nonguard_bw += bandwidths[i].dbl;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* If there's no bandwidth at all, pick at random. */
 | 
	
		
			
				|  |  | -  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);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Figure out how to weight exits and guards */
 | 
	
		
			
				|  |  | -  {
 | 
	
		
			
				|  |  | -    double all_bw = U64_TO_DBL(total_exit_bw+total_nonexit_bw);
 | 
	
		
			
				|  |  | -    double exit_bw = U64_TO_DBL(total_exit_bw);
 | 
	
		
			
				|  |  | -    double guard_bw = U64_TO_DBL(total_guard_bw);
 | 
	
		
			
				|  |  | -    /*
 | 
	
		
			
				|  |  | -     * 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<EPSILON)
 | 
	
		
			
				|  |  | -      exit_weight = 1.0;
 | 
	
		
			
				|  |  | -    else
 | 
	
		
			
				|  |  | -      exit_weight = 1.0 - all_bw/(3.0*exit_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);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (exit_weight <= 0.0)
 | 
	
		
			
				|  |  | -      exit_weight = 0.0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (guard_weight <= 0.0)
 | 
	
		
			
				|  |  | -      guard_weight = 0.0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    for (i=0; i < (unsigned)smartlist_len(sl); i++) {
 | 
	
		
			
				|  |  | -      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)
 | 
	
		
			
				|  |  | -        bandwidths[i].dbl *= exit_weight * guard_weight;
 | 
	
		
			
				|  |  | -      else if (is_guard)
 | 
	
		
			
				|  |  | -        bandwidths[i].dbl *= guard_weight;
 | 
	
		
			
				|  |  | -      else if (is_exit)
 | 
	
		
			
				|  |  | -        bandwidths[i].dbl *= exit_weight;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#if 0
 | 
	
		
			
				|  |  | -  log_debug(LD_CIRC, "Total weighted bw = "U64_FORMAT
 | 
	
		
			
				|  |  | -            ", exit bw = "U64_FORMAT
 | 
	
		
			
				|  |  | -            ", nonexit bw = "U64_FORMAT", exit weight = %f "
 | 
	
		
			
				|  |  | -            "(for exit == %d)"
 | 
	
		
			
				|  |  | -            ", guard bw = "U64_FORMAT
 | 
	
		
			
				|  |  | -            ", nonguard bw = "U64_FORMAT", guard weight = %f "
 | 
	
		
			
				|  |  | -            "(for guard == %d)",
 | 
	
		
			
				|  |  | -            U64_PRINTF_ARG(total_bw),
 | 
	
		
			
				|  |  | -            U64_PRINTF_ARG(total_exit_bw), U64_PRINTF_ARG(total_nonexit_bw),
 | 
	
		
			
				|  |  | -            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
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  scale_array_elements_to_u64(bandwidths, smartlist_len(sl), NULL);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  {
 | 
	
		
			
				|  |  | -    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);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /** Choose a random element of status list <b>sl</b>, weighted by
 | 
	
		
			
				|  |  |   * the advertised bandwidth of each node */
 | 
	
		
			
				|  |  |  const node_t *
 | 
	
		
			
				|  |  |  node_sl_choose_by_bandwidth(const smartlist_t *sl,
 | 
	
		
			
				|  |  |                              bandwidth_weight_rule_t rule)
 | 
	
		
			
				|  |  |  { /*XXXX MOVE */
 | 
	
		
			
				|  |  | -  const node_t *ret;
 | 
	
		
			
				|  |  | -  if ((ret = smartlist_choose_node_by_bandwidth_weights(sl, rule))) {
 | 
	
		
			
				|  |  | -    return ret;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    return smartlist_choose_node_by_bandwidth(sl, rule);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +  return smartlist_choose_node_by_bandwidth_weights(sl, rule);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** Return a random running node from the nodelist. Never
 |