Sfoglia il codice sorgente

Implement some more GETINFO goodness: expose helper nodes, config options, getinfo keys.

svn:r4694
Nick Mathewson 19 anni fa
parent
commit
4cb89fd557
6 ha cambiato i file con 224 aggiunte e 37 eliminazioni
  1. 9 5
      doc/TODO
  2. 39 0
      doc/control-spec.txt
  3. 50 3
      src/or/circuitbuild.c
  4. 89 29
      src/or/config.c
  5. 34 0
      src/or/control.c
  6. 3 0
      src/or/or.h

+ 9 - 5
doc/TODO

@@ -78,12 +78,16 @@ for 0.1.1.x:
         o Implement main controller interface
         o Glue code
         o Testing
-N - Additional controller features
-      - Expose more information via getinfo
+N . Additional controller features
+      . Expose more information via getinfo:
         o Accounting status
-        - Helper node status
-        - Review all static fields for candidates
-        - List of available getinfo/getconf fields.
+        o Helper node status
+          o Document
+          o Implement
+        o List of available getinfo/getconf fields.
+          o Document
+          o Implement
+        - Review all static fields for additional candidates
       - Allow EXTENDCIRCUIT to unknown server.
       - We need some way to adjust server status, and to tell tor not to
         download directories/network-status, and a way to force a download.

+ 39 - 0
doc/control-spec.txt

@@ -325,6 +325,45 @@ $Id$
       form:
          ServerID SP ORStatus CRLF
 
+    "helper-nodes"
+      A series of lines listing the currently chosen helper nodes, if any.
+      Each is of the form:
+         ServerID  SP ((("down" / "unlisted") ISOTime) / "up")  CRLF
+
+    "accounting/enabled"
+    "accounting/hibernating"
+    "accounting/bytes"
+    "accounting/bytes-left"
+    "accounting/interval-start"
+    "accounting/interval-wake"
+    "accounting/interval-end"
+      Information about accounting status.  If accounting is enabled,
+      "enabled" is 1; otherwise it is 0.  The "hibernating" field is "hard"
+      if we are accepting no data; "soft" if we're accepting no new
+      connections, and "awake" if we're not hibernating at all.  The "bytes"
+      and "bytes-left" fields contain (read-bytes SP write-bytes), for the
+      start and the rest of the interval respectively.  The 'interval-start'
+      and 'interval-end' fields are the borders of the current interval; the
+      'interval-wake' field is the time within the current interval (if any)
+      where we plan[ned] to start being active.
+
+    "config/names"
+      A series of lines listing the available configuration options. Each is
+      of the form:
+         OptionName SP OptionType [ SP Documentation ] CRLF
+         OptionName = Keyword
+         OptionType = "Integer" / "TimeInterval" / "DataSize" / "Float" /
+           "Boolean" / "Time" / "CommaList" / "Dependant" / "Virtual" /
+           "String" / "LineList"
+         Documentation = Text
+
+    "info/names"
+      A series of lines listing the available GETINFO options.  Each is of
+      one of thes forms:
+         OptionName SP Documentation CRLF
+         OptionPrefix SP Documentation CRLF
+         OptionPrefix = OptionName "/*"
+
   Examples:
      C: GETINFO version desc/name/moria1
      S: 250+desc/name/moria=

+ 50 - 3
src/or/circuitbuild.c

@@ -1621,11 +1621,12 @@ static void
 pick_helper_nodes(void)
 {
   or_options_t *options = get_options();
+  int changed = 0;
 
   if (! options->UseHelperNodes)
     return;
 
-  if (helper_nodes == NULL)
+  if (!helper_nodes)
     helper_nodes = smartlist_create();
 
   while (smartlist_len(helper_nodes) < options->NumHelperNodes) {
@@ -1637,8 +1638,10 @@ pick_helper_nodes(void)
     strlcpy(helper->nickname, entry->nickname, sizeof(helper->nickname));
     memcpy(helper->identity, entry->identity_digest, DIGEST_LEN);
     smartlist_add(helper_nodes, helper);
-    helper_nodes_changed();
+    changed = 1;
   }
+  if (changed)
+    helper_nodes_changed();
 }
 
 /** Remove all elements from the list of helper nodes */
@@ -1810,8 +1813,9 @@ choose_random_helper(void)
  retry:
   SMARTLIST_FOREACH(helper_nodes, helper_node_t *, helper,
                     if (! helper->down_since && ! helper->unlisted_since) {
-                      if ((r = router_get_by_digest(helper->identity)))
+                      if ((r = router_get_by_digest(helper->identity))) {
                         smartlist_add(live_helpers, r);
+                      }
                     });
 
   if (! smartlist_len(live_helpers)) {
@@ -1909,6 +1913,8 @@ helper_nodes_update_state(or_state_t *state)
   config_free_lines(state->HelperNodes);
   next = &state->HelperNodes;
   *next = NULL;
+  if (!helper_nodes)
+    helper_nodes = smartlist_create();
   SMARTLIST_FOREACH(helper_nodes, helper_node_t *, h,
     {
       char dbuf[HEX_DIGEST_LEN+1];
@@ -1939,3 +1945,44 @@ helper_nodes_update_state(or_state_t *state)
 
   return 1;
 }
+
+/** DOCDOC */
+int
+helper_nodes_getinfo_helper(const char *question, char **answer)
+{
+  if (!strcmp(question,"helper-nodes")) {
+    smartlist_t *sl = smartlist_create();
+    char tbuf[ISO_TIME_LEN+1];
+    char dbuf[HEX_DIGEST_LEN+1];
+    if (!helper_nodes)
+      helper_nodes = smartlist_create();
+    SMARTLIST_FOREACH(helper_nodes, helper_node_t *, h,
+      {
+        size_t len = HEX_DIGEST_LEN+ISO_TIME_LEN+16;
+        char *c = tor_malloc(len);
+        const char *status = NULL;
+        time_t when = 0;
+        if (h->unlisted_since) {
+          when = h->unlisted_since;
+          status = "unlisted";
+        } else if (h->down_since) {
+          when = h->down_since;
+          status = "down";
+        } else {
+          status = "up";
+        }
+        base16_encode(dbuf, sizeof(dbuf), h->identity, DIGEST_LEN);
+        if (when) {
+          format_iso_time(tbuf, when);
+          tor_snprintf(c, len, "$%s %s %s\n", dbuf, status, tbuf);
+        } else {
+          tor_snprintf(c, len, "$%s %s\n", dbuf, status);
+        }
+        smartlist_add(sl, c);
+      });
+    *answer = smartlist_join_strings(sl, "", 0, NULL);
+    SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
+    smartlist_free(sl);
+  }
+  return 0;
+}

+ 89 - 29
src/or/config.c

@@ -218,7 +218,7 @@ typedef struct config_var_description_t {
 } config_var_description_t;
 
 static config_var_description_t options_description[] = {
-  { "Address", "The advertised (external) address we should use" },
+  { "Address", "The advertised (external) address we should use." },
   // { "AccountingStart", ""},
   { NULL, NULL },
 };
@@ -294,7 +294,7 @@ static void check_libevent_version(const char *m, const char *v, int server);
 
 #define OR_OPTIONS_MAGIC 9090909
 
-static config_format_t config_format = {
+static config_format_t options_format = {
   sizeof(or_options_t),
   OR_OPTIONS_MAGIC,
   STRUCT_OFFSET(or_options_t, _magic),
@@ -351,14 +351,14 @@ void
 set_options(or_options_t *new_val)
 {
   if (global_options)
-    config_free(&config_format, global_options);
+    config_free(&options_format, global_options);
   global_options = new_val;
 }
 
 void
 config_free_all(void)
 {
-  config_free(&config_format, global_options);
+  config_free(&options_format, global_options);
   tor_free(config_fname);
 }
 
@@ -568,7 +568,7 @@ config_get_commandlines(int argc, char **argv)
     while (*s == '-')
       s++;
 
-    (*new)->key = tor_strdup(expand_abbrev(&config_format, s, 1));
+    (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1));
     (*new)->value = tor_strdup(argv[i+1]);
     (*new)->next = NULL;
     log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
@@ -650,6 +650,18 @@ config_free_lines(config_line_t *front)
   }
 }
 
+/** DOCDOC */
+static const char *
+config_find_description(config_format_t *fmt, const char *name)
+{
+  int i;
+  for (i=0; fmt->descriptions[i].name; ++i) {
+    if (!strcasecmp(name, fmt->descriptions[i].name))
+      return fmt->descriptions[i].description;
+  }
+  return NULL;
+}
+
 /** If <b>key</b> is a configuration option, return the corresponding
  * config_var_t.  Otherwise, if <b>key</b> is a non-standard abbreviation,
  * warn, and return the corresponding config_var_t.  Otherwise return NULL.
@@ -663,8 +675,9 @@ config_find_option(config_format_t *fmt, const char *key)
     return NULL; /* if they say "--" on the commandline, it's not an option */
   /* First, check for an exact (case-insensitive) match */
   for (i=0; fmt->vars[i].name; ++i) {
-    if (!strcasecmp(key, fmt->vars[i].name))
+    if (!strcasecmp(key, fmt->vars[i].name)) {
       return &fmt->vars[i];
+    }
   }
   /* If none, check for an abbreviated match */
   for (i=0; fmt->vars[i].name; ++i) {
@@ -817,7 +830,7 @@ config_reset_line(config_format_t *fmt, or_options_t *options, const char *key)
 int
 option_is_recognized(const char *key)
 {
-  config_var_t *var = config_find_option(&config_format, key);
+  config_var_t *var = config_find_option(&options_format, key);
   return (var != NULL);
 }
 
@@ -825,7 +838,7 @@ option_is_recognized(const char *key)
 const char *
 option_get_canonical_name(const char *key)
 {
-  config_var_t *var = config_find_option(&config_format, key);
+  config_var_t *var = config_find_option(&options_format, key);
   return var->name;
 }
 
@@ -834,7 +847,7 @@ option_get_canonical_name(const char *key)
 config_line_t *
 option_get_assignment(or_options_t *options, const char *key)
 {
-  return get_assigned_option(&config_format, options, key);
+  return get_assigned_option(&options_format, options, key);
 }
 
 static config_line_t *
@@ -990,20 +1003,20 @@ int
 options_trial_assign(config_line_t *list, int reset)
 {
   int r;
-  or_options_t *trial_options = options_dup(&config_format, get_options());
+  or_options_t *trial_options = options_dup(&options_format, get_options());
 
-  if ((r=config_assign(&config_format, trial_options, list, reset)) < 0) {
-    config_free(&config_format, trial_options);
+  if ((r=config_assign(&options_format, trial_options, list, reset)) < 0) {
+    config_free(&options_format, trial_options);
     return r;
   }
 
   if (options_validate(trial_options) < 0) {
-    config_free(&config_format, trial_options);
+    config_free(&options_format, trial_options);
     return -2;
   }
 
   if (options_transition_allowed(get_options(), trial_options) < 0) {
-    config_free(&config_format, trial_options);
+    config_free(&options_format, trial_options);
     return -3;
   }
 
@@ -1320,7 +1333,7 @@ options_dup(config_format_t *fmt, or_options_t *old)
 void
 options_init(or_options_t *options)
 {
-  config_init(&config_format, options);
+  config_init(&options_format, options);
 }
 
 /* DOCDOC */
@@ -1347,7 +1360,8 @@ config_dump(config_format_t *fmt, void *options, int minimal)
   or_options_t *defaults;
   config_line_t *line;
   char *result;
-  int i, j;
+  int i;
+  const char *desc;
 
   defaults = config_alloc(fmt);
   config_init(fmt, defaults);
@@ -1364,15 +1378,13 @@ config_dump(config_format_t *fmt, void *options, int minimal)
     if (minimal && option_is_same(fmt, options, defaults, fmt->vars[i].name))
       continue;
 
-    for (j=0; fmt->descriptions[j].name; ++j) {
-      if (!strcasecmp(fmt->vars[i].name, fmt->descriptions[j].name)) {
-        const char *desc = fmt->descriptions[j].description;
-        size_t len = strlen(desc)+8;
-        char *tmp = tor_malloc(len);
-        tor_snprintf(tmp, len, "# %s\n",desc);
-        smartlist_add(elements, tmp);
-        break;
-      }
+
+    desc = config_find_description(fmt, fmt->vars[i].name);
+    if (desc) {
+      size_t len = strlen(desc)+8;
+      char *tmp = tor_malloc(len);
+      tor_snprintf(tmp, len, "# %s\n",desc);
+      smartlist_add(elements, tmp);
     }
 
     line = get_assigned_option(fmt, options, fmt->vars[i].name);
@@ -1402,7 +1414,7 @@ config_dump(config_format_t *fmt, void *options, int minimal)
 char *
 options_dump(or_options_t *options, int minimal)
 {
-  return config_dump(&config_format, options, minimal);
+  return config_dump(&options_format, options, minimal);
 }
 
 static int
@@ -2053,7 +2065,7 @@ options_init_from_torrc(int argc, char **argv)
     tor_free(cf);
     if (retval < 0)
       goto err;
-    retval = config_assign(&config_format, newoptions, cl, 0);
+    retval = config_assign(&options_format, newoptions, cl, 0);
     config_free_lines(cl);
     if (retval < 0)
       goto err;
@@ -2061,7 +2073,7 @@ options_init_from_torrc(int argc, char **argv)
 
   /* Go through command-line variables too */
   cl = config_get_commandlines(argc,argv);
-  retval = config_assign(&config_format, newoptions,cl,0);
+  retval = config_assign(&options_format, newoptions,cl,0);
   config_free_lines(cl);
   if (retval < 0)
     goto err;
@@ -2083,7 +2095,7 @@ options_init_from_torrc(int argc, char **argv)
   return 0;
  err:
   tor_free(fname);
-  config_free(&config_format, newoptions);
+  config_free(&options_format, newoptions);
   return -1;
 }
 
@@ -3050,6 +3062,54 @@ or_state_save(void)
   return 0;
 }
 
+/** DOCDOC */
+int
+config_getinfo_helper(const char *question, char **answer)
+{
+  if (!strcmp(question, "config/names")) {
+    smartlist_t *sl = smartlist_create();
+    int i;
+    for (i = 0; _option_vars[i].name; ++i) {
+      config_var_t *var = &_option_vars[i];
+      const char *type, *desc;
+      char *line;
+      size_t len;
+      desc = config_find_description(&options_format, var->name);
+      switch (var->type) {
+        case CONFIG_TYPE_STRING: type = "String"; break; 
+        case CONFIG_TYPE_UINT: type = "Integer"; break;
+        case CONFIG_TYPE_INTERVAL: type = "TimeInterval"; break; 
+        case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break;
+        case CONFIG_TYPE_DOUBLE: type = "Float"; break;
+        case CONFIG_TYPE_BOOL: type = "Boolean"; break;
+        case CONFIG_TYPE_ISOTIME: type = "Time"; break;
+        case CONFIG_TYPE_CSV: type = "CommaList"; break;
+        case CONFIG_TYPE_LINELIST: type = "LineList"; break;
+        case CONFIG_TYPE_LINELIST_S: type = "Dependant"; break;
+        case CONFIG_TYPE_LINELIST_V: type = "Virtual"; break;
+        default:
+        case CONFIG_TYPE_OBSOLETE:
+          type = NULL; break;
+      }
+      if (!type)
+        continue;
+      len = strlen(var->name)+strlen(type)+16;
+      if (desc)
+        len += strlen(desc);
+      line = tor_malloc(len);
+      if (desc)
+        tor_snprintf(line, len, "%s %s %s\n",var->name,type,desc);
+      else
+        tor_snprintf(line, len, "%s %s\n",var->name,type);
+      smartlist_add(sl, line);
+    }
+    *answer = smartlist_join_strings(sl, "", 0, NULL);
+    SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
+    smartlist_free(sl);
+  }
+  return 0;
+}
+
 /** Dump the version of every file to the log. */
 static void
 print_cvs_version(void)

+ 34 - 0
src/or/control.c

@@ -1112,6 +1112,34 @@ handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
   return 0;
 }
 
+/** DOCDOC */
+static char *
+list_getinfo_options(void)
+{
+  return tor_strdup(
+    "accounting/bytes Number of bytes read/written so far in interval.\n"
+    "accounting/bytes-left Number of bytes left to read/write in interval.\n"
+    "accounting/enabled Is accounting currently enabled?\n"
+    "accounting/hibernating Are we hibernating or awake?\n"
+    "accounting/interval-end Time when interval ends.\n"
+    "accounting/interval-start Time when interval starts.\n"
+    "accounting/interval-wake Time to wake up in this interval.\n"
+    "addr-mappings/all All current remapped addresses.\n"
+    "addr-mappings/cache Addresses remapped by DNS cache.\n"
+    "addr-mappings/configl Addresses remapped from configuration options.\n"
+    "addr-mappings/control Addresses remapped by a controller.\n"
+    "circuit-status Status of each current circuit.\n"
+    "config/names List of configuration options, types, and documentation.\n"
+    "desc/id/* Server descriptor by hex ID\n"
+    "desc/name/* Server descriptor by nickname.\n"
+    "helper-nodes Which nodes will we use as helpers?\n"
+    "info/names List of GETINFO options, types, and documentation.\n"
+    "network-status List of hex IDs, nicknames, server statuses.\n"
+    "orconn-status Status of each current OR connection.\n"
+    "stream-status Status of each current application stream.\n"
+    "version The current version of Tor.\n");
+}
+
 /** Lookup the 'getinfo' entry <b>question</b>, and return
  * the answer in <b>*answer</b> (or NULL if key not recognized).
  * Return 0 if success, or -1 if internal error. */
@@ -1123,6 +1151,12 @@ handle_getinfo_helper(const char *question, char **answer)
     *answer = tor_strdup(VERSION);
   } else if (!strcmpstart(question, "accounting/")) {
     return accounting_getinfo_helper(question, answer);
+  } else if (!strcmpstart(question, "helper-nodes")) {
+    return helper_nodes_getinfo_helper(question, answer);
+  } else if (!strcmpstart(question, "config/")) {
+    return config_getinfo_helper(question, answer);
+  } else if (!strcmp(question, "info/names")) {
+    *answer = list_getinfo_options();
   } else if (!strcmpstart(question, "desc/id/")) {
     routerinfo_t *ri = router_get_by_hexdigest(question+strlen("desc/id/"));
     if (ri && ri->signed_descriptor)

+ 3 - 0
src/or/or.h

@@ -1279,6 +1279,7 @@ void helper_node_set_status(const char *digest, int succeeded);
 void helper_nodes_set_status_from_directory(void);
 int helper_nodes_update_state(or_state_t *state);
 int helper_nodes_parse_state(or_state_t *state, int set, const char **err);
+int helper_nodes_getinfo_helper(const char *question, char **answer);
 
 /********************************* circuitlist.c ***********************/
 
@@ -1372,6 +1373,8 @@ or_state_t *get_or_state(void);
 int or_state_load(void);
 int or_state_save(void);
 
+int config_getinfo_helper(const char *question, char **answer);
+
 /********************************* connection.c ***************************/
 
 const char *conn_type_to_string(int type);