From 75c19716a80a96a7550dd723aca73c245987b87f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 7 Apr 2004 19:46:27 +0000 Subject: [PATCH] Put ourself in router list; act accordingly. svn:r1521 --- src/common/util.c | 29 +++++++++++++ src/common/util.h | 2 + src/or/connection_or.c | 2 +- src/or/onion.c | 58 +++++++++++++------------ src/or/or.h | 4 +- src/or/router.c | 21 ++++++--- src/or/routerlist.c | 96 +++++++++++++++++++++--------------------- src/or/test.c | 23 +++++++++- 8 files changed, 151 insertions(+), 84 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index 6df6853aba..f91d2ce061 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -293,10 +293,39 @@ void *smartlist_del(smartlist_t *sl, int idx) sl->list[idx] = sl->list[--sl->num_used]; return old; } +void *smartlist_del_keeporder(smartlist_t *sl, int idx) +{ + void *old; + assert(sl && idx>=0 && idx < sl->num_used); + old = sl->list[idx]; + --sl->num_used; + if (idx < sl->num_used) + memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx)); + return old; +} int smartlist_len(smartlist_t *sl) { return sl->num_used; } +void smartlist_insert(smartlist_t *sl, int idx, void *val) +{ + assert(sl && idx >= 0 && idx <= sl->num_used); + if (idx == sl->num_used) { + smartlist_add(sl, val); + } else { + /* Ensure sufficient capacity */ + if (sl->num_used >= sl->capacity) { + sl->capacity *= 2; + sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity); + } + /* Move other elements away */ + if (idx < sl->num_used) + memmove(sl->list + idx + 1, sl->list + idx, + sizeof(void*)*(sl->num_used-idx)); + sl->num_used++; + sl->list[idx] = val; + } +} /* * Splay-tree implementation of string-to-void* map diff --git a/src/common/util.h b/src/common/util.h index 0500b1fe1c..763de87952 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -113,6 +113,8 @@ void *smartlist_choose(smartlist_t *sl); void *smartlist_get(smartlist_t *sl, int idx); void *smartlist_set(smartlist_t *sl, int idx, void *val); void *smartlist_del(smartlist_t *sl, int idx); +void *smartlist_del_keeporder(smartlist_t *sl, int idx); +void smartlist_insert(smartlist_t *sl, int idx, void *val); int smartlist_len(smartlist_t *sl); #define SMARTLIST_FOREACH(sl, type, var, cmd) \ do { \ diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 45ac64f23e..1de668e639 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -96,7 +96,7 @@ connection_t *connection_or_connect(routerinfo_t *router) { assert(router); - if(options.Nickname && !strcmp(router->nickname,options.Nickname)) { + if(router_is_me(router)) { log_fn(LOG_WARN,"You asked me to connect to myself! Failing."); return NULL; } diff --git a/src/or/onion.c b/src/or/onion.c index 0185a47555..7d979d503e 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -12,7 +12,7 @@ void add_nickname_list_to_smartlist(smartlist_t *sl, char *list); extern or_options_t options; /* command-line and config-file options */ -static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len); +static int count_acceptable_routers(smartlist_t *routers); int decide_circ_id_type(char *local_nick, char *remote_nick) { int result; @@ -160,11 +160,11 @@ int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *key extern int has_fetched_directory; -static int new_route_len(double cw, routerinfo_t **rarray, int rarray_len) { +static int new_route_len(double cw, smartlist_t *routers) { int num_acceptable_routers; int routelen; - assert((cw >= 0) && (cw < 1) && rarray); /* valid parameters */ + assert((cw >= 0) && (cw < 1) && routers); /* valid parameters */ #ifdef TOR_PERF routelen = 2; @@ -177,9 +177,10 @@ static int new_route_len(double cw, routerinfo_t **rarray, int rarray_len) { break; } #endif - log_fn(LOG_DEBUG,"Chosen route length %d (%d routers available).",routelen, rarray_len); + log_fn(LOG_DEBUG,"Chosen route length %d (%d routers available).",routelen, + smartlist_len(routers)); - num_acceptable_routers = count_acceptable_routers(rarray, rarray_len); + num_acceptable_routers = count_acceptable_routers(routers); if(num_acceptable_routers < 2) { log_fn(LOG_INFO,"Not enough acceptable routers (%d). Discarding this circuit.", @@ -227,18 +228,19 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) * router (n_supported[i]). (We can't be sure about cases where we * don't know the IP address of the pending connection.) */ - n_supported = tor_malloc(sizeof(int)*dir->n_routers); - for (i = 0; i < dir->n_routers; ++i) { /* iterate over routers */ - if(!dir->routers[i]->is_running) { + n_supported = tor_malloc(sizeof(int)*smartlist_len(dir->routers)); + for (i = 0; i < smartlist_len(dir->routers); ++i) { /* iterate over routers */ + router = smartlist_get(dir->routers, i); + if(!router->is_running) { n_supported[i] = -1; log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- directory says it's not running.", - dir->routers[i]->nickname, i); + router->nickname, i); continue; /* skip routers that are known to be down */ } - if(router_exit_policy_rejects_all(dir->routers[i])) { + if(router_exit_policy_rejects_all(router)) { n_supported[i] = -1; log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- it rejects all.", - dir->routers[i]->nickname, i); + router->nickname, i); continue; /* skip routers that reject all */ } n_supported[i] = 0; @@ -248,17 +250,17 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) carray[j]->marked_for_close || circuit_stream_is_being_handled(carray[j])) continue; /* Skip everything but APs in CIRCUIT_WAIT */ - switch (connection_ap_can_use_exit(carray[j], dir->routers[i])) + switch (connection_ap_can_use_exit(carray[j], router)) { case ADDR_POLICY_REJECTED: log_fn(LOG_DEBUG,"%s (index %d) would reject this stream.", - dir->routers[i]->nickname, i); + router->nickname, i); break; /* would be rejected; try next connection */ case ADDR_POLICY_ACCEPTED: case ADDR_POLICY_UNKNOWN: ++n_supported[i]; log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.", - dir->routers[i]->nickname, i, n_supported[i]); + router->nickname, i, n_supported[i]); } } /* End looping over connections. */ if (n_supported[i] > best_support) { @@ -266,7 +268,7 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) * and goodness, and start counting how many routers are this good. */ best_support = n_supported[i]; n_best_support=1; log_fn(LOG_DEBUG,"%s is new best supported option so far.", - dir->routers[i]->nickname); + router->nickname); } else if (n_supported[i] == best_support) { /* If this router is _as good_ as the best one, just increment the * count of equally good routers.*/ @@ -287,9 +289,9 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) /* If any routers definitely support any pending connections, choose one * at random. */ if (best_support > 0) { - for (i = 0; i < dir->n_routers; i++) + for (i = 0; i < smartlist_len(dir->routers); i++) if (n_supported[i] == best_support) - smartlist_add(sl, dir->routers[i]); + smartlist_add(sl, smartlist_get(dir->routers, i)); smartlist_subtract(sl,excludedexits); if (smartlist_overlap(sl,preferredexits)) @@ -301,9 +303,9 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) if (best_support == -1) { log(LOG_WARN, "All routers are down or middleman -- choosing a doomed exit at random."); } - for(i = 0; i < dir->n_routers; i++) + for(i = 0; i < smartlist_len(dir->routers); i++) if(n_supported[i] != -1) - smartlist_add(sl, dir->routers[i]); + smartlist_add(sl, smartlist_get(dir->routers, i)); smartlist_subtract(sl,excludedexits); if (smartlist_overlap(sl,preferredexits)) @@ -339,7 +341,7 @@ cpath_build_state_t *onion_new_cpath_build_state(uint8_t purpose, routerinfo_t *exit; router_get_routerlist(&rl); - r = new_route_len(options.PathlenCoinWeight, rl->routers, rl->n_routers); + r = new_route_len(options.PathlenCoinWeight, rl->routers); if (r < 0) return NULL; info = tor_malloc_zero(sizeof(cpath_build_state_t)); @@ -359,26 +361,30 @@ cpath_build_state_t *onion_new_cpath_build_state(uint8_t purpose, return info; } -static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) { - int i, j; +static int count_acceptable_routers(smartlist_t *routers) { + int i, j, n; int num=0; connection_t *conn; + routerinfo_t *r, *r2; - for(i=0;iis_running == 0) { + r = smartlist_get(routers, i); + if(r->is_running == 0) { log_fn(LOG_DEBUG,"Nope, the directory says %d is not running.",i); goto next_i_loop; } if(options.ORPort) { - conn = connection_exact_get_by_addr_port(rarray[i]->addr, rarray[i]->or_port); + conn = connection_exact_get_by_addr_port(r->addr, r->or_port); if(!conn || conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN) { log_fn(LOG_DEBUG,"Nope, %d is not connected.",i); goto next_i_loop; } } for(j=0;jonion_pkey, rarray[j]->onion_pkey)) { + r2 = smartlist_get(routers, j); + if(!crypto_pk_cmp_keys(r->onion_pkey, r2->onion_pkey)) { /* these guys are twins. so we've already counted him. */ log_fn(LOG_DEBUG,"Nope, %d is a twin of %d.",i,j); goto next_i_loop; diff --git a/src/or/or.h b/src/or/or.h index aa5f308bdf..0a0b08591f 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -469,8 +469,7 @@ typedef struct { #define MAX_ROUTERS_IN_DIR 1024 typedef struct { - routerinfo_t **routers; - int n_routers; + smartlist_t *routers; char *software_versions; time_t published_on; } routerlist_t; @@ -980,6 +979,7 @@ void router_post_to_dirservers(uint8_t purpose, const char *payload, int payload int router_compare_to_my_exit_policy(connection_t *conn); routerinfo_t *router_get_my_routerinfo(void); const char *router_get_my_descriptor(void); +int router_is_me(routerinfo_t *router); int router_rebuild_descriptor(void); int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, crypto_pk_env_t *ident_key); diff --git a/src/or/router.c b/src/or/router.c index 42168bf495..ead4162f58 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -226,8 +226,10 @@ void router_retry_connections(void) { routerlist_t *rl; router_get_routerlist(&rl); - for (i=0;in_routers;i++) { - router = rl->routers[i]; + for (i=0;i < smartlist_len(rl->routers);i++) { + router = smartlist_get(rl->routers, i); + if(router_is_me(router)) + continue; if(!connection_exact_get_by_addr_port(router->addr,router->or_port)) { /* not in the list */ log_fn(LOG_DEBUG,"connecting to OR %s:%u.",router->address,router->or_port); @@ -256,8 +258,8 @@ void router_post_to_dirservers(uint8_t purpose, const char *payload, int payload if(!rl) return; - for(i=0;in_routers;i++) { - router = rl->routers[i]; + for(i=0; i < smartlist_len(rl->routers); i++) { + router = smartlist_get(rl->routers, i); if(router->dir_port > 0) directory_initiate_command(router, purpose, payload, payload_len); } @@ -310,16 +312,23 @@ static void router_add_exit_policy_from_config(routerinfo_t *router) { /* Return false if my exit policy says to allow connection to conn. * Else return true. */ -int router_compare_to_my_exit_policy(connection_t *conn) { +int router_compare_to_my_exit_policy(connection_t *conn) +{ assert(desc_routerinfo); assert(conn->addr); /* make sure it's resolved to something. this way we can't get a 'maybe' below. */ - return router_compare_addr_to_exit_policy(conn->addr, conn->port, + return router_compare_addr_to_exit_policy(conn->addr, conn->port, desc_routerinfo->exit_policy); } +int router_is_me(routerinfo_t *router) +{ + assert(router); + return options.Nickname && !strcasecmp(router->nickname, options.Nickname); +} + routerinfo_t *router_get_my_routerinfo(void) { if (!options.ORPort) diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 526559c9f3..e7f8cbce0f 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -98,7 +98,7 @@ static struct { { "ports", K_PORTS, ARGS, NO_OBJ, RTR_ONLY }, { "bandwidth", K_BANDWIDTH, ARGS, NO_OBJ, RTR_ONLY }, { "opt", K_OPT, CONCAT_ARGS, OBJ_OK, ANY }, - + { NULL, -1 } }; @@ -165,8 +165,8 @@ static routerinfo_t *router_pick_directory_server_impl(void) { return NULL; sl = smartlist_create(); - for(i=0;in_routers;i++) { - router = routerlist->routers[i]; + for(i=0;i< smartlist_len(routerlist->routers); i++) { + router = smartlist_get(routerlist->routers, i); if(router->dir_port > 0 && router->is_running) smartlist_add(sl, router); } @@ -179,8 +179,8 @@ static routerinfo_t *router_pick_directory_server_impl(void) { log_fn(LOG_INFO,"No dirservers are reachable. Trying them all again."); /* no running dir servers found? go through and mark them all as up, * and we'll cycle through the list again. */ - for(i=0;in_routers;i++) { - router = routerlist->routers[i]; + for(i=0; i < smartlist_len(routerlist->routers); i++) { + router = smartlist_get(routerlist->routers, i); if(router->dir_port > 0) { router->is_running = 1; dirserver = router; @@ -227,8 +227,8 @@ void router_add_running_routers_to_smartlist(smartlist_t *sl) { if(!routerlist) return; - for(i=0;in_routers;i++) { - router = routerlist->routers[i]; + for(i=0;irouters);i++) { + router = smartlist_get(routerlist->routers, i); if(router->is_running && (!options.ORPort || connection_twin_get_by_addr_port(router->addr, router->or_port) )) @@ -279,8 +279,8 @@ routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) { assert(routerlist); - for(i=0;in_routers;i++) { - router = routerlist->routers[i]; + for(i=0;irouters);i++) { + router = smartlist_get(routerlist->routers, i); if ((router->addr == addr) && (router->or_port == port)) return router; } @@ -294,8 +294,8 @@ routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk) assert(routerlist); - for(i=0;in_routers;i++) { - router = routerlist->routers[i]; + for(i=0;irouters);i++) { + router = smartlist_get(routerlist->routers, i); if (0 == crypto_pk_cmp_keys(router->link_pkey, pk)) return router; } @@ -309,14 +309,11 @@ routerinfo_t *router_get_by_nickname(char *nickname) assert(routerlist); - for(i=0;in_routers;i++) { - router = routerlist->routers[i]; + for(i=0;irouters);i++) { + router = smartlist_get(routerlist->routers, i); if (0 == strcasecmp(router->nickname, nickname)) return router; } - router = router_get_my_routerinfo(); - if (router && 0 == strcasecmp(router->nickname, nickname)) - return router; return NULL; } @@ -353,12 +350,12 @@ void routerinfo_free(routerinfo_t *router) static void routerlist_free(routerlist_t *rl) { - int i; - for (i = 0; i < rl->n_routers; ++i) - routerinfo_free(rl->routers[i]); + SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, + routerinfo_free(r)); + smartlist_free(rl->routers); tor_free(rl->routers); tor_free(rl->software_versions); - free(rl); + tor_free(rl); } void router_mark_as_down(char *nickname) { @@ -494,30 +491,35 @@ router_resolve(routerinfo_t *router) return 0; } -/* Helper function: resolve every router in rl. */ +/* Helper function: resolve every router in rl, and ensure that our own + * routerinfo is at the front. + */ static int router_resolve_routerlist(routerlist_t *rl) { - int i, max, remove; + int i, remove; + routerinfo_t *r; if (!rl) rl = routerlist; - max = rl->n_routers; - for (i = 0; i < max; ++i) { + i = 0; + if ((r = router_get_my_routerinfo())) { + smartlist_insert(rl->routers, 0, r); + ++i; + } + + for ( ; i < smartlist_len(rl->routers); ++i) { remove = 0; - if (router_resolve(rl->routers[i])) { - log_fn(LOG_WARN, "Couldn't resolve router %s; not using", - rl->routers[i]->address); + r = smartlist_get(rl->routers,i); + if (router_is_me(r)) { remove = 1; - } else if (options.Nickname && - !strcmp(rl->routers[i]->nickname, options.Nickname)) { + } else if (router_resolve(r)) { + log_fn(LOG_WARN, "Couldn't resolve router %s; not using", r->address); remove = 1; } if (remove) { - routerinfo_free(rl->routers[i]); - rl->routers[i] = rl->routers[--max]; - --rl->n_routers; - --i; + routerinfo_free(r); + smartlist_del_keeporder(rl->routers, i--); } } @@ -595,8 +597,8 @@ int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port) { int i; routerinfo_t *router; - for (i=0;in_routers;i++) { - router = routerlist->routers[i]; + for (i=0;irouters);i++) { + router = smartlist_get(routerlist->routers, i); if (router->is_running && router_compare_addr_to_exit_policy( addr, port, router->exit_policy) != ADDR_POLICY_REJECTED) return 0; /* this one could be ok. good enough. */ @@ -801,15 +803,14 @@ router_get_list_from_string_impl(const char **s, routerlist_t **dest, const char **good_nickname_lst) { routerinfo_t *router; - routerinfo_t **rarray; + smartlist_t *routers; int rarray_len = 0; int i; const char *end; assert(s && *s); - rarray = (routerinfo_t **) - tor_malloc((sizeof(routerinfo_t *))*MAX_ROUTERS_IN_DIR); + routers = smartlist_create(); while (1) { *s = eat_whitespace(*s); @@ -842,15 +843,14 @@ router_get_list_from_string_impl(const char **s, routerlist_t **dest, } else { router->is_running = 1; /* start out assuming all dirservers are up */ } - rarray[rarray_len++] = router; + smartlist_add(routers, router); log_fn(LOG_DEBUG,"just added router #%d.",rarray_len); } if (*dest) routerlist_free(*dest); - *dest = (routerlist_t *)tor_malloc(sizeof(routerlist_t)); - (*dest)->routers = rarray; - (*dest)->n_routers = rarray_len; + *dest = tor_malloc(sizeof(routerlist_t)); + (*dest)->routers = routers; (*dest)->software_versions = NULL; return 0; } @@ -860,7 +860,7 @@ router_get_list_from_string_impl(const char **s, routerlist_t **dest, * *s so it points to just after the router it just read. * mallocs a new router and returns it if all goes well, else returns * NULL. - * + * * DOCDOC */ routerinfo_t *router_get_entry_from_string(const char *s, @@ -1288,7 +1288,7 @@ get_next_token(const char **s, where_syntax where) { i = 0; done = (*next == '\n'); allocated = 32; - tok->args = (char**)tor_malloc(sizeof(char*)*32); + tok->args = tor_malloc(sizeof(char*)*32); *s = eat_whitespace_no_nl(next); while (**s != '\n' && !done) { next = find_whitespace(*s); @@ -1296,7 +1296,7 @@ get_next_token(const char **s, where_syntax where) { done = 1; if (i == allocated) { allocated *= 2; - tok->args = (char**)tor_realloc(tok->args,sizeof(char*)*allocated); + tok->args = tor_realloc(tok->args,sizeof(char*)*allocated); } tok->args[i++] = tor_strndup(*s,next-*s); *s = eat_whitespace_no_nl(next+1); @@ -1308,7 +1308,7 @@ get_next_token(const char **s, where_syntax where) { next = strchr(*s, '\n'); if (!next) RET_ERR("Unexpected EOF"); - tok->args = (char**) tor_malloc(sizeof(char*)); + tok->args = tor_malloc(sizeof(char*)); tok->args[0] = tor_strndup(*s,next-*s); tok->n_args = 1; *s = eat_whitespace_no_nl(next+1); @@ -1330,8 +1330,8 @@ get_next_token(const char **s, where_syntax where) { next = strchr(*s, '\n'); if (!next) { RET_ERR("Unexpected EOF"); - } - tok->args = (char**) tor_malloc(sizeof(char*)); + } + tok->args = tor_malloc(sizeof(char*)); tok->args[0] = tor_strndup(*s,next-*s); tok->n_args = 1; *s = next+1; diff --git a/src/or/test.c b/src/or/test.c index 276636670f..11b5392535 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -456,6 +456,7 @@ void test_util() { struct timeval start, end; struct tm a_time; + smartlist_t *sl; start.tv_sec = 5; start.tv_usec = 5000; @@ -495,6 +496,26 @@ test_util() { a_time.tm_mon = 1; /* Try a leap year, in feb. */ a_time.tm_mday = 10; test_eq((time_t) 1076393695UL, tor_timegm(&a_time)); + + + /* Test smartlist */ + sl = smartlist_create(); + smartlist_add(sl, (void*)1); + smartlist_add(sl, (void*)2); + smartlist_add(sl, (void*)3); + smartlist_add(sl, (void*)4); + test_eq(2, (int)smartlist_del_keeporder(sl, 1)); + smartlist_insert(sl, 1, (void*)22); + smartlist_insert(sl, 0, (void*)0); + smartlist_insert(sl, 5, (void*)555); + test_eq(0, (int)smartlist_get(sl,0)); + test_eq(1, (int)smartlist_get(sl,1)); + test_eq(22, (int)smartlist_get(sl,2)); + test_eq(3, (int)smartlist_get(sl,3)); + test_eq(4, (int)smartlist_get(sl,4)); + test_eq(555, (int)smartlist_get(sl,5)); + /* XXXX test older functions. */ + smartlist_free(sl); } static void* _squareAndRemoveK4(const char *key, void*val, void *data) @@ -790,7 +811,7 @@ test_dir_format() test_assert(!dirserv_dump_directory_to_string(buf,8192,pk3)); cp = buf; test_assert(!router_get_routerlist_from_directory_impl(buf, &dir1, pk3)); - test_eq(2, dir1->n_routers); + test_eq(2, smartlist_len(dir1->routers)); dirserv_free_fingerprint_list(); tor_free(pk1_str);