diff options
Diffstat (limited to 'src/or/routerlist.c')
-rw-r--r-- | src/or/routerlist.c | 73 |
1 files changed, 50 insertions, 23 deletions
diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 92cab57a09..b36fa82d53 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -884,46 +884,70 @@ router_get_advertised_bandwidth(routerinfo_t *router) * the advertised bandwidth of each router. */ routerinfo_t * -routerlist_sl_choose_by_bandwidth(smartlist_t *sl) +routerlist_sl_choose_by_bandwidth(smartlist_t *sl, int for_exit) { int i; routerinfo_t *router; - smartlist_t *bandwidths; - uint32_t this_bw, tmp, total_bw=0, rand_bw; - uint32_t *p; + uint32_t *bandwidths; + uint32_t this_bw; + uint64_t total_nonexit_bw = 0, total_exit_bw = 0, total_bw = 0; + uint64_t rand_bw, tmp; + double exit_weight; /* First count the total bandwidth weight, and make a smartlist * of each value. */ - bandwidths = smartlist_create(); + bandwidths = tor_malloc(sizeof(uint32_t)*smartlist_len(sl)); for (i = 0; i < smartlist_len(sl); ++i) { router = smartlist_get(sl, i); this_bw = router_get_advertised_bandwidth(router); /* if they claim something huge, don't believe it */ if (this_bw > MAX_BELIEVABLE_BANDWIDTH) this_bw = MAX_BELIEVABLE_BANDWIDTH; - p = tor_malloc(sizeof(uint32_t)); - *p = this_bw; - smartlist_add(bandwidths, p); - total_bw += this_bw; + bandwidths[i] = this_bw; + if (router->is_exit) + total_exit_bw += this_bw; + else + total_nonexit_bw += this_bw; } - if (!total_bw) { - SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p)); - smartlist_free(bandwidths); + if (!(total_exit_bw+total_nonexit_bw)) { + tor_free(bandwidths); return smartlist_choose(sl); } + if (for_exit) { + exit_weight = 1.0; + total_bw = total_exit_bw + total_nonexit_bw; + } else if (total_exit_bw < total_nonexit_bw / 2) { + exit_weight = 0.0; + total_bw = total_nonexit_bw; + } else { + uint64_t leftover = (total_exit_bw - total_nonexit_bw / 2); + exit_weight = U64_TO_DBL(leftover) / + U64_TO_DBL(leftover + total_nonexit_bw); + total_bw = total_nonexit_bw + + DBL_TO_U64(exit_weight * U64_TO_DBL(total_exit_bw)); + } + /* + log_debug(LD_CIRC, "Total bw = "U64_FORMAT", total exit bw = "U64_FORMAT + ", total nonexit bw = "U64_FORMAT", exit weight = %lf " + "(for exit == %d)", + U64_PRINTF_ARG(total_bw), U64_PRINTF_ARG(total_exit_bw), + U64_PRINTF_ARG(total_nonexit_bw), exit_weight, for_exit); + */ + /* Second, choose a random value from the bandwidth weights. */ - rand_bw = crypto_rand_int(total_bw); + rand_bw = crypto_rand_uint64(total_bw); /* Last, count through sl until we get to the element we picked */ tmp = 0; - for (i=0; ; i++) { - tor_assert(i < smartlist_len(sl)); - p = smartlist_get(bandwidths, i); - tmp += *p; + for (i=0; i < smartlist_len(sl); i++) { + router = smartlist_get(sl, i); + if (router->is_exit) + tmp += ((uint64_t)(bandwidths[i] * exit_weight)); + else + tmp += bandwidths[i]; if (tmp >= rand_bw) break; } - SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p)); - smartlist_free(bandwidths); + tor_free(bandwidths); return (routerinfo_t *)smartlist_get(sl, i); } @@ -944,7 +968,8 @@ router_choose_random_node(const char *preferred, smartlist_t *excludedsmartlist, int need_uptime, int need_capacity, int need_guard, - int allow_invalid, int strict) + int allow_invalid, int strict, + int weight_for_exit) { smartlist_t *sl, *excludednodes; routerinfo_t *choice = NULL; @@ -975,8 +1000,8 @@ router_choose_random_node(const char *preferred, smartlist_subtract(sl,excludedsmartlist); routerlist_sl_remove_unreliable_routers(sl, need_uptime, need_capacity, need_guard); - if (need_capacity) - choice = routerlist_sl_choose_by_bandwidth(sl); + if (need_capacity) /* XXXX Is this documented in path spec. -NM */ + choice = routerlist_sl_choose_by_bandwidth(sl, weight_for_exit); else choice = smartlist_choose(sl); smartlist_free(sl); @@ -989,7 +1014,8 @@ router_choose_random_node(const char *preferred, need_uptime?", stable":"", need_guard?", guard":""); choice = router_choose_random_node( - NULL, excluded, excludedsmartlist, 0, 0, 0, allow_invalid, 0); + NULL, excluded, excludedsmartlist, + 0, 0, 0, allow_invalid, 0, weight_for_exit); } } smartlist_free(excludednodes); @@ -3422,6 +3448,7 @@ routers_update_status_from_networkstatus(smartlist_t *routers, router->is_fast = rs->status.is_fast; router->is_stable = rs->status.is_stable; router->is_possible_guard = rs->status.is_possible_guard; + router->is_exit = rs->status.is_exit; } if (router->is_running && ds) { ds->n_networkstatus_failures = 0; |