Request (and try to use) consensus diffs.

This commit is contained in:
Nick Mathewson 2017-05-03 15:08:59 -04:00
parent 912b0641e9
commit c12d2cb2dc
5 changed files with 111 additions and 30 deletions

View File

@ -1401,3 +1401,12 @@ consensus_diff_apply(const char *consensus,
return result;
}
/** Return true iff, based on its header, <b>document</b> is likely
* to be a consensus diff. */
int
looks_like_a_consensus_diff(const char *document, size_t len)
{
return (len >= strlen(ns_diff_version) &&
fast_memeq(document, ns_diff_version, strlen(ns_diff_version)));
}

View File

@ -12,6 +12,8 @@ char *consensus_diff_generate(const char *cons1,
char *consensus_diff_apply(const char *consensus,
const char *diff);
int looks_like_a_consensus_diff(const char *document, size_t len);
#ifdef CONSDIFF_PRIVATE
struct memarea_t;

View File

@ -13,6 +13,7 @@
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "consdiff.h"
#include "consdiffmgr.h"
#include "control.h"
#include "compat.h"
@ -2417,6 +2418,10 @@ handle_response_fetch_consensus(dir_connection_t *conn,
const char *reason = args->reason;
const time_t now = approx_time();
const char *consensus;
char *new_consensus = NULL;
const char *sourcename;
int r;
const char *flavname = conn->requested_resource;
if (status_code != 200) {
@ -2429,15 +2434,57 @@ handle_response_fetch_consensus(dir_connection_t *conn,
networkstatus_consensus_download_failed(status_code, flavname);
return -1;
}
log_info(LD_DIR,"Received consensus directory (body size %d) from server "
"'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
if ((r=networkstatus_set_current_consensus(body, flavname, 0,
if (looks_like_a_consensus_diff(body, body_len)) {
/* First find our previous consensus. Maybe it's in ram, maybe not. */
cached_dir_t *cd = dirserv_get_consensus(flavname);
const char *consensus_body;
char *owned_consensus = NULL;
if (cd) {
consensus_body = cd->dir;
} else {
owned_consensus = networkstatus_read_cached_consensus(flavname);
consensus_body = owned_consensus;
}
if (!consensus_body) {
log_warn(LD_DIR, "Received a consensus diff, but we can't find "
"any %s-flavored consensus in our current cache.",flavname);
networkstatus_consensus_download_failed(0, flavname);
// XXXX if this happens too much, see below
return -1;
}
new_consensus = consensus_diff_apply(consensus_body, body);
tor_free(owned_consensus);
if (new_consensus == NULL) {
log_warn(LD_DIR, "Could not apply consensus diff received from server "
"'%s:%d'", conn->base_.address, conn->base_.port);
// XXXX If this happens too many times, we should maybe not use
// XXXX this directory for diffs any more?
networkstatus_consensus_download_failed(0, flavname);
return -1;
}
log_info(LD_DIR, "Applied consensus diff (body size %d) from server "
"'%s:%d' resulted in a new consensus document (size %d).",
(int)body_len, conn->base_.address, conn->base_.port,
(int)strlen(new_consensus));
consensus = new_consensus;
sourcename = "generated based on a diff";
} else {
log_info(LD_DIR,"Received consensus directory (body size %d) from server "
"'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
consensus = body;
sourcename = "downloaded";
}
if ((r=networkstatus_set_current_consensus(consensus, flavname, 0,
conn->identity_digest))<0) {
log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
"Unable to load %s consensus directory downloaded from "
"Unable to load %s consensus directory %s from "
"server '%s:%d'. I'll try again soon.",
flavname, conn->base_.address, conn->base_.port);
flavname, sourcename, conn->base_.address, conn->base_.port);
networkstatus_consensus_download_failed(0, flavname);
tor_free(new_consensus);
return -1;
}
@ -2455,6 +2502,7 @@ handle_response_fetch_consensus(dir_connection_t *conn,
}
log_info(LD_DIR, "Successfully loaded consensus.");
tor_free(new_consensus);
return 0;
}

View File

@ -179,53 +179,74 @@ networkstatus_reset_download_failures(void)
download_status_reset(&consensus_bootstrap_dl_status[i]);
}
/**
* Read and and return the cached consensus of type <b>flavorname</b>. If
* <b>unverified</b> is false, get the one we haven't verified. Return NULL if
* the file isn't there. */
static char *
networkstatus_read_cached_consensus_impl(int flav,
const char *flavorname,
int unverified_consensus)
{
char buf[128];
const char *prefix;
if (unverified_consensus) {
prefix = "unverified";
} else {
prefix = "cached";
}
if (flav == FLAV_NS) {
tor_snprintf(buf, sizeof(buf), "%s-consensus", prefix);
} else {
tor_snprintf(buf, sizeof(buf), "%s-%s-consensus", prefix, flavorname);
}
char *filename = get_datadir_fname(buf);
char *result = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
tor_free(filename);
return result;
}
/** Return a new string containing the current cached consensus of flavor
* <b>flavorname</b>. */
char *
networkstatus_read_cached_consensus(const char *flavorname)
{
int flav = networkstatus_parse_flavor_name(flavorname);
if (flav < 0)
return NULL;
return networkstatus_read_cached_consensus_impl(flav, flavorname, 0);
}
/** Read every cached v3 consensus networkstatus from the disk. */
int
router_reload_consensus_networkstatus(void)
{
char *filename;
char *s;
const unsigned int flags = NSSET_FROM_CACHE | NSSET_DONT_DOWNLOAD_CERTS;
int flav;
/* FFFF Suppress warnings if cached consensus is bad? */
for (flav = 0; flav < N_CONSENSUS_FLAVORS; ++flav) {
char buf[128];
const char *flavor = networkstatus_get_flavor_name(flav);
if (flav == FLAV_NS) {
filename = get_datadir_fname("cached-consensus");
} else {
tor_snprintf(buf, sizeof(buf), "cached-%s-consensus", flavor);
filename = get_datadir_fname(buf);
}
s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
char *s = networkstatus_read_cached_consensus_impl(flav, flavor, 0);
if (s) {
if (networkstatus_set_current_consensus(s, flavor, flags, NULL) < -1) {
log_warn(LD_FS, "Couldn't load consensus %s networkstatus from \"%s\"",
flavor, filename);
log_warn(LD_FS, "Couldn't load consensus %s networkstatus from cache",
flavor);
}
tor_free(s);
}
tor_free(filename);
if (flav == FLAV_NS) {
filename = get_datadir_fname("unverified-consensus");
} else {
tor_snprintf(buf, sizeof(buf), "unverified-%s-consensus", flavor);
filename = get_datadir_fname(buf);
}
s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
s = networkstatus_read_cached_consensus_impl(flav, flavor, 1);
if (s) {
if (networkstatus_set_current_consensus(s, flavor,
flags|NSSET_WAS_WAITING_FOR_CERTS,
NULL)) {
log_info(LD_FS, "Couldn't load consensus %s networkstatus from \"%s\"",
flavor, filename);
}
log_info(LD_FS, "Couldn't load unverified consensus %s networkstatus "
"from cache", flavor);
}
tor_free(s);
}
tor_free(filename);
}
if (!networkstatus_get_latest_consensus()) {

View File

@ -16,6 +16,7 @@
void networkstatus_reset_warnings(void);
void networkstatus_reset_download_failures(void);
char *networkstatus_read_cached_consensus(const char *flavorname);
int router_reload_consensus_networkstatus(void);
void routerstatus_free(routerstatus_t *rs);
void networkstatus_vote_free(networkstatus_t *ns);