summaryrefslogtreecommitdiff
path: root/src/or/circuitbuild.c
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2004-12-05 07:10:08 +0000
committerRoger Dingledine <arma@torproject.org>2004-12-05 07:10:08 +0000
commitef6c9d18e799e5b02505ba73bbf36bfe92ce5a8b (patch)
tree24e864902bc7196fb3e2ca1a39fc7463c2582d1c /src/or/circuitbuild.c
parent32e74d352500dc228a1de5d5bc97e219897ef09b (diff)
downloadtor-ef6c9d18e799e5b02505ba73bbf36bfe92ce5a8b.tar.gz
tor-ef6c9d18e799e5b02505ba73bbf36bfe92ce5a8b.zip
New circuit building strategy: keep a list of ports that we've used in the past 6 hours, and always try to have 2 circuits open or on the way
that will handle each such port. (We can extend this to include addresses if exit policies shift to require that.) Seed us with port 80 so web browsers won't complain that Tor is "slow to start up". This was necessary because our old circuit building strategy just involved counting circuits, and as time went by we would build up a big pile of circuits that had peculiar exit policies (e.g. only exit to 9001-9100) which would take up space in the circuit pile but never get used. Fix router_compare_addr_to_addr_policy: it was not treating a port of * as always matching, so we were picking reject *:* nodes as exit nodes too. If you haven't used a clean circuit in an hour, throw it away, just to be on the safe side. This means after 6 hours a totally unused Tor client will have no circuits open. svn:r3078
Diffstat (limited to 'src/or/circuitbuild.c')
-rw-r--r--src/or/circuitbuild.c87
1 files changed, 77 insertions, 10 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 43dccf7dbb..373f1c78a8 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -787,6 +787,56 @@ static int new_route_len(double cw, uint8_t purpose, smartlist_t *routers) {
return routelen;
}
+/** Fetch the list of predicted ports, turn it into a smartlist of
+ * strings, remove the ones that are already handled by an
+ * existing circuit, and return it.
+ */
+static smartlist_t *
+circuit_get_unhandled_ports(time_t now) {
+ char *pp = rep_hist_get_predicted_ports(now);
+ smartlist_t *needed_ports = smartlist_create();
+ smartlist_split_string(needed_ports, pp, " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ tor_free(pp);
+
+ circuit_remove_handled_ports(needed_ports);
+ return needed_ports;
+}
+
+/** Return 1 if we already have circuits present or on the way for
+ * all anticipated ports. Return 0 if we should make more.
+ */
+int
+circuit_all_predicted_ports_handled(time_t now) {
+ int enough;
+ smartlist_t *sl = circuit_get_unhandled_ports(now);
+ enough = (smartlist_len(sl) == 0);
+ smartlist_free(sl);
+ return enough;
+}
+
+/** Return 1 if <b>router</b> can handle one or more of the ports in
+ * <b>needed_ports</b>, else return 0.
+ */
+static int
+router_handles_some_port(routerinfo_t *router, smartlist_t *needed_ports) {
+ int i;
+ uint16_t port;
+
+ for (i = 0; i < smartlist_len(needed_ports); ++i) {
+ port = *(uint16_t *)smartlist_get(needed_ports, i);
+ tor_assert(port);
+ if (router_compare_addr_to_addr_policy(0, port, router->exit_policy) !=
+ ADDR_POLICY_REJECTED)
+ return 1;
+ }
+ return 0;
+}
+
+/** How many circuits do we want simultaneously in-progress to handle
+ * a given stream?
+ */
+#define MIN_CIRCUITS_HANDLING_STREAM 2
+
/** Return a pointer to a suitable router to be the exit node for the
* general-purpose circuit we're about to build.
*
@@ -820,7 +870,7 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir)
if (carray[i]->type == CONN_TYPE_AP &&
carray[i]->state == AP_CONN_STATE_CIRCUIT_WAIT &&
!carray[i]->marked_for_close &&
- !circuit_stream_is_being_handled(carray[i]))
+ !circuit_stream_is_being_handled(carray[i], 0, MIN_CIRCUITS_HANDLING_STREAM))
++n_pending_connections;
}
// log_fn(LOG_DEBUG, "Choosing exit node; %d connections are pending",
@@ -873,7 +923,7 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir)
if (carray[j]->type != CONN_TYPE_AP ||
carray[j]->state != AP_CONN_STATE_CIRCUIT_WAIT ||
carray[j]->marked_for_close ||
- circuit_stream_is_being_handled(carray[j]))
+ circuit_stream_is_being_handled(carray[j], 0, MIN_CIRCUITS_HANDLING_STREAM))
continue; /* Skip everything but APs in CIRCUIT_WAIT */
if (connection_ap_can_use_exit(carray[j], router)) {
++n_supported[i];
@@ -920,18 +970,35 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir)
router = routerlist_sl_choose_by_bandwidth(sl);
} else {
/* Either there are no pending connections, or no routers even seem to
- * possibly support any of them. Choose a router at random. */
+ * possibly support any of them. Choose a router at random that satisfies
+ * at least one predicted exit port. */
+
+ int try;
+ smartlist_t *needed_ports = circuit_get_unhandled_ports(time(NULL));
+
if (best_support == -1) {
log(LOG_WARN, "All routers are down or middleman -- choosing a doomed exit at random.");
}
- for (i = 0; i < smartlist_len(dir->routers); i++)
- if (n_supported[i] != -1)
- smartlist_add(sl, smartlist_get(dir->routers, i));
+ for (try = 0; try < 2; try++) {
+ /* try once to pick only from routers that satisfy a needed port,
+ * then if there are none, pick from any that support exiting. */
+ for (i = 0; i < smartlist_len(dir->routers); i++) {
+ router = smartlist_get(dir->routers, i);
+ if (n_supported[i] != -1 &&
+ (try || router_handles_some_port(router, needed_ports))) {
+ log_fn(LOG_DEBUG,"Try %d: '%s' is a possibility.", try, router->nickname);
+ smartlist_add(sl, router);
+ }
+ }
- smartlist_subtract(sl,excludedexits);
- if (options->StrictExitNodes || smartlist_overlap(sl,preferredexits))
- smartlist_intersect(sl,preferredexits);
- router = routerlist_sl_choose_by_bandwidth(sl);
+ smartlist_subtract(sl,excludedexits);
+ if (options->StrictExitNodes || smartlist_overlap(sl,preferredexits))
+ smartlist_intersect(sl,preferredexits);
+ router = routerlist_sl_choose_by_bandwidth(sl);
+ if (router)
+ break;
+ }
+ smartlist_free(needed_ports);
}
smartlist_free(preferredexits);