[or-cvs] Support code for resettable options, and option sets. Stil...
Nick Mathewson
nickm at seul.org
Thu Nov 4 22:31:52 UTC 2004
Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv20916/src/or
Modified Files:
control.c config.c
Log Message:
Support code for resettable options, and option sets. Still needs validate-and-then-replace logic
Index: control.c
===================================================================
RCS file: /home/or/cvsroot/src/or/control.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- control.c 3 Nov 2004 21:53:54 -0000 1.5
+++ control.c 4 Nov 2004 22:31:50 -0000 1.6
@@ -59,7 +59,7 @@
const char *message);
static void send_control_event(uint16_t event, uint16_t len, const char *body);
static int handle_control_setconf(connection_t *conn, uint16_t len,
- const char *body);
+ char *body);
static int handle_control_getconf(connection_t *conn, uint16_t len,
const char *body);
static int handle_control_setevents(connection_t *conn, uint16_t len,
@@ -139,58 +139,81 @@
static int
handle_control_setconf(connection_t *conn, uint16_t len,
- const char *body)
+ char *body)
{
+ char *k, *v;
+ struct config_line_t *lines = NULL;
+
+ /* XXXX009 move this logic into config.c someplace. */
+
+ do {
+ body = parse_line_from_str(body, &k, &v);
+ if (!body) {
+ goto err;
+ }
+ if (k && v)
+ lines = config_line_prepend(lines, k, v);
+ } while (*body);
+
/* XXXX009 NM */
+
+ return 0;
+ err:
+ send_control_error(conn, ERR_UNSPECIFIED, "Couldn't parse configuration");
+ /* config_free_lines(lines); */
return 0;
}
-static int handle_control_getconf(connection_t *conn, uint16_t body_len,
+static int
+handle_control_getconf(connection_t *conn, uint16_t body_len,
const char *body)
{
- smartlist_t *answer_elements = NULL;
+ smartlist_t *questions = NULL;
+ smartlist_t *answers = NULL;
char *msg = NULL;
size_t msg_len;
- if (body[body_len-1] != '\0') {
- send_control_error(conn, ERR_UNSPECIFIED,
- "getconf message body not nul-terminated.");
- return 0;
- }
- /* Now we can be sure that body will end in a nul-terminated string. */
-
- answer_elements = smartlist_create();
- while (body_len) {
- size_t question_len = strlen(body);
- struct config_line_t *answer = config_get_assigned_option(&options,body);
+ questions = smartlist_create();
+ smartlist_split_string(questions, body, "\n",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ answers = smartlist_create();
+ SMARTLIST_FOREACH(questions, const char *, q,
+ {
+ struct config_line_t *answer = config_get_assigned_option(&options,q);
if (!answer) {
send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body);
goto done;
} else {
while (answer) {
struct config_line_t *next;
- smartlist_add(answer_elements, answer->key);
- smartlist_add(answer_elements, answer->value);
+ size_t alen = strlen(answer->key)+strlen(answer->value)+2;
+ char *astr = tor_malloc(alen);
+ tor_snprintf(astr, alen, "%s %s\n", answer->key, answer->value);
+ smartlist_add(answers, astr);
+
next = answer->next;
+ tor_free(answer->key);
+ tor_free(answer->value);
tor_free(answer);
answer = next;
}
}
- body += question_len+1;
- body_len -= question_len+1;
- }
+ });
- msg = smartlist_join_strings2(answer_elements, "\0", 1, 0, &msg_len);
+ msg = smartlist_join_strings(answers, "", 0, &msg_len);
send_control_message(conn, CONTROL_CMD_CONFVALUE,
(uint16_t)msg_len, msg);
done:
- SMARTLIST_FOREACH(answer_elements, char *, cp, tor_free(cp));
- smartlist_free(answer_elements);
+ if (answers) SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp));
+ if (questions) SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp));
+ smartlist_free(answers);
+ smartlist_free(questions);
tor_free(msg);
return 0;
}
+
static int handle_control_setevents(connection_t *conn, uint16_t len,
const char *body)
{
@@ -218,6 +241,7 @@
send_control_done(conn);
return 0;
}
+
static int handle_control_authenticate(connection_t *conn, uint16_t len,
const char *body)
{
Index: config.c
===================================================================
RCS file: /home/or/cvsroot/src/or/config.c,v
retrieving revision 1.204
retrieving revision 1.205
diff -u -d -r1.204 -r1.205
--- config.c 4 Nov 2004 10:23:29 -0000 1.204
+++ config.c 4 Nov 2004 22:31:50 -0000 1.205
@@ -23,6 +23,11 @@
CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and optional
* whitespace. */
CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
+ CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines,
+ * mixed with other keywords. */
+ CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize
+ * context-sensitive config lines when fetching.
+ */
CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
} config_type_t;
@@ -106,14 +111,16 @@
VAR("Group", STRING, Group, NULL),
VAR("HashedControlPassword",STRING, HashedControlPassword, NULL),
VAR("HttpProxy", STRING, HttpProxy, NULL),
- VAR("HiddenServiceDir", LINELIST, RendConfigLines, NULL),
- VAR("HiddenServicePort", LINELIST, RendConfigLines, NULL),
- VAR("HiddenServiceNodes", LINELIST, RendConfigLines, NULL),
- VAR("HiddenServiceExcludeNodes", LINELIST, RendConfigLines,NULL),
+ VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL),
+ VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServiceNodes", LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServiceExcludeNodes", LINELIST_S, RendConfigLines, NULL),
VAR("IgnoreVersion", BOOL, IgnoreVersion, "0"),
VAR("KeepalivePeriod", UINT, KeepalivePeriod, "300"),
- VAR("LogLevel", LINELIST, LogOptions, NULL),
- VAR("LogFile", LINELIST, LogOptions, NULL),
+ VAR("LogOptions", LINELIST_V, LogOptions, NULL),
+ VAR("LogLevel", LINELIST_S, LogOptions, NULL),
+ VAR("LogFile", LINELIST_S, LogOptions, NULL),
OBSOLETE("LinkPadding"),
VAR("MaxConn", UINT, MaxConn, "1024"),
VAR("MaxOnionsPending", UINT, MaxOnionsPending, "100"),
@@ -137,7 +144,7 @@
VAR("SocksPort", UINT, SocksPort, "9050"),
VAR("SocksBindAddress", LINELIST, SocksBindAddress, NULL),
VAR("SocksPolicy", LINELIST, SocksPolicy, NULL),
- VAR("SysLog", LINELIST, LogOptions, NULL),
+ VAR("SysLog", LINELIST_S, LogOptions, NULL),
OBSOLETE("TrafficShaping"),
VAR("User", STRING, User, NULL),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
@@ -151,13 +158,16 @@
static struct config_line_t *config_get_commandlines(int argc, char **argv);
static int config_get_lines(FILE *f, struct config_line_t **result);
static void config_free_lines(struct config_line_t *front);
-static int config_assign_line(or_options_t *options, struct config_line_t *c);
-static int config_assign(or_options_t *options, struct config_line_t *list);
+static int config_assign_line(or_options_t *options, struct config_line_t *c,
+ int reset);
+static int config_assign(or_options_t *options, struct config_line_t *list,
+ int reset);
static int parse_dir_server_line(const char *line);
static int parse_redirect_line(or_options_t *options,
struct config_line_t *line);
static const char *expand_abbrev(const char *option, int commandline_only);
static config_var_t *config_find_option(const char *key);
+static void reset_option(or_options_t *options, config_var_t *var);
/** If <b>option</b> is an official abbreviation for a longer option,
* return the longer option. Otherwise return <b>option</b>.
@@ -216,7 +226,7 @@
/** Helper: allocate a new configuration option mapping 'key' to 'val',
* prepend it to 'front', and return the newly allocated config_line_t */
-static struct config_line_t *
+struct config_line_t *
config_line_prepend(struct config_line_t *front,
const char *key,
const char *val)
@@ -298,9 +308,13 @@
}
/** If <b>c</b> is a syntactically valid configuration line, update
- * <b>options</b> with its value and return 0. Otherwise return -1. */
+ * <b>options</b> with its value and return 0. Otherwise return -1.
+ *
+ * If 'reset' is set, and we get a line containing no value, restore the
+ * option to its default value.
+ */
static int
-config_assign_line(or_options_t *options, struct config_line_t *c)
+config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
{
int i, ok;
config_var_t *var;
@@ -311,13 +325,17 @@
log_fn(LOG_WARN, "Unknown option '%s'. Failing.", c->key);
return -1;
}
-
/* Put keyword into canonical case. */
if (strcmp(var->name, c->key)) {
tor_free(c->key);
c->key = tor_strdup(var->name);
}
+ if (reset && !strlen(c->value)) {
+ reset_option(options, var);
+ return 0;
+ }
+
lvalue = ((char*)options) + var->var_offset;
switch(var->type) {
@@ -357,22 +375,43 @@
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
break;
- case CONFIG_TYPE_LINELIST:
- /* Note: this reverses the order that the lines appear in. That's
- * just fine, since we build up the list of lines reversed in the
- * first place. */
- *(struct config_line_t**)lvalue =
- config_line_prepend(*(struct config_line_t**)lvalue, c->key, c->value);
- break;
+
+ case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_S:
+ /* Note: this reverses the order that the lines appear in. That's
+ * just fine, since we build up the list of lines reversed in the
+ * first place. */
+ *(struct config_line_t**)lvalue =
+ config_line_prepend(*(struct config_line_t**)lvalue, c->key, c->value);
+ break;
case CONFIG_TYPE_OBSOLETE:
log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
break;
+ case CONFIG_TYPE_LINELIST_V:
+ log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
+ return -1;
+ default:
+ tor_assert(0);
+ break;
}
return 0;
}
+/** restore the option named <b>key</b> in options to its default value. */
+static void
+config_reset_line(or_options_t *options, const char *key)
+{
+ config_var_t *var;
+
+ var = config_find_option(key);
+ if (!var)
+ return; /* give error on next pass. */
+
+ reset_option(options, var);
+}
+
/** Return a canonicalized list of the options assigned for key.
*/
struct config_line_t *
@@ -387,10 +426,14 @@
if (!var) {
log_fn(LOG_WARN, "Unknown option '%s'. Failing.", key);
return NULL;
+ } else if (var->type == CONFIG_TYPE_LINELIST_S) {
+ log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
+ return NULL;
}
value = ((char*)options) + var->var_offset;
- if (var->type == CONFIG_TYPE_LINELIST) {
+ if (var->type == CONFIG_TYPE_LINELIST ||
+ var->type == CONFIG_TYPE_LINELIST_V) {
/* Linelist requires special handling: we just copy and return it. */
const struct config_line_t *next_in = value;
struct config_line_t **next_out = &result;
@@ -442,18 +485,36 @@
/** Iterate through the linked list of requested options <b>list</b>.
* For each item, convert as appropriate and assign to <b>options</b>.
* If an item is unrecognized, return -1 immediately,
- * else return 0 for success. */
+ * else return 0 for success.
+ *
+ * If <b>reset</b>, then interpret empty lines as meaning "restore to
+ * default value", and interpret LINELIST* options as replacing (not
+ * extending) their previous values.
+ */
static int
-config_assign(or_options_t *options, struct config_line_t *list)
+config_assign(or_options_t *options, struct config_line_t *list, int reset)
{
- while (list) {
- const char *full = expand_abbrev(list->key, 0);
- if (strcmp(full,list->key)) {
- tor_free(list->key);
- list->key = tor_strdup(full);
+ struct config_line_t *p;
+
+ /* pass 1: normalize keys */
+ for (p = list; p; p = p->next) {
+ const char *full = expand_abbrev(p->key, 0);
+ if (strcmp(full,p->key)) {
+ tor_free(p->key);
+ p->key = tor_strdup(full);
}
+ }
- if (config_assign_line(options, list))
+ /* pass 2: if we're reading from a resetting souurce, clear all mentioned
+ * linelists. */
+ if (reset) {
+ for (p = list; p; p = p->next)
+ config_reset_line(options, p->key);
+ }
+
+ /* pass 3: assign. */
+ while (list) {
+ if (config_assign_line(options, list, reset))
return -1;
list = list->next;
}
@@ -604,6 +665,7 @@
tor_free(*(char **)lvalue);
break;
case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_V:
config_free_lines(*(struct config_line_t**)lvalue);
*(struct config_line_t**)lvalue = NULL;
break;
@@ -614,6 +676,9 @@
*(smartlist_t**)lvalue = NULL;
}
break;
+ case CONFIG_TYPE_LINELIST_S:
+ /* will be freed by corresponding LINELIST_V. */
+ break;
}
}
/* XXX this last part is an exception. can we make it not needed? */
@@ -625,13 +690,59 @@
}
}
+/** Replace the option indexed by <b>var</b> in <b>options</b> with its
+ * default value. */
+static void
+reset_option(or_options_t *options, config_var_t *var)
+{
+ struct config_line_t *c;
+ void *lvalue;
+
+ lvalue = ((char*)options) + var->var_offset;
+ switch (var->type) {
+ case CONFIG_TYPE_STRING:
+ tor_free(*(char**)lvalue);
+ break;
+ case CONFIG_TYPE_DOUBLE:
+ *(double*)lvalue = 0.0;
+ break;
+ case CONFIG_TYPE_UINT:
+ case CONFIG_TYPE_BOOL:
+ *(int*)lvalue = 0;
+ break;
+ case CONFIG_TYPE_CSV:
+ if (*(smartlist_t**)lvalue) {
+ SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp));
+ smartlist_free(*(smartlist_t **)lvalue);
+ *(smartlist_t **)lvalue = NULL;
+ }
+ break;
+ case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_S:
+ config_free_lines(*(struct config_line_t **)lvalue);
+ *(struct config_line_t **)lvalue = NULL;
+ break;
+ case CONFIG_TYPE_LINELIST_V:
+ /* handled by linelist_s. */
+ break;
+ case CONFIG_TYPE_OBSOLETE:
+ break;
+ }
+ if (var->initvalue) {
+ c = tor_malloc(sizeof(struct config_line_t));
+ c->key = tor_strdup(var->name);
+ c->value = tor_strdup(var->initvalue);
+ config_assign_line(options,c,0);
+ config_free_lines(c);
+ }
+}
+
/** Set <b>options</b> to hold reasonable defaults for most options.
* Each option defaults to zero. */
static void
init_options(or_options_t *options)
{
int i;
- struct config_line_t *c;
config_var_t *var;
memset(options,0,sizeof(or_options_t));
@@ -639,11 +750,7 @@
var = &config_vars[i];
if(!var->initvalue)
continue; /* defaults to NULL or 0 */
- c = tor_malloc(sizeof(struct config_line_t));
- c->key = tor_strdup(var->name);
- c->value = tor_strdup(var->initvalue);
- config_assign_line(options,c);
- config_free_lines(c);
+ reset_option(options, var);
}
}
@@ -1048,7 +1155,7 @@
tor_free(fname);
if (config_get_lines(cf, &cl)<0)
return -1;
- if (config_assign(options,cl) < 0)
+ if (config_assign(options,cl, 0) < 0)
return -1;
config_free_lines(cl);
fclose(cf);
@@ -1056,7 +1163,7 @@
/* go through command-line variables too */
cl = config_get_commandlines(argc,argv);
- if (config_assign(options,cl) < 0)
+ if (config_assign(options,cl,0) < 0)
return -1;
config_free_lines(cl);
More information about the tor-commits
mailing list