[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] Support code for resettable options, and option sets. Stil...



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);