diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/or/connection.c | 12 | ||||
-rw-r--r-- | src/or/directory.c | 4 | ||||
-rw-r--r-- | src/or/or.h | 1 | ||||
-rw-r--r-- | src/or/routerlist.c | 29 |
4 files changed, 38 insertions, 8 deletions
diff --git a/src/or/connection.c b/src/or/connection.c index 578466bae..0128cf93f 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -709,16 +709,20 @@ int connection_handle_read(connection_t *conn) { } if(connection_read_to_buf(conn) < 0) { + /* There's a read error; kill the connection.*/ + connection_close_immediate(conn); /* Don't flush; connection is dead. */ + conn->has_sent_end = 1; + connection_mark_for_close(conn); if(conn->type == CONN_TYPE_DIR && conn->state == DIR_CONN_STATE_CONNECTING) { /* it's a directory server and connecting failed: forget about this router */ /* XXX I suspect pollerr may make Windows not get to this point. :( */ router_mark_as_down(conn->identity_digest); + if(conn->purpose == DIR_PURPOSE_FETCH_DIR && !all_directory_servers_down()) { + log_fn(LOG_INFO,"Giving up on dirserver %s; trying another.", conn->nickname); + directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 0); + } } - /* There's a read error; kill the connection.*/ - connection_close_immediate(conn); /* Don't flush; connection is dead. */ - conn->has_sent_end = 1; - connection_mark_for_close(conn); return -1; } if(connection_process_inbuf(conn) < 0) { diff --git a/src/or/directory.c b/src/or/directory.c index 432c704f7..042f3851d 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -150,6 +150,10 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose, switch(connection_connect(conn, conn->address, conn->addr, conn->port)) { case -1: router_mark_as_down(conn->identity_digest); /* don't try him again */ + if(purpose == DIR_PURPOSE_FETCH_DIR && !all_directory_servers_down) { + log_fn(LOG_INFO,"Giving up on dirserver %s; trying another.", conn->nickname); + directory_get_from_dirserver(purpose, payload, payload_len); + } connection_free(conn); return; case 1: diff --git a/src/or/or.h b/src/or/or.h index 47cb4c9f0..ac72b3322 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1348,6 +1348,7 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, /********************************* routerlist.c ***************************/ routerinfo_t *router_pick_directory_server(void); +int all_directory_servers_down(void); struct smartlist_t; void add_nickname_list_to_smartlist(struct smartlist_t *sl, const char *list); void router_add_running_routers_to_smartlist(struct smartlist_t *sl); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 7874b1075..ea89a9ab7 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -62,7 +62,7 @@ routerinfo_t *router_pick_directory_server(void) { * routerlist. */ static routerinfo_t *router_pick_directory_server_impl(void) { int i; - routerinfo_t *router, *dirserver=NULL; + routerinfo_t *router; smartlist_t *sl; if(!routerlist) @@ -87,17 +87,38 @@ static routerinfo_t *router_pick_directory_server_impl(void) { /* No running dir servers found? go through and mark them all as up, * so we cycle through the list again. */ + sl = smartlist_create(); for(i=0; i < smartlist_len(routerlist->routers); i++) { router = smartlist_get(routerlist->routers, i); if(router->is_trusted_dir) { tor_assert(router->dir_port > 0); router->is_running = 1; - dirserver = router; + smartlist_add(sl, router); } } - if(!dirserver) + router = smartlist_choose(sl); + smartlist_free(sl); + if(!router) log_fn(LOG_WARN,"No dirservers in directory! Returning NULL."); - return dirserver; + return router; +} + +/** Return 0 if \exists an authoritative dirserver that's currently + * thought to be running, else return 1. + */ +int all_directory_servers_down(void) { + int i; + routerinfo_t *router; + if(!routerlist) + return 1; /* if no dirservers, I guess they're all down */ + for(i=0;i< smartlist_len(routerlist->routers); i++) { + router = smartlist_get(routerlist->routers, i); + if(router->is_running && router->is_trusted_dir) { + tor_assert(router->dir_port > 0); + return 0; + } + } + return 1; } /** Given a comma-and-whitespace separated list of nicknames, see which |