diff options
author | Nick Mathewson <nickm@torproject.org> | 2005-08-04 19:56:41 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2005-08-04 19:56:41 +0000 |
commit | 4cb89fd557db8ac66234f94f922fd5b4a371a9e0 (patch) | |
tree | f633228bf564133260a830fa4c7f85c0d072f783 | |
parent | 5b3286179cf74ad90555a352145c66428834fbb5 (diff) | |
download | tor-4cb89fd557db8ac66234f94f922fd5b4a371a9e0.tar.gz tor-4cb89fd557db8ac66234f94f922fd5b4a371a9e0.zip |
Implement some more GETINFO goodness: expose helper nodes, config options, getinfo keys.
svn:r4694
-rw-r--r-- | doc/TODO | 14 | ||||
-rw-r--r-- | doc/control-spec.txt | 39 | ||||
-rw-r--r-- | src/or/circuitbuild.c | 53 | ||||
-rw-r--r-- | src/or/config.c | 118 | ||||
-rw-r--r-- | src/or/control.c | 34 | ||||
-rw-r--r-- | src/or/or.h | 3 |
6 files changed, 224 insertions, 37 deletions
@@ -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. diff --git a/doc/control-spec.txt b/doc/control-spec.txt index 22edad6963..9ce1f60713 100644 --- a/doc/control-spec.txt +++ b/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= diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 9dcdde734b..0da796e412 100644 --- a/src/or/circuitbuild.c +++ b/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; +} diff --git a/src/or/config.c b/src/or/config.c index 94daaecb98..602362b165 100644 --- a/src/or/config.c +++ b/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) diff --git a/src/or/control.c b/src/or/control.c index 59fc7e55ab..b9032742b2 100644 --- a/src/or/control.c +++ b/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) diff --git a/src/or/or.h b/src/or/or.h index a31503b4d5..da6d261017 100644 --- a/src/or/or.h +++ b/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); |