commit 25341245ae53a5800757fbfad37f5623b807befc
Author: rl1987 <rl1987(a)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
};