Skip to content

Commit

Permalink
Add: GETINFO support for dumping microdesc consensus
Browse files Browse the repository at this point in the history
test: case to check GETINFO consensus commands are functional.
fix: code structure
update: changes with human readable description
fix: command naming convention
add: test case checks if consensus body is returned
fix: potential memory leak
  • Loading branch information
ltbringer committed Sep 30, 2019
1 parent d41c4f1 commit e546a6a
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 47 deletions.
2 changes: 1 addition & 1 deletion changes/ticket31684
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
o Minor features (onion services):
- GETINFO dir/status-vote/current/consensus-microdesc dumps microdesc consensus. Closes ticket 31684.
- Implement a new GETINFO command to fetch consensus. Closes ticket 31684.
65 changes: 28 additions & 37 deletions src/feature/control/control_getinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,46 +326,36 @@ getinfo_helper_current_time(control_connection_t *control_conn,
}

/**
* Switch between microdesc vs networkstatus descriptor dumps
* Assumes that question would be either:
* - dir/status-vote/current/consensus-microdesc
* or
* - dir/status-vote/current/consensus
* Helps to access directory information for a given
* type of consensus.
*
* returns: int
* -1 in cases of an error
* 0 otherwise
*/
STATIC int
getinfo_helper_current_consensus(const char* question,
char** answer,
const char** errmsg)
getinfo_helper_current_consensus(const char* consensus_type,
int flavor, char** answer,
const char** errmsg)
{
// Ensures question contains a request for
// ns or microdesc consensus
if (
strcmp(question, "dir/status-vote/current/consensus") &&
strcmp(question, "dir/status-vote/current/consensus-microdesc")) {
return 0;
}

const char* consensus_type = !strcmp(
question, "dir/status-vote/current/consensus-microdesc"
) ? "microdesc" : "ns";

if (we_want_to_fetch_flavor(get_options(), FLAV_NS)) {
/** Check if the consensus flavor is cached or in the ram. */
if (we_want_to_fetch_flavor(get_options(), flavor)) {
const cached_dir_t *consensus = dirserv_get_consensus(consensus_type);
if (consensus) {
*answer = tor_strdup(consensus->dir);
}
}
if (!*answer) { /* try loading it from disk */
if (!*answer) { /* else, try loading consensus from disk */
tor_mmap_t *mapped = networkstatus_map_cached_consensus(consensus_type);
if (mapped) {
*answer = tor_memdup_nulterm(mapped->data, mapped->size);
tor_munmap_file(mapped);
}
if (!*answer) { /* generate an error */
*errmsg = "Could not open cached consensus. "
"Make sure FetchUselessDescriptors is set to 1.";
return -1;
}
}
if (!*answer) { /* generate an error */
*errmsg = "Could not open cached consensus. "
"Make sure FetchUselessDescriptors is set to 1.";
return -1;
}
return 0;
}
Expand Down Expand Up @@ -622,16 +612,17 @@ getinfo_helper_dir(control_connection_t *control_conn,
smartlist_free(descs);
} else if (!strcmpstart(question, "dir/status/")) {
*answer = tor_strdup("");
} else if (-1 == getinfo_helper_current_consensus(
question,
answer,
errmsg))
{
/**
* answer is set by getinfo_helper_current_consensus
* if the question matches
*/
return -1;
} else if (!strcmp(question, "dir/status-vote/current/consensus")) {
if (getinfo_helper_current_consensus(
"ns", FLAV_NS, answer, errmsg) == -1) {
return -1;
}
} else if (!strcmp(question, "dir/status-vote/current/consensus-microdesc"))
{
if (getinfo_helper_current_consensus(
"microdesc", FLAV_MICRODESC, answer, errmsg) == -1) {
return -1;
}
} else if (!strcmp(question, "network-status")) { /* v1 */
static int network_status_warned = 0;
if (!network_status_warned) {
Expand Down
3 changes: 2 additions & 1 deletion src/feature/control/control_getinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ STATIC int getinfo_helper_downloads(
const char *question, char **answer,
const char **errmsg);
STATIC int getinfo_helper_current_consensus(
const char *question, char **answer,
const char *question, int flavor,
char **answer,
const char **errmsg);
STATIC int getinfo_helper_dir(
control_connection_t *control_conn,
Expand Down
12 changes: 6 additions & 6 deletions src/feature/nodelist/networkstatus.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,9 @@ networkstatus_get_cache_fname(int flav,
* 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 tor_mmap_t *
networkstatus_map_cached_consensus_impl(int flav,
const char *flavorname,
int unverified_consensus)
MOCK_IMPL(tor_mmap_t *,
networkstatus_map_cached_consensus_impl,
(int flav, const char *flavorname, int unverified_consensus))
{
char *filename = networkstatus_get_cache_fname(flav,
flavorname,
Expand All @@ -256,8 +255,9 @@ networkstatus_map_cached_consensus_impl(int flav,

/** Map the file containing the current cached consensus of flavor
* <b>flavorname</b> */
tor_mmap_t *
networkstatus_map_cached_consensus(const char *flavorname)
MOCK_IMPL(tor_mmap_t *,
networkstatus_map_cached_consensus,
(const char *flavorname))
{
int flav = networkstatus_parse_flavor_name(flavorname);
if (flav < 0)
Expand Down
9 changes: 8 additions & 1 deletion src/feature/nodelist/networkstatus.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@

void networkstatus_reset_warnings(void);
void networkstatus_reset_download_failures(void);
tor_mmap_t *networkstatus_map_cached_consensus(const char *flavorname);

MOCK_DECL(tor_mmap_t *,
networkstatus_map_cached_consensus_impl,
(int flav, const char *flavorname, int unverified_consensus));

MOCK_DECL(tor_mmap_t *,
networkstatus_map_cached_consensus,
(const char *flavorname));
int router_reload_consensus_networkstatus(void);
void routerstatus_free_(routerstatus_t *rs);
#define routerstatus_free(rs) \
Expand Down
75 changes: 74 additions & 1 deletion src/test/test_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,12 @@ static download_status_t descbr_digest_2_dl;
static const char *descbr_expected_list =
"616408544C7345822696074A1A3DFA16AB381CBD\n"
"06E8067246967265DBCB6641631B530EFEC12DC3\n";

/** Simulated Networkstatus consensus */
static const char *mock_ns_consensus = "mock_ns_consensus";
/** Simulated Microdesc consensus */
static const char *mock_microdesc_consensus = "mock_microdesc_consensus";

/*
* Flag to make all descbr queries fail, to simulate not being
* configured such that such queries make sense.
Expand Down Expand Up @@ -1689,6 +1695,72 @@ test_download_status_bridge(void *arg)
return;
}

tor_mmap_t *
mock_networkstatus_map_cached_consensus_impl(int flav,
const char *flavorname,
int unverified_consensus);

tor_mmap_t *
mock_networkstatus_map_cached_consensus_impl(int flav,
const char *flavorname,
int unverified_consensus)
{
tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t));

/** Suppress error on the CI */
flav = flav;
unverified_consensus = unverified_consensus;

if (!strcmp(flavorname, "ns")) {
res->data = "mock_ns_consensus";
}
if (!strcmp(flavorname, "microdesc")) {
res->data = "mock_microdesc_consensus";
}
res->size = strlen(res->data);
return res;
}

static void
test_getinfo_helper_dir(void *arg)
{
/* We just need one of these to pass, it doesn't matter what's in it */
control_connection_t dummy;
/* Get results out */
char *answer = NULL;
const char *errmsg = NULL;

(void)arg;

setup_bridge_mocks();
MOCK(networkstatus_map_cached_consensus_impl,
mock_networkstatus_map_cached_consensus_impl);

getinfo_helper_dir(&dummy,
"dir/status-vote/current/consensus",
&answer,
&errmsg);
tt_str_op(answer, OP_EQ, mock_ns_consensus);
tt_ptr_op(errmsg, OP_EQ, NULL);
tor_free(answer);
answer = NULL;
errmsg = NULL;

getinfo_helper_dir(&dummy,
"dir/status-vote/current/consensus-microdesc",
&answer,
&errmsg);
tt_str_op(answer, OP_EQ, mock_microdesc_consensus);
tt_ptr_op(errmsg, OP_EQ, NULL);
tor_free(answer);

done:
clear_bridge_mocks();
tor_free(answer);
UNMOCK(networkstatus_map_cached_consensus_impl);
return;
}

/** Set timeval to a mock date and time. This is necessary
* to make tor_gettimeofday() mockable. */
static void
Expand Down Expand Up @@ -1740,7 +1812,6 @@ test_current_time(void *arg)
done:
UNMOCK(tor_gettimeofday);
tor_free(answer);

return;
}

Expand Down Expand Up @@ -1838,6 +1909,8 @@ struct testcase_t controller_tests[] = {
NULL },
{ "download_status_consensus", test_download_status_consensus, 0, NULL,
NULL },
{"getinfo_helper_current_consensus", test_getinfo_helper_dir, 0, NULL,
NULL },
{ "download_status_cert", test_download_status_cert, 0, NULL,
NULL },
{ "download_status_desc", test_download_status_desc, 0, NULL, NULL },
Expand Down

0 comments on commit e546a6a

Please sign in to comment.