|
@@ -15,6 +15,7 @@
|
|
#include "dirvote.h"
|
|
#include "dirvote.h"
|
|
#include "geoip.h"
|
|
#include "geoip.h"
|
|
#include "main.h"
|
|
#include "main.h"
|
|
|
|
+#include "microdesc.h"
|
|
#include "networkstatus.h"
|
|
#include "networkstatus.h"
|
|
#include "policies.h"
|
|
#include "policies.h"
|
|
#include "rendclient.h"
|
|
#include "rendclient.h"
|
|
@@ -78,6 +79,8 @@ static void dir_routerdesc_download_failed(smartlist_t *failed,
|
|
int router_purpose,
|
|
int router_purpose,
|
|
int was_extrainfo,
|
|
int was_extrainfo,
|
|
int was_descriptor_digests);
|
|
int was_descriptor_digests);
|
|
|
|
+static void dir_microdesc_download_failed(smartlist_t *failed,
|
|
|
|
+ int status_code);
|
|
static void note_client_request(int purpose, int compressed, size_t bytes);
|
|
static void note_client_request(int purpose, int compressed, size_t bytes);
|
|
static int client_likes_consensus(networkstatus_t *v, const char *want_url);
|
|
static int client_likes_consensus(networkstatus_t *v, const char *want_url);
|
|
|
|
|
|
@@ -137,7 +140,8 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose)
|
|
dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS ||
|
|
dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS ||
|
|
dir_purpose == DIR_PURPOSE_FETCH_CERTIFICATE ||
|
|
dir_purpose == DIR_PURPOSE_FETCH_CERTIFICATE ||
|
|
dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
|
|
dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
|
|
- dir_purpose == DIR_PURPOSE_FETCH_EXTRAINFO)
|
|
|
|
|
|
+ dir_purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
|
|
|
|
+ dir_purpose == DIR_PURPOSE_FETCH_MICRODESC)
|
|
return 0;
|
|
return 0;
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
@@ -201,6 +205,8 @@ dir_conn_purpose_to_string(int purpose)
|
|
return "hidden-service v2 descriptor fetch";
|
|
return "hidden-service v2 descriptor fetch";
|
|
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
|
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
|
return "hidden-service v2 descriptor upload";
|
|
return "hidden-service v2 descriptor upload";
|
|
|
|
+ case DIR_PURPOSE_FETCH_MICRODESC:
|
|
|
|
+ return "microdescriptor fetch";
|
|
}
|
|
}
|
|
|
|
|
|
log_warn(LD_BUG, "Called with unknown purpose %d", purpose);
|
|
log_warn(LD_BUG, "Called with unknown purpose %d", purpose);
|
|
@@ -355,15 +361,33 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
|
|
case DIR_PURPOSE_FETCH_CERTIFICATE:
|
|
case DIR_PURPOSE_FETCH_CERTIFICATE:
|
|
type = V3_AUTHORITY;
|
|
type = V3_AUTHORITY;
|
|
break;
|
|
break;
|
|
|
|
+ case DIR_PURPOSE_FETCH_MICRODESC:
|
|
|
|
+ type = V3_AUTHORITY;
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
|
|
log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
|
|
if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
|
|
- networkstatus_t *v = networkstatus_get_latest_consensus();
|
|
|
|
- if (v)
|
|
|
|
- if_modified_since = v->valid_after + 180;
|
|
|
|
|
|
+ int flav = FLAV_NS;
|
|
|
|
+ networkstatus_t *v;
|
|
|
|
+ if (resource)
|
|
|
|
+ flav = networkstatus_parse_flavor_name(resource);
|
|
|
|
+
|
|
|
|
+ if (flav != -1) {
|
|
|
|
+ /* IF we have a parsed consensus of this type, we can do an
|
|
|
|
+ * if-modified-time based on it. */
|
|
|
|
+ v = networkstatus_get_latest_consensus_by_flavor(flav);
|
|
|
|
+ if (v)
|
|
|
|
+ if_modified_since = v->valid_after + 180;
|
|
|
|
+ } else {
|
|
|
|
+ /* Otherwise it might be a consensus we don't parse, but which we
|
|
|
|
+ * do cache. Look at the cached copy, perhaps. */
|
|
|
|
+ cached_dir_t *cd = dirserv_get_consensus(resource ? resource : "ns");
|
|
|
|
+ if (cd)
|
|
|
|
+ if_modified_since = cd->published + 180;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if (!options->FetchServerDescriptors && type != HIDSERV_AUTHORITY)
|
|
if (!options->FetchServerDescriptors && type != HIDSERV_AUTHORITY)
|
|
@@ -395,7 +419,8 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
|
|
if (prefer_authority || type == BRIDGE_AUTHORITY) {
|
|
if (prefer_authority || type == BRIDGE_AUTHORITY) {
|
|
/* only ask authdirservers, and don't ask myself */
|
|
/* only ask authdirservers, and don't ask myself */
|
|
rs = router_pick_trusteddirserver(type, pds_flags);
|
|
rs = router_pick_trusteddirserver(type, pds_flags);
|
|
- if (rs == NULL && (pds_flags & PDS_NO_EXISTING_SERVERDESC_FETCH)) {
|
|
|
|
|
|
+ if (rs == NULL && (pds_flags & (PDS_NO_EXISTING_SERVERDESC_FETCH|
|
|
|
|
+ PDS_NO_EXISTING_MICRODESC_FETCH))) {
|
|
/* We don't want to fetch from any authorities that we're currently
|
|
/* We don't want to fetch from any authorities that we're currently
|
|
* fetching server descriptors from, and we got no match. Did we
|
|
* fetching server descriptors from, and we got no match. Did we
|
|
* get no match because all the authorities have connections
|
|
* get no match because all the authorities have connections
|
|
@@ -403,7 +428,8 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
|
|
* return,) or because all the authorities are down or on fire or
|
|
* return,) or because all the authorities are down or on fire or
|
|
* unreachable or something (in which case we should go on with
|
|
* unreachable or something (in which case we should go on with
|
|
* our fallback code)? */
|
|
* our fallback code)? */
|
|
- pds_flags &= ~PDS_NO_EXISTING_SERVERDESC_FETCH;
|
|
|
|
|
|
+ pds_flags &= ~(PDS_NO_EXISTING_SERVERDESC_FETCH|
|
|
|
|
+ PDS_NO_EXISTING_MICRODESC_FETCH);
|
|
rs = router_pick_trusteddirserver(type, pds_flags);
|
|
rs = router_pick_trusteddirserver(type, pds_flags);
|
|
if (rs) {
|
|
if (rs) {
|
|
log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities "
|
|
log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities "
|
|
@@ -592,15 +618,19 @@ connection_dir_request_failed(dir_connection_t *conn)
|
|
connection_dir_download_networkstatus_failed(conn, -1);
|
|
connection_dir_download_networkstatus_failed(conn, -1);
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
|
|
conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
|
|
conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
|
|
- log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
|
|
|
|
|
|
+ log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from "
|
|
|
|
+ "directory server at '%s'; retrying",
|
|
conn->_base.address);
|
|
conn->_base.address);
|
|
if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE)
|
|
if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE)
|
|
connection_dir_bridge_routerdesc_failed(conn);
|
|
connection_dir_bridge_routerdesc_failed(conn);
|
|
connection_dir_download_routerdesc_failed(conn);
|
|
connection_dir_download_routerdesc_failed(conn);
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
|
|
- networkstatus_consensus_download_failed(0);
|
|
|
|
|
|
+ const char *flavname =
|
|
|
|
+ conn->requested_resource ? conn->requested_resource : "ns";
|
|
|
|
+ networkstatus_consensus_download_failed(0, flavname);
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
|
|
- log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
|
|
|
|
|
|
+ log_info(LD_DIR, "Giving up on certificate fetch from directory server "
|
|
|
|
+ "at '%s'; retrying",
|
|
conn->_base.address);
|
|
conn->_base.address);
|
|
connection_dir_download_cert_failed(conn, 0);
|
|
connection_dir_download_cert_failed(conn, 0);
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
|
|
@@ -609,6 +639,10 @@ connection_dir_request_failed(dir_connection_t *conn)
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
|
|
} else if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
|
|
log_info(LD_DIR, "Giving up downloading votes from '%s'",
|
|
log_info(LD_DIR, "Giving up downloading votes from '%s'",
|
|
conn->_base.address);
|
|
conn->_base.address);
|
|
|
|
+ } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
|
|
|
|
+ log_info(LD_DIR, "Giving up on downloading microdescriptors from "
|
|
|
|
+ " directory server at '%s'; will retry", conn->_base.address);
|
|
|
|
+ connection_dir_download_routerdesc_failed(conn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -679,7 +713,8 @@ connection_dir_download_routerdesc_failed(dir_connection_t *conn)
|
|
/* No need to relaunch descriptor downloads here: we already do it
|
|
/* No need to relaunch descriptor downloads here: we already do it
|
|
* every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
|
|
* every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
|
|
tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
|
|
tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
|
|
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO);
|
|
|
|
|
|
+ conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
|
|
|
|
+ conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC);
|
|
|
|
|
|
(void) conn;
|
|
(void) conn;
|
|
}
|
|
}
|
|
@@ -955,12 +990,16 @@ _compare_strs(const void **a, const void **b)
|
|
* This url depends on whether or not the server we go to
|
|
* This url depends on whether or not the server we go to
|
|
* is sufficiently new to support conditional consensus downloading,
|
|
* is sufficiently new to support conditional consensus downloading,
|
|
* i.e. GET .../consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>
|
|
* i.e. GET .../consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>
|
|
|
|
+ *
|
|
|
|
+ * If 'resource' is provided, it is the name of a consensus flavor to request.
|
|
*/
|
|
*/
|
|
static char *
|
|
static char *
|
|
-directory_get_consensus_url(int supports_conditional_consensus)
|
|
|
|
|
|
+directory_get_consensus_url(int supports_conditional_consensus,
|
|
|
|
+ const char *resource)
|
|
{
|
|
{
|
|
- char *url;
|
|
|
|
- size_t len;
|
|
|
|
|
|
+ char *url = NULL;
|
|
|
|
+ const char *hyphen = resource ? "-" : "";
|
|
|
|
+ const char *flavor = resource ? resource : "";
|
|
|
|
|
|
if (supports_conditional_consensus) {
|
|
if (supports_conditional_consensus) {
|
|
char *authority_id_list;
|
|
char *authority_id_list;
|
|
@@ -982,16 +1021,15 @@ directory_get_consensus_url(int supports_conditional_consensus)
|
|
authority_id_list = smartlist_join_strings(authority_digests,
|
|
authority_id_list = smartlist_join_strings(authority_digests,
|
|
"+", 0, NULL);
|
|
"+", 0, NULL);
|
|
|
|
|
|
- len = strlen(authority_id_list)+64;
|
|
|
|
- url = tor_malloc(len);
|
|
|
|
- tor_snprintf(url, len, "/tor/status-vote/current/consensus/%s.z",
|
|
|
|
- authority_id_list);
|
|
|
|
|
|
+ tor_asprintf(&url, "/tor/status-vote/current/consensus%s%s/%s.z",
|
|
|
|
+ hyphen, flavor, authority_id_list);
|
|
|
|
|
|
SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp));
|
|
SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp));
|
|
smartlist_free(authority_digests);
|
|
smartlist_free(authority_digests);
|
|
tor_free(authority_id_list);
|
|
tor_free(authority_id_list);
|
|
} else {
|
|
} else {
|
|
- url = tor_strdup("/tor/status-vote/current/consensus.z");
|
|
|
|
|
|
+ tor_asprintf(&url, "/tor/status-vote/current/consensus%s%s.z",
|
|
|
|
+ hyphen, flavor);
|
|
}
|
|
}
|
|
return url;
|
|
return url;
|
|
}
|
|
}
|
|
@@ -1072,10 +1110,11 @@ directory_send_command(dir_connection_t *conn,
|
|
tor_snprintf(url, len, "/tor/status/%s", resource);
|
|
tor_snprintf(url, len, "/tor/status/%s", resource);
|
|
break;
|
|
break;
|
|
case DIR_PURPOSE_FETCH_CONSENSUS:
|
|
case DIR_PURPOSE_FETCH_CONSENSUS:
|
|
- tor_assert(!resource);
|
|
|
|
|
|
+ /* resource is optional. If present, it's a flavor name */
|
|
tor_assert(!payload);
|
|
tor_assert(!payload);
|
|
httpcommand = "GET";
|
|
httpcommand = "GET";
|
|
- url = directory_get_consensus_url(supports_conditional_consensus);
|
|
|
|
|
|
+ url = directory_get_consensus_url(supports_conditional_consensus,
|
|
|
|
+ resource);
|
|
log_info(LD_DIR, "Downloading consensus from %s using %s",
|
|
log_info(LD_DIR, "Downloading consensus from %s using %s",
|
|
hoststring, url);
|
|
hoststring, url);
|
|
break;
|
|
break;
|
|
@@ -1115,6 +1154,11 @@ directory_send_command(dir_connection_t *conn,
|
|
url = tor_malloc(len);
|
|
url = tor_malloc(len);
|
|
tor_snprintf(url, len, "/tor/extra/%s", resource);
|
|
tor_snprintf(url, len, "/tor/extra/%s", resource);
|
|
break;
|
|
break;
|
|
|
|
+ case DIR_PURPOSE_FETCH_MICRODESC:
|
|
|
|
+ tor_assert(resource);
|
|
|
|
+ httpcommand = "GET";
|
|
|
|
+ tor_asprintf(&url, "/tor/micro/%s.z", resource);
|
|
|
|
+ break;
|
|
case DIR_PURPOSE_UPLOAD_DIR:
|
|
case DIR_PURPOSE_UPLOAD_DIR:
|
|
tor_assert(!resource);
|
|
tor_assert(!resource);
|
|
tor_assert(payload);
|
|
tor_assert(payload);
|
|
@@ -1390,6 +1434,9 @@ body_is_plausible(const char *body, size_t len, int purpose)
|
|
return 1; /* empty bodies don't need decompression */
|
|
return 1; /* empty bodies don't need decompression */
|
|
if (len < 32)
|
|
if (len < 32)
|
|
return 0;
|
|
return 0;
|
|
|
|
+ if (purpose == DIR_PURPOSE_FETCH_MICRODESC) {
|
|
|
|
+ return (!strcmpstart(body,"onion-key"));
|
|
|
|
+ }
|
|
if (purpose != DIR_PURPOSE_FETCH_RENDDESC) {
|
|
if (purpose != DIR_PURPOSE_FETCH_RENDDESC) {
|
|
if (!strcmpstart(body,"router") ||
|
|
if (!strcmpstart(body,"router") ||
|
|
!strcmpstart(body,"signed-directory") ||
|
|
!strcmpstart(body,"signed-directory") ||
|
|
@@ -1466,7 +1513,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
|
int plausible;
|
|
int plausible;
|
|
int skewed=0;
|
|
int skewed=0;
|
|
int allow_partial = (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
|
|
int allow_partial = (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
|
|
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO);
|
|
|
|
|
|
+ conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
|
|
|
|
+ conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC);
|
|
int was_compressed=0;
|
|
int was_compressed=0;
|
|
time_t now = time(NULL);
|
|
time_t now = time(NULL);
|
|
|
|
|
|
@@ -1690,6 +1738,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
|
|
|
|
|
if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
|
|
if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
|
|
int r;
|
|
int r;
|
|
|
|
+ const char *flavname =
|
|
|
|
+ conn->requested_resource ? conn->requested_resource : "ns";
|
|
if (status_code != 200) {
|
|
if (status_code != 200) {
|
|
int severity = (status_code == 304) ? LOG_INFO : LOG_WARN;
|
|
int severity = (status_code == 304) ? LOG_INFO : LOG_WARN;
|
|
log(severity, LD_DIR,
|
|
log(severity, LD_DIR,
|
|
@@ -1698,22 +1748,24 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
|
status_code, escaped(reason), conn->_base.address,
|
|
status_code, escaped(reason), conn->_base.address,
|
|
conn->_base.port);
|
|
conn->_base.port);
|
|
tor_free(body); tor_free(headers); tor_free(reason);
|
|
tor_free(body); tor_free(headers); tor_free(reason);
|
|
- networkstatus_consensus_download_failed(status_code);
|
|
|
|
|
|
+ networkstatus_consensus_download_failed(status_code, flavname);
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
log_info(LD_DIR,"Received consensus directory (size %d) from server "
|
|
log_info(LD_DIR,"Received consensus directory (size %d) from server "
|
|
"'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
|
|
"'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
|
|
- if ((r=networkstatus_set_current_consensus(body, "ns", 0))<0) {
|
|
|
|
|
|
+ if ((r=networkstatus_set_current_consensus(body, flavname, 0))<0) {
|
|
log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
|
|
log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
|
|
- "Unable to load consensus directory downloaded from "
|
|
|
|
|
|
+ "Unable to load %s consensus directory downloaded from "
|
|
"server '%s:%d'. I'll try again soon.",
|
|
"server '%s:%d'. I'll try again soon.",
|
|
- conn->_base.address, conn->_base.port);
|
|
|
|
|
|
+ flavname, conn->_base.address, conn->_base.port);
|
|
tor_free(body); tor_free(headers); tor_free(reason);
|
|
tor_free(body); tor_free(headers); tor_free(reason);
|
|
- networkstatus_consensus_download_failed(0);
|
|
|
|
|
|
+ networkstatus_consensus_download_failed(0, flavname);
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
/* launches router downloads as needed */
|
|
/* launches router downloads as needed */
|
|
routers_update_all_from_networkstatus(now, 3);
|
|
routers_update_all_from_networkstatus(now, 3);
|
|
|
|
+ update_microdescs_from_networkstatus(now);
|
|
|
|
+ update_microdesc_downloads(now);
|
|
directory_info_has_arrived(now, 0);
|
|
directory_info_has_arrived(now, 0);
|
|
log_info(LD_DIR, "Successfully loaded consensus.");
|
|
log_info(LD_DIR, "Successfully loaded consensus.");
|
|
}
|
|
}
|
|
@@ -1863,6 +1915,41 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
|
if (directory_conn_is_self_reachability_test(conn))
|
|
if (directory_conn_is_self_reachability_test(conn))
|
|
router_dirport_found_reachable();
|
|
router_dirport_found_reachable();
|
|
}
|
|
}
|
|
|
|
+ if (conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
|
|
|
|
+ smartlist_t *which = NULL;
|
|
|
|
+ log_info(LD_DIR,"Received answer to microdescriptor request (status %d, "
|
|
|
|
+ "size %d) from server '%s:%d'",
|
|
|
|
+ status_code, (int)body_len, conn->_base.address, conn->_base.port);
|
|
|
|
+ tor_assert(conn->requested_resource &&
|
|
|
|
+ !strcmpstart(conn->requested_resource, "d/"));
|
|
|
|
+ which = smartlist_create();
|
|
|
|
+ dir_split_resource_into_fingerprints(conn->requested_resource+2,
|
|
|
|
+ which, NULL,
|
|
|
|
+ DSR_DIGEST256|DSR_BASE64);
|
|
|
|
+ if (status_code != 200) {
|
|
|
|
+ log_info(LD_DIR, "Received status code %d (%s) from server "
|
|
|
|
+ "'%s:%d' while fetching \"/tor/micro/%s\". I'll try again "
|
|
|
|
+ "soon.",
|
|
|
|
+ status_code, escaped(reason), conn->_base.address,
|
|
|
|
+ (int)conn->_base.port, conn->requested_resource);
|
|
|
|
+ dir_microdesc_download_failed(which, status_code);
|
|
|
|
+ SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
|
|
|
|
+ smartlist_free(which);
|
|
|
|
+ tor_free(body); tor_free(headers); tor_free(reason);
|
|
|
|
+ return 0;
|
|
|
|
+ } else {
|
|
|
|
+ smartlist_t *mds;
|
|
|
|
+ mds = microdescs_add_to_cache(get_microdesc_cache(),
|
|
|
|
+ body, body+body_len, SAVED_NOWHERE, 0,
|
|
|
|
+ now, which);
|
|
|
|
+ if (smartlist_len(which)) {
|
|
|
|
+ /* Mark remaining ones as failed. */
|
|
|
|
+ dir_microdesc_download_failed(which, status_code);
|
|
|
|
+ }
|
|
|
|
+ SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
|
|
|
|
+ smartlist_free(which);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
|
|
if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
|
|
switch (status_code) {
|
|
switch (status_code) {
|
|
@@ -3589,6 +3676,36 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
|
|
* every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
|
|
* every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* DOCDOC NM */
|
|
|
|
+static void
|
|
|
|
+dir_microdesc_download_failed(smartlist_t *failed,
|
|
|
|
+ int status_code)
|
|
|
|
+{
|
|
|
|
+ networkstatus_t *consensus
|
|
|
|
+ = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC);
|
|
|
|
+ routerstatus_t *rs;
|
|
|
|
+ download_status_t *dls;
|
|
|
|
+ time_t now = time(NULL);
|
|
|
|
+ int server = directory_fetches_from_authorities(get_options());
|
|
|
|
+
|
|
|
|
+ if (! consensus)
|
|
|
|
+ return;
|
|
|
|
+ SMARTLIST_FOREACH_BEGIN(failed, const char *, d) {
|
|
|
|
+ rs = router_get_consensus_status_by_descriptor_digest(consensus, d);
|
|
|
|
+ if (!rs)
|
|
|
|
+ continue;
|
|
|
|
+ dls = &rs->dl_status;
|
|
|
|
+ if (dls->n_download_failures >= MAX_MICRODESC_DOWNLOAD_FAILURES)
|
|
|
|
+ continue;
|
|
|
|
+ {
|
|
|
|
+ char buf[BASE64_DIGEST256_LEN+1];
|
|
|
|
+ digest256_to_base64(buf, d);
|
|
|
|
+ download_status_increment_failure(dls, status_code, buf,
|
|
|
|
+ server, now);
|
|
|
|
+ }
|
|
|
|
+ } SMARTLIST_FOREACH_END(d);
|
|
|
|
+}
|
|
|
|
+
|
|
/** Helper. Compare two fp_pair_t objects, and return -1, 0, or 1 as
|
|
/** Helper. Compare two fp_pair_t objects, and return -1, 0, or 1 as
|
|
* appropriate. */
|
|
* appropriate. */
|
|
static int
|
|
static int
|