commit 25341245ae53a5800757fbfad37f5623b807befc Author: rl1987 rl1987@sdf.lonestar.org Date: Fri May 25 13:37:12 2018 +0200
Implement GETINFO md/all --- changes/feature8323 | 3 ++ src/or/control.c | 23 ++++++++++++++ src/test/test_controller.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+)
diff --git a/changes/feature8323 b/changes/feature8323 new file mode 100644 index 000000000..6fbc972d2 --- /dev/null +++ b/changes/feature8323 @@ -0,0 +1,3 @@ + o Minor features (controller): + - Implement 'GETINFO md/all' controller command to enable + getting all known microdesriptors. Closes ticket 8323. diff --git a/src/or/control.c b/src/or/control.c index 0d637dce7..aba4bed0e 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -2207,6 +2207,27 @@ getinfo_helper_dir(control_connection_t *control_conn, return -1; } } + } else if (!strcmp(question, "md/all")) { + const smartlist_t *nodes = nodelist_get_list(); + tor_assert(nodes); + + if (smartlist_len(nodes) == 0) { + *answer = tor_strdup(""); + return 0; + } + + smartlist_t *microdescs = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(nodes, node_t *, n) { + if (n->md && n->md->body) { + char *copy = tor_strndup(n->md->body, n->md->bodylen); + smartlist_add(microdescs, copy); + } + } SMARTLIST_FOREACH_END(n); + + *answer = smartlist_join_strings(microdescs, "", 0, NULL); + SMARTLIST_FOREACH(microdescs, char *, md, tor_free(md)); + smartlist_free(microdescs); } else if (!strcmpstart(question, "md/id/")) { const node_t *node = node_get_by_hex_id(question+strlen("md/id/"), 0); const microdesc_t *md = NULL; @@ -3241,6 +3262,7 @@ static const getinfo_item_t getinfo_items[] = { ITEM("desc/download-enabled", dir, "Do we try to download router descriptors?"), ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */ + ITEM("md/all", dir, "All known microdescriptors."), PREFIX("md/id/", dir, "Microdescriptors by ID"), PREFIX("md/name/", dir, "Microdescriptors by name"), ITEM("md/download-enabled", dir, @@ -3400,6 +3422,7 @@ handle_control_getinfo(control_connection_t *conn, uint32_t len, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { const char *errmsg = NULL; + if (handle_getinfo_helper(conn, q, &ans, &errmsg) < 0) { if (!errmsg) errmsg = "Internal error"; diff --git a/src/test/test_controller.c b/src/test/test_controller.c index 1a350f66c..c9517583c 100644 --- a/src/test/test_controller.c +++ b/src/test/test_controller.c @@ -10,6 +10,7 @@ #include "networkstatus.h" #include "rendservice.h" #include "routerlist.h" +#include "nodelist.h" #include "test.h" #include "test_helpers.h"
@@ -1525,6 +1526,80 @@ test_current_time(void *arg) return; }
+static size_t n_nodelist_get_list = 0; +static smartlist_t *nodes = NULL; + +static smartlist_t * +mock_nodelist_get_list(void) +{ + n_nodelist_get_list++; + tor_assert(nodes); + + return nodes; +} + +static void +test_getinfo_md_all(void *arg) +{ + char *answer = NULL; + const char *errmsg = NULL; + int retval = 0; + + (void)arg; + + node_t *node1 = tor_malloc(sizeof(node_t)); + memset(node1, 0, sizeof(node_t)); + node1->md = tor_malloc(sizeof(microdesc_t)); + memset(node1->md, 0, sizeof(microdesc_t)); + node1->md->body = tor_strdup("md1\n"); + node1->md->bodylen = 4; + + node_t *node2 = tor_malloc(sizeof(node_t)); + memset(node2, 0, sizeof(node_t)); + node2->md = tor_malloc(sizeof(microdesc_t)); + memset(node2->md, 0, sizeof(microdesc_t)); + node2->md->body = tor_strdup("md2\n"); + node2->md->bodylen = 4; + + MOCK(nodelist_get_list, mock_nodelist_get_list); + + nodes = smartlist_new(); + + retval = getinfo_helper_dir(NULL, "md/all", &answer, &errmsg); + + tt_int_op(n_nodelist_get_list, OP_EQ, 1); + tt_int_op(retval, OP_EQ, 0); + tt_assert(answer != NULL); + tt_assert(errmsg == NULL); + tt_str_op(answer, OP_EQ, ""); + + tor_free(answer); + + smartlist_add(nodes, node1); + smartlist_add(nodes, node2); + + retval = getinfo_helper_dir(NULL, "md/all", &answer, &errmsg); + + tt_int_op(n_nodelist_get_list, OP_EQ, 2); + tt_int_op(retval, OP_EQ, 0); + tt_assert(answer != NULL); + tt_assert(errmsg == NULL); + + tt_str_op(answer, OP_EQ, "md1\nmd2\n"); + + done: + UNMOCK(nodelist_get_list); + tor_free(node1->md->body); + tor_free(node1->md); + tor_free(node1); + tor_free(node2->md->body); + tor_free(node2->md); + tor_free(node2); + tor_free(answer); + smartlist_free(nodes); + return; +} + struct testcase_t controller_tests[] = { { "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0, NULL, NULL }, @@ -1542,6 +1617,7 @@ struct testcase_t controller_tests[] = { { "download_status_desc", test_download_status_desc, 0, NULL, NULL }, { "download_status_bridge", test_download_status_bridge, 0, NULL, NULL }, { "current_time", test_current_time, 0, NULL, NULL }, + { "getinfo_md_all", test_getinfo_md_all, 0, NULL, NULL }, END_OF_TESTCASES };