diff --git a/src/or/circuituse.c b/src/or/circuituse.c index dcd92af8b7..2e7169b7cb 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -717,6 +717,18 @@ circuit_get_open_circ_or_launch(connection_t *conn, return 1; /* we're happy */ } + if (!has_fetched_directory) { + if (!connection_get_by_type(CONN_TYPE_DIR)) { + log_fn(LOG_NOTICE,"Application request when we're believed to be offline. Optimistically trying again."); + directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1); + } + /* the stream will be dealt with when has_fetched_directory becomes + * 1, or when all directory attempts fail and directory_all_unreachable() + * kills it. + */ + return 0; + } + /* Do we need to check exit policy? */ if (!is_resolve && !connection_edge_is_rendezvous_stream(conn)) { addr = client_dns_lookup_entry(conn->socks_request->address); diff --git a/src/or/directory.c b/src/or/directory.c index 696e113486..c6ec9a58b9 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -184,7 +184,8 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource, else if (ds) directory_initiate_command_trusted_dir(ds, purpose, resource, NULL, 0); else { - log_fn(LOG_WARN,"No running dirservers known. Not trying. (purpose %d)", purpose); + log_fn(LOG_NOTICE,"No running dirservers known. Not trying. (purpose %d)", purpose); + directory_all_unreachable(time(NULL)); /* remember we tried them all and failed. */ } } diff --git a/src/or/main.c b/src/or/main.c index 2b9c67234f..fffa039fa4 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -402,6 +402,25 @@ static void conn_close_if_marked(int i) { } } +/** We've just tried every dirserver we know about, and none of + * them were reachable. Assume the network is down. Change state + * so next time an application connection arrives we'll delay it + * and try another directory fetch. Kill off all the circuit_wait + * streams that are waiting now, since they will all timeout anyway. + */ +void directory_all_unreachable(time_t now) { + connection_t *conn; + + has_fetched_directory=0; + + while ((conn = connection_get_by_type_state(CONN_TYPE_AP, + AP_CONN_STATE_CIRCUIT_WAIT))) { + conn->has_sent_end = 1; /* it's not connected anywhere, so no need to end */ + log_fn(LOG_NOTICE,"Network down? Failing connection to '%s'.", conn->address); + connection_mark_for_close(conn); + } +} + /** This function is called whenever we successfully pull down a directory */ void directory_has_arrived(time_t now) { or_options_t *options = get_options(); diff --git a/src/or/or.h b/src/or/or.h index 0535a7e4ef..e5fe36966d 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1382,7 +1382,9 @@ int connection_is_writing(connection_t *conn); void connection_stop_writing(connection_t *conn); void connection_start_writing(connection_t *conn); +void directory_all_unreachable(time_t now); void directory_has_arrived(time_t now); + int authdir_mode(or_options_t *options); int clique_mode(or_options_t *options); int server_mode(or_options_t *options);