if (prefer_authority || type == BRIDGE_AUTHORITY) {
/* only ask authdirservers, and don't ask myself */
rs = router_pick_trusteddirserver(type, pds_flags);
+ if (rs == NULL && (pds_flags & PDS_NO_EXISTING_SERVERDESC_FETCH)) {
+ /* We don't want to fetch from any authorities that we're currently
+ * fetching server descriptors from, and we got no match. Did we
+ * get no match because all the authorities have connections
+ * fetching server descriptors (in which case we should just
+ * return,) or because all the authorities are down or on fire or
+ * unreachable or something (in which case we should go on with
+ * our fallback code)? */
+ pds_flags &= ~PDS_NO_EXISTING_SERVERDESC_FETCH;
+ rs = router_pick_trusteddirserver(type, pds_flags);
+ if (rs) {
+ log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities "
+ "are in use.");
+ return;
+ }
+ }
}
if (!rs && type != BRIDGE_AUTHORITY) {
/* anybody with a non-zero dirport will do */
smartlist_t *router_get_trusted_dir_servers(void);
/* Flags for pick_directory_server and pick_trusteddirserver. */
+/** Flag to indicate that we should not automatically be willing to use
+ * ourself to answer a directory request.
+ * Passed to router_pick_directory_server (et al).*/
#define PDS_ALLOW_SELF (1<<0)
+/** Flag to indicate that if no servers seem to be up, we should mark all
+ * directory servers as up and try again.
+ * Passed to router_pick_directory_server (et al).*/
#define PDS_RETRY_IF_NO_SERVERS (1<<1)
+/** Flag to indicate that we should not exclude directory servers that
+ * our ReachableAddress settings would exclude. This usually means that
+ * we're going to connect to the server over Tor, and so we don't need to
+ * worry about our firewall telling us we can't.
+ * Passed to router_pick_directory_server (et al).*/
#define PDS_IGNORE_FASCISTFIREWALL (1<<2)
+/** Flag to indicate that we should not use any directory authority to which
+ * we have an existing directory connection for downloading server descriptors
+ * or extrainfo documents. [NOTE: Only implemented for
+ * router_pick_trusteddirserver, not router_pick_directory_server.]
+ * Passed to router_pick_directory_server (et al).*/
+#define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3)
#define _PDS_PREFER_TUNNELED_DIR_CONNS (1<<16)
routerstatus_t *router_pick_directory_server(authority_type_t type, int flags);
trusted_dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
static routerstatus_t *router_pick_directory_server_impl(
authority_type_t auth, int flags);
static routerstatus_t *router_pick_trusteddirserver_impl(
- authority_type_t auth, int flags);
+ authority_type_t auth, int flags, int *n_busy_out);
static void mark_all_trusteddirservers_up(void);
static int router_nickname_matches(routerinfo_t *router, const char *nickname);
static void trusted_dir_server_free(trusted_dir_server_t *ds);
router_pick_trusteddirserver(authority_type_t type, int flags)
{
routerstatus_t *choice;
+ int busy = 0;
if (get_options()->PreferTunneledDirConns)
flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
- choice = router_pick_trusteddirserver_impl(type, flags);
+ choice = router_pick_trusteddirserver_impl(type, flags, &busy);
if (choice || !(flags & PDS_RETRY_IF_NO_SERVERS))
return choice;
+ if (busy) {
+ /* If the reason that we got no server is that servers are "busy",
+ * we must be excluding good servers because we already have serverdesc
+ * fetches with them. Do not mark down servers up because of this. */
+ tor_assert((flags & PDS_NO_EXISTING_SERVERDESC_FETCH));
+ return NULL;
+ }
log_info(LD_DIR,
"No trusted dirservers are reachable. Trying them all again.");
mark_all_trusteddirservers_up();
- return router_pick_trusteddirserver_impl(type, flags);
+ return router_pick_trusteddirserver_impl(type, flags, NULL);
}
/** How long do we avoid using a directory server after it's given us a 503? */
* are as for router_pick_directory_server_impl().
*/
static routerstatus_t *
-router_pick_trusteddirserver_impl(authority_type_t type, int flags)
+router_pick_trusteddirserver_impl(authority_type_t type, int flags,
+ int *n_busy_out)
{
smartlist_t *direct, *tunnel;
smartlist_t *overloaded_direct, *overloaded_tunnel;
routerinfo_t *me = router_get_my_routerinfo();
routerstatus_t *result;
time_t now = time(NULL);
- int requireother = ! (flags & PDS_ALLOW_SELF);
- int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
- int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
+ const int requireother = ! (flags & PDS_ALLOW_SELF);
+ const int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
+ const int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
+ const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH);
+ int n_busy = 0;
if (!trusted_dir_servers)
return NULL;
/* XXXX021 IP6 proposal 118 */
tor_addr_from_ipv4h(&addr, d->addr);
+ if (no_serverdesc_fetching) {
+ if (connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR, &addr, d->dir_port, DIR_PURPOSE_FETCH_SERVERDESC)
+ || connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR, &addr, d->dir_port, DIR_PURPOSE_FETCH_EXTRAINFO)) {
+ //log_debug(LD_DIR, "We have an existing connection to fetch "
+ // "descriptor from %s; delaying",d->description);
+ ++n_busy;
+ continue;
+ }
+ }
+
if (prefer_tunnel &&
d->or_port &&
(!fascistfirewall ||
result = smartlist_choose(overloaded_direct);
}
+ if (n_busy_out)
+ *n_busy_out = n_busy;
+
smartlist_free(direct);
smartlist_free(tunnel);
smartlist_free(overloaded_direct);