[or-cvs] Make options no longer a global variable.

Roger Dingledine arma at seul.org
Sat Nov 6 05:18:15 UTC 2004


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/home2/arma/work/onion/cvs/src/or

Modified Files:
	circuitbuild.c circuitlist.c circuituse.c command.c config.c 
	connection.c connection_edge.c connection_or.c control.c 
	cpuworker.c directory.c dirserv.c dns.c hibernate.c main.c 
	onion.c or.h relay.c rendservice.c router.c routerlist.c 
	routerparse.c test.c 
Log Message:
Make options no longer a global variable.
Now we can try setting an option but back out if it fails to parse, or
  if it's disallowed (e.g. changing RunAsDaemon from 1 to 0).
Use parse_line_from_str rather than parse_line_from_file.


Index: circuitbuild.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuitbuild.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -d -r1.50 -r1.51
--- circuitbuild.c	4 Nov 2004 23:39:57 -0000	1.50
+++ circuitbuild.c	6 Nov 2004 05:18:10 -0000	1.51
@@ -9,8 +9,6 @@
 
 #include "or.h"
 
-extern or_options_t options; /* command-line and config-file options */
-
 /********* START VARIABLES **********/
 
 /** A global list of all circuits at this hop. */
@@ -149,7 +147,7 @@
      */
     return;
   }
-  if (server_mode()) {
+  if (server_mode(get_options())) {
     routerinfo_t *me = router_get_my_routerinfo();
     tor_assert(me);
     prev_digest = me->identity_digest;
@@ -354,7 +352,7 @@
    * compare keys, not nicknames...but older servers will compare nicknames.
    * Should we check server version from the most recent directory? Hm.
    */
-  circ_id_type = decide_circ_id_type(options.Nickname,
+  circ_id_type = decide_circ_id_type(get_options()->Nickname,
                                      circ->n_conn->nickname);
   circ->n_circ_id = get_unique_circ_id_by_conn(circ->n_conn, circ_id_type);
   if(!circ->n_circ_id) {
@@ -830,9 +828,10 @@
   int n_best_support=0;
   smartlist_t *sl, *preferredexits, *preferredentries, *excludedexits;
   routerinfo_t *router;
+  or_options_t *options = get_options();
 
   preferredentries = smartlist_create();
-  add_nickname_list_to_smartlist(preferredentries,options.EntryNodes,1);
+  add_nickname_list_to_smartlist(preferredentries,options->EntryNodes,1);
 
   get_connection_array(&carray, &n_connections);
 
@@ -871,7 +870,7 @@
       continue; /* skip routers that are known to be down */
     }
     if(!router->is_verified &&
-       (!(options._AllowUnverified & ALLOW_UNVERIFIED_EXIT) ||
+       (!(options->_AllowUnverified & ALLOW_UNVERIFIED_EXIT) ||
          router_is_unreliable_router(router, 1, 1))) {
       /* if it's unverified, and either we don't want it or it's unsuitable */
       n_supported[i] = -1;
@@ -923,10 +922,10 @@
          n_best_support, best_support, n_pending_connections);
 
   preferredexits = smartlist_create();
-  add_nickname_list_to_smartlist(preferredexits,options.ExitNodes,1);
+  add_nickname_list_to_smartlist(preferredexits,options->ExitNodes,1);
 
   excludedexits = smartlist_create();
-  add_nickname_list_to_smartlist(excludedexits,options.ExcludeNodes,0);
+  add_nickname_list_to_smartlist(excludedexits,options->ExcludeNodes,0);
 
   sl = smartlist_create();
 
@@ -938,7 +937,7 @@
         smartlist_add(sl, smartlist_get(dir->routers, i));
 
     smartlist_subtract(sl,excludedexits);
-    if (options.StrictExitNodes || smartlist_overlap(sl,preferredexits))
+    if (options->StrictExitNodes || smartlist_overlap(sl,preferredexits))
       smartlist_intersect(sl,preferredexits);
     router = routerlist_sl_choose_by_bandwidth(sl);
   } else {
@@ -952,7 +951,7 @@
         smartlist_add(sl, smartlist_get(dir->routers, i));
 
     smartlist_subtract(sl,excludedexits);
-    if (options.StrictExitNodes || smartlist_overlap(sl,preferredexits))
+    if (options->StrictExitNodes || smartlist_overlap(sl,preferredexits))
       smartlist_intersect(sl,preferredexits);
     router = routerlist_sl_choose_by_bandwidth(sl);
   }
@@ -966,7 +965,7 @@
     log_fn(LOG_INFO, "Chose exit server '%s'", router->nickname);
     return router;
   }
-  if (options.StrictExitNodes)
+  if (options->StrictExitNodes)
     log_fn(LOG_WARN, "No exit routers seem to be running; can't choose an exit.");
 
   return NULL;
@@ -985,12 +984,13 @@
 static routerinfo_t *choose_good_exit_server(uint8_t purpose, routerlist_t *dir)
 {
   routerinfo_t *r;
+  or_options_t *options = get_options();
   switch(purpose) {
     case CIRCUIT_PURPOSE_C_GENERAL:
       return choose_good_exit_server_general(dir);
     case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
-      r = router_choose_random_node(options.RendNodes, options.RendExcludeNodes,
-          NULL, 0, 1, options._AllowUnverified & ALLOW_UNVERIFIED_RENDEZVOUS, 0);
+      r = router_choose_random_node(options->RendNodes, options->RendExcludeNodes,
+          NULL, 0, 1, options->_AllowUnverified & ALLOW_UNVERIFIED_RENDEZVOUS, 0);
       return r;
   }
   log_fn(LOG_WARN,"Unhandled purpose %d", purpose);
@@ -1008,10 +1008,11 @@
   int r;
   cpath_build_state_t *info;
   routerinfo_t *exit;
+
   router_get_routerlist(&rl);
   if (!rl)
     return NULL;
-  r = new_route_len(options.PathlenCoinWeight, purpose, rl->routers);
+  r = new_route_len(get_options()->PathlenCoinWeight, purpose, rl->routers);
   if (r < 1) /* must be at least 1 */
     return NULL;
   info = tor_malloc_zero(sizeof(cpath_build_state_t));
@@ -1112,8 +1113,8 @@
       routerlist_add_family(excluded, r);
     }
   }
-  choice = router_choose_random_node(NULL, options.ExcludeNodes, excluded,
-           0, 1, options._AllowUnverified & ALLOW_UNVERIFIED_MIDDLE, 0);
+  choice = router_choose_random_node(NULL, get_options()->ExcludeNodes, excluded,
+           0, 1, get_options()->_AllowUnverified & ALLOW_UNVERIFIED_MIDDLE, 0);
   smartlist_free(excluded);
   return choice;
 }
@@ -1122,6 +1123,7 @@
 {
   routerinfo_t *r, *choice;
   smartlist_t *excluded = smartlist_create();
+  or_options_t *options = get_options();
   char buf[16];
 
   if((r = router_get_by_digest(state->chosen_exit_digest))) {
@@ -1132,7 +1134,7 @@
     smartlist_add(excluded, r);
     routerlist_add_family(excluded, r);
   }
-  if(options.FascistFirewall) {
+  if(options->FascistFirewall) {
     /* exclude all ORs that listen on the wrong port */
     routerlist_t *rl;
     int i;
@@ -1144,13 +1146,13 @@
     for(i=0; i < smartlist_len(rl->routers); i++) {
       r = smartlist_get(rl->routers, i);
       tor_snprintf(buf, sizeof(buf), "%d", r->or_port);
-      if (!smartlist_string_isin(options.FirewallPorts, buf))
+      if (!smartlist_string_isin(options->FirewallPorts, buf))
          smartlist_add(excluded, r);
     }
   }
-  choice = router_choose_random_node(options.EntryNodes, options.ExcludeNodes,
-           excluded, 0, 1, options._AllowUnverified & ALLOW_UNVERIFIED_ENTRY,
-           options.StrictEntryNodes);
+  choice = router_choose_random_node(options->EntryNodes, options->ExcludeNodes,
+           excluded, 0, 1, options->_AllowUnverified & ALLOW_UNVERIFIED_ENTRY,
+           options->StrictEntryNodes);
   smartlist_free(excluded);
   return choice;
 }
@@ -1188,7 +1190,7 @@
          state->desired_path_len);
 
   excludednodes = smartlist_create();
-  add_nickname_list_to_smartlist(excludednodes,options.ExcludeNodes,0);
+  add_nickname_list_to_smartlist(excludednodes,get_options()->ExcludeNodes,0);
 
   if(cur_len == state->desired_path_len - 1) { /* Picking last node */
     choice = router_get_by_digest(state->chosen_exit_digest);

Index: circuitlist.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuitlist.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- circuitlist.c	3 Nov 2004 18:33:06 -0000	1.15
+++ circuitlist.c	6 Nov 2004 05:18:10 -0000	1.16
@@ -9,8 +9,6 @@
 
 #include "or.h"
 
-extern or_options_t options; /* command-line and config-file options */
-
 /********* START VARIABLES **********/
 
 /** A global list of all circuits at this hop. */

Index: circuituse.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuituse.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- circuituse.c	3 Nov 2004 18:33:06 -0000	1.20
+++ circuituse.c	6 Nov 2004 05:18:10 -0000	1.21
@@ -9,8 +9,6 @@
 
 #include "or.h"
 
-extern or_options_t options; /* command-line and config-file options */
-
 /********* START VARIABLES **********/
 
 extern circuit_t *global_circuitlist; /* from circuitlist.c */
@@ -57,7 +55,7 @@
 
   if(purpose == CIRCUIT_PURPOSE_C_GENERAL)
     if(circ->timestamp_dirty &&
-       circ->timestamp_dirty+options.NewCircuitPeriod <= now)
+       circ->timestamp_dirty+get_options()->NewCircuitPeriod <= now)
       return 0;
 
   if(conn) {
@@ -264,7 +262,7 @@
     if(CIRCUIT_IS_ORIGIN(circ) && circ->state != CIRCUIT_STATE_OPEN &&
        !circ->marked_for_close && circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
        (!circ->timestamp_dirty ||
-        circ->timestamp_dirty + options.NewCircuitPeriod < now)) {
+        circ->timestamp_dirty + get_options()->NewCircuitPeriod < now)) {
       exitrouter = router_get_by_digest(circ->build_state->chosen_exit_digest);
       if(exitrouter && connection_ap_can_use_exit(conn, exitrouter))
         if(++num >= MIN_CIRCUITS_HANDLING_STREAM)
@@ -297,12 +295,12 @@
 
   if(time_to_new_circuit < now) {
     circuit_reset_failure_count(1);
-    time_to_new_circuit = now + options.NewCircuitPeriod;
-    if(proxy_mode())
+    time_to_new_circuit = now + get_options()->NewCircuitPeriod;
+    if(proxy_mode(get_options()))
       client_dns_clean();
     circuit_expire_old_circuits();
 
-    if(options.RunTesting && circ &&
+    if(get_options()->RunTesting && circ &&
                circ->timestamp_created + TESTING_CIRCUIT_INTERVAL < now) {
       log_fn(LOG_INFO,"Creating a new testing circuit.");
       circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL);
@@ -452,7 +450,7 @@
      * on it, mark it for close.
      */
     if (circ->timestamp_dirty &&
-        circ->timestamp_dirty + options.NewCircuitPeriod < now &&
+        circ->timestamp_dirty + get_options()->NewCircuitPeriod < now &&
         !circ->p_conn && /* we're the origin */
         !circ->p_streams /* nothing attached */ ) {
       log_fn(LOG_DEBUG,"Closing n_circ_id %d (dirty %d secs ago, purp %d)",circ->n_circ_id,

Index: command.c
===================================================================
RCS file: /home/or/cvsroot/src/or/command.c,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -d -r1.69 -r1.70
--- command.c	31 Oct 2004 20:28:41 -0000	1.69
+++ command.c	6 Nov 2004 05:18:10 -0000	1.70
@@ -15,8 +15,6 @@
 
 #include "or.h"
 
-extern or_options_t options; /* command-line and config-file options */
-
 /** Keep statistics about how many of each type of cell we've received. */
 unsigned long stats_n_padding_cells_processed = 0;
 unsigned long stats_n_create_cells_processed = 0;

Index: config.c
===================================================================
RCS file: /home/or/cvsroot/src/or/config.c,v
retrieving revision 1.208
retrieving revision 1.209
diff -u -d -r1.208 -r1.209
--- config.c	5 Nov 2004 21:22:38 -0000	1.208
+++ config.c	6 Nov 2004 05:18:10 -0000	1.209
@@ -155,19 +155,16 @@
 /** Largest allowed config line */
 #define CONFIG_LINE_T_MAXLEN 4096
 
-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,
-                              int reset);
-static int config_assign(or_options_t *options, struct config_line_t *list,
-                         int reset);
+static void option_reset(or_options_t *options, config_var_t *var);
+static void options_free(or_options_t *options);
+static or_options_t *options_dup(or_options_t *old);
+static int options_validate(or_options_t *options);
+static int options_transition_allowed(or_options_t *old, or_options_t *new);
+static int check_nickname_list(const char *lst, const char *name);
+
 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);
 static int parse_log_severity_range(const char *range, int *min_out,
                                     int *max_out);
 static int convert_log_option(or_options_t *options,
@@ -178,6 +175,25 @@
                                  const char *type, const char *fname);
 static int normalize_log_options(or_options_t *options);
 
+/*
+ * Functions to read and write the global options pointer.
+ */
+
+/** Command-line and config-file options. */
+static or_options_t *global_options=NULL;
+
+or_options_t *get_options(void) {
+  tor_assert(global_options);
+  return global_options;
+}
+void set_options(or_options_t *new) {
+  global_options = new;
+}
+
+/*
+ * Functions to parse config options
+ */
+
 /** If <b>option</b> is an official abbreviation for a longer option,
  * return the longer option.  Otherwise return <b>option</b>.
  * If <b>command_line</b> is set, apply all abbreviations.  Otherwise, only
@@ -249,34 +265,34 @@
   return newline;
 }
 
-/** Helper: parse the config file and strdup into key/value
- * strings. Set *result to the list, or NULL if parsing the file
+/** Helper: parse the config string and strdup into key/value
+ * strings. Set *result to the list, or NULL if parsing the string
  * failed.  Return 0 on success, -1 on failure. Warn and ignore any
  * misformatted lines. */
-static int
-config_get_lines(FILE *f, struct config_line_t **result)
+int
+config_get_lines(char *string, struct config_line_t **result)
 {
-  struct config_line_t *front = NULL;
-  char line[CONFIG_LINE_T_MAXLEN];
-  int r;
-  char *key, *value;
+  struct config_line_t *list = NULL;
+  char *k, *v;
 
-  while ((r = parse_line_from_file(line, sizeof(line), f, &key, &value)) > 0) {
-    front = config_line_prepend(front, key, value);
-  }
+  do {
+    string = parse_line_from_str(string, &k, &v);
+    if (!string) {
+      config_free_lines(list);
+      return -1;
+    }
+    if (k && v)
+      list = config_line_prepend(list, k, v);
+  } while (*string);
 
-  if (r < 0) {
-    *result = NULL;
-    return -1;
-  }
-  *result = front;
+  *result = list;
   return 0;
 }
 
 /**
  * Free all the configuration lines on the linked list <b>front</b>.
  */
-static void
+void
 config_free_lines(struct config_line_t *front)
 {
   struct config_line_t *tmp;
@@ -341,7 +357,7 @@
   }
 
   if (reset && !strlen(c->value)) {
-    reset_option(options, var);
+    option_reset(options, var);
     return 0;
   }
 
@@ -351,9 +367,9 @@
   case CONFIG_TYPE_UINT:
     i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
     if (!ok) {
-      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds. Skipping.",
+      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
           c->key,c->value);
-      return 0;
+      return -1;
     }
     *(int *)lvalue = i;
     break;
@@ -361,8 +377,8 @@
   case CONFIG_TYPE_BOOL:
     i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
     if (!ok) {
-      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1. Skipping.", c->key);
-      return 0;
+      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
+      return -1;
     }
     *(int *)lvalue = i;
     break;
@@ -384,7 +400,6 @@
                            SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
     break;
 
-
   case CONFIG_TYPE_LINELIST:
   case CONFIG_TYPE_LINELIST_S:
     /* Note: this reverses the order that the lines appear in.  That's
@@ -404,7 +419,6 @@
     tor_assert(0);
     break;
   }
-
   return 0;
 }
 
@@ -418,7 +432,7 @@
   if (!var)
     return; /* give error on next pass. */
 
-  reset_option(options, var);
+  option_reset(options, var);
 }
 
 /** Return a canonicalized list of the options assigned for key.
@@ -465,6 +479,8 @@
       result->value = tor_strdup(value ? (char*)value : "");
       break;
     case CONFIG_TYPE_UINT:
+      /* XXX This means every or_options_t uint or bool element
+       * needs to be an int. Not, say, a uint16_t or char. */
       tor_snprintf(buf, sizeof(buf), "%d", *(int*)value);
       result->value = tor_strdup(buf);
       break;
@@ -514,7 +530,7 @@
     }
   }
 
-  /* pass 2: if we're reading from a resetting souurce, clear all mentioned
+  /* pass 2: if we're reading from a resetting source, clear all mentioned
    * linelists. */
   if (reset) {
     for (p = list; p; p = p->next)
@@ -530,6 +546,89 @@
   return 0;
 }
 
+/** Try assigning <b>list</b> to <b>options</b>. You do this by duping
+ * options, assigning list to the new one, then validating it. If it's
+ * ok, then through out the old one and stick with the new one. Else,
+ * revert to old and return failure.
+ */
+int
+config_trial_assign(or_options_t **options, struct config_line_t *list, int reset)
+{
+  or_options_t *trial_options = options_dup(*options);
+
+  if (config_assign(trial_options, list, reset) < 0) {
+    options_free(trial_options);
+    return -1;
+  }
+
+  if (options_validate(trial_options) < 0) {
+    options_free(trial_options);
+    return -1;
+  }
+
+  if (options_transition_allowed(*options, trial_options) < 0) {
+    options_free(trial_options);
+    return -1;
+  }
+
+  /* XXX now act on options */
+
+  options_free(*options);
+  *options = trial_options;
+  return 0;
+}
+
+/** Replace the option indexed by <b>var</b> in <b>options</b> with its
+ * default value. */
+static void
+option_reset(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);
+  }
+}
+
+
+
+
+
 static void
 add_default_trusted_dirservers(void)
 {
@@ -657,7 +756,7 @@
 
 /** Release storage held by <b>options</b> */
 static void
-free_options(or_options_t *options)
+options_free(or_options_t *options)
 {
   int i;
   void *lvalue;
@@ -699,149 +798,47 @@
   }
 }
 
-/** 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)
+/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
+static or_options_t *
+options_dup(or_options_t *old)
 {
-  struct config_line_t *c;
-  void *lvalue;
+  or_options_t *new;
+  int i;
+  struct config_line_t *line;
 
-  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;
+  new = tor_malloc_zero(sizeof(or_options_t));
+  for (i=0; config_vars[i].name; ++i) {
+    line = config_get_assigned_option(old, config_vars[i].name);
+    if (line) {
+      if (config_assign(new, line, 0) < 0) {
+        log_fn(LOG_WARN,"Bug: config_get_assigned_option() generated "
+               "something we couldn't config_assign().");
+        tor_assert(0);
       }
-      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);
+    }
+    config_free_lines(line);
   }
+  return new;
 }
 
 /** Set <b>options</b> to hold reasonable defaults for most options.
  * Each option defaults to zero. */
-static void
-init_options(or_options_t *options)
+void
+options_init(or_options_t *options)
 {
   int i;
   config_var_t *var;
 
-  memset(options,0,sizeof(or_options_t));
   for (i=0; config_vars[i].name; ++i) {
     var = &config_vars[i];
     if(!var->initvalue)
       continue; /* defaults to NULL or 0 */
-    reset_option(options, var);
-  }
-}
-
-#ifdef MS_WINDOWS
-static char *get_windows_conf_root(void)
-{
-  static int is_set = 0;
-  static char path[MAX_PATH+1];
-
-  LPITEMIDLIST idl;
-  IMalloc *m;
-  HRESULT result;
-
-  if (is_set)
-    return path;
-
-  /* Find X:\documents and settings\username\applicatation data\ .
-   * We would use SHGetSpecialFolder path, but that wasn't added until IE4.
-   */
-  if (!SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA,
-                                            &idl))) {
-    GetCurrentDirectory(MAX_PATH, path);
-    is_set = 1;
-    log_fn(LOG_WARN, "I couldn't find your application data folder: are you running an ancient version of Windows 95? Defaulting to '%s'", path);
-    return path;
-  }
-  /* Convert the path from an "ID List" (whatever that is!) to a path. */
-  result = SHGetPathFromIDList(idl, path);
-  /* Now we need to free the */
-  SHGetMalloc(&m);
-  if (m) {
-    m->lpVtbl->Free(m, idl);
-    m->lpVtbl->Release(m);
-  }
-  if (!SUCCEEDED(result)) {
-    return NULL;
+    option_reset(options, var);
   }
-  strlcat(path,"\\tor",MAX_PATH);
-  is_set = 1;
-  return path;
-}
-#endif
-
-static char *
-get_default_conf_file(void)
-{
-#ifdef MS_WINDOWS
-  char *path = tor_malloc(MAX_PATH);
-  strlcpy(path, get_windows_conf_root(), MAX_PATH);
-  strlcat(path,"\\torrc",MAX_PATH);
-  return path;
-#else
-  return tor_strdup(CONFDIR "/torrc");
-#endif
-}
-
-/** Verify whether lst is a string containing valid-looking space-separated
- * nicknames, or NULL. Return 0 on success. Warn and return -1 on failure.
- */
-static int check_nickname_list(const char *lst, const char *name)
-{
-  int r = 0;
-  smartlist_t *sl;
-
-  if (!lst)
-    return 0;
-  sl = smartlist_create();
-  smartlist_split_string(sl, lst, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
-  SMARTLIST_FOREACH(sl, const char *, s,
-    {
-      if (!is_legal_nickname_or_hexdigest(s)) {
-        log_fn(LOG_WARN, "Invalid nickname '%s' in %s line", s, name);
-        r = -1;
-      }
-    });
-  SMARTLIST_FOREACH(sl, char *, s, tor_free(s));
-  smartlist_free(sl);
-  return r;
 }
 
 static int
-validate_options(or_options_t *options)
+options_validate(or_options_t *options)
 {
   int i;
   int result = 0;
@@ -853,7 +850,7 @@
   }
 
   if (options->Nickname == NULL) {
-    if (server_mode()) {
+    if (server_mode(options)) {
       if (!(options->Nickname = get_default_nickname()))
         return -1;
       log_fn(LOG_NOTICE, "Choosing default nickname %s", options->Nickname);
@@ -875,7 +872,7 @@
     }
   }
 
-  if (server_mode()) {
+  if (server_mode(options)) {
     /* confirm that our address isn't broken, so we can complain now */
     uint32_t tmp;
     if (resolve_my_address(options->Address, &tmp) < 0)
@@ -1031,14 +1028,20 @@
       result = -1;
   }
 
-  if (!options->RedirectExitList)
-    options->RedirectExitList = smartlist_create();
-/* XXX need to free the old one if it's there, else they just keep piling up */
+  /* free options->RedirectExitList */
+  if (options->RedirectExitList) {
+    SMARTLIST_FOREACH(options->RedirectExitList,
+                      exit_redirect_t *, p, tor_free(p));
+    smartlist_free(options->RedirectExitList);
+  }
+
+  options->RedirectExitList = smartlist_create();
   for (cl = options->RedirectExit; cl; cl = cl->next) {
     if (parse_redirect_line(options, cl)<0)
       result = -1;
   }
 
+/* XXX bug: this parsing shouldn't have side effects */
   clear_trusted_dir_servers();
   if (!options->DirServers) {
     add_default_trusted_dirservers();
@@ -1052,23 +1055,125 @@
   return result;
 }
 
+/** Check if any of the previous options have changed but aren't allowed to. */
+static int
+options_transition_allowed(or_options_t *old, or_options_t *new) {
+
+  if(!old)
+    return 0;
+
+  if (old->PidFile &&
+      (!new->PidFile || strcmp(old->PidFile,new->PidFile))) {
+    log_fn(LOG_WARN,"PidFile is not allowed to change. Failing.");
+    return -1;
+  }
+
+  if (old->RunAsDaemon && !new->RunAsDaemon) {
+    log_fn(LOG_WARN,"During reload, change from RunAsDaemon=1 to =0 not allowed. Failing.");
+    return -1;
+  }
+
+  if (old->ORPort != new->ORPort) {
+    log_fn(LOG_WARN,"During reload, changing ORPort is not allowed. Failing.");
+    return -1;
+  }
+
+  return 0;
+}
+
+#ifdef MS_WINDOWS
+static char *get_windows_conf_root(void)
+{
+  static int is_set = 0;
+  static char path[MAX_PATH+1];
+
+  LPITEMIDLIST idl;
+  IMalloc *m;
+  HRESULT result;
+
+  if (is_set)
+    return path;
+
+  /* Find X:\documents and settings\username\applicatation data\ .
+   * We would use SHGetSpecialFolder path, but that wasn't added until IE4.
+   */
+  if (!SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA,
+                                            &idl))) {
+    GetCurrentDirectory(MAX_PATH, path);
+    is_set = 1;
+    log_fn(LOG_WARN, "I couldn't find your application data folder: are you running an ancient version of Windows 95? Defaulting to '%s'", path);
+    return path;
+  }
+  /* Convert the path from an "ID List" (whatever that is!) to a path. */
+  result = SHGetPathFromIDList(idl, path);
+  /* Now we need to free the */
+  SHGetMalloc(&m);
+  if (m) {
+    m->lpVtbl->Free(m, idl);
+    m->lpVtbl->Release(m);
+  }
+  if (!SUCCEEDED(result)) {
+    return NULL;
+  }
+  strlcat(path,"\\tor",MAX_PATH);
+  is_set = 1;
+  return path;
+}
+#endif
+
+static char *
+get_default_conf_file(void)
+{
+#ifdef MS_WINDOWS
+  char *path = tor_malloc(MAX_PATH);
+  strlcpy(path, get_windows_conf_root(), MAX_PATH);
+  strlcat(path,"\\torrc",MAX_PATH);
+  return path;
+#else
+  return tor_strdup(CONFDIR "/torrc");
+#endif
+}
+
+/** Verify whether lst is a string containing valid-looking space-separated
+ * nicknames, or NULL. Return 0 on success. Warn and return -1 on failure.
+ */
+static int check_nickname_list(const char *lst, const char *name)
+{
+  int r = 0;
+  smartlist_t *sl;
+
+  if (!lst)
+    return 0;
+  sl = smartlist_create();
+  smartlist_split_string(sl, lst, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+  SMARTLIST_FOREACH(sl, const char *, s,
+    {
+      if (!is_legal_nickname_or_hexdigest(s)) {
+        log_fn(LOG_WARN, "Invalid nickname '%s' in %s line", s, name);
+        r = -1;
+      }
+    });
+  SMARTLIST_FOREACH(sl, char *, s, tor_free(s));
+  smartlist_free(sl);
+  return r;
+}
+
+
 /** Read a configuration file into <b>options</b>, finding the configuration
  * file location based on the command line.  After loading the options,
  * validate them for consistency. Return 0 if success, <0 if failure. */
 int
-getconfig(int argc, char **argv, or_options_t *options)
+getconfig(int argc, char **argv)
 {
+  or_options_t *oldoptions, *newoptions;
   struct config_line_t *cl;
-  FILE *cf;
-  char *fname;
-  int i;
-  int result = 0;
+  char *cf=NULL, *fname=NULL;
+  int i, retval;
   int using_default_torrc;
   static char **backup_argv;
   static int backup_argc;
-  char *previous_pidfile = NULL;
-  int previous_runasdaemon = 0;
-  int previous_orport = -1;
+
+  oldoptions = global_options;
 
   if (argv) { /* first time we're called. save commandline args */
     backup_argv = argv;
@@ -1076,16 +1181,7 @@
   } else { /* we're reloading. need to clean up old options first. */
     argv = backup_argv;
     argc = backup_argc;
-
-    /* record some previous values, so we can fail if they change */
-    if (options->PidFile)
-      previous_pidfile = tor_strdup(options->PidFile);
-    previous_runasdaemon = options->RunAsDaemon;
-    previous_orport = options->ORPort;
-    free_options(options);
   }
-  init_options(options);
-
   if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1],"--help"))) {
     print_usage();
     exit(0);
@@ -1096,10 +1192,13 @@
     exit(0);
   }
 
+  newoptions = tor_malloc_zero(sizeof(or_options_t));
+  options_init(newoptions);
+
   /* learn config file name, get config lines, assign them */
   fname = NULL;
   using_default_torrc = 1;
-  options->command = CMD_RUN_TOR;
+  newoptions->command = CMD_RUN_TOR;
   for (i = 1; i < argc; ++i) {
     if (i < argc-1 && !strcmp(argv[i],"-f")) {
       if (fname) {
@@ -1110,10 +1209,10 @@
       using_default_torrc = 0;
       ++i;
     } else if (!strcmp(argv[i],"--list-fingerprint")) {
-      options->command = CMD_LIST_FINGERPRINT;
+      newoptions->command = CMD_LIST_FINGERPRINT;
     } else if (!strcmp(argv[i],"--hash-password")) {
-      options->command = CMD_HASH_PASSWORD;
-      options->command_arg = tor_strdup( (i < argc-1) ? argv[i+1] : "");
+      newoptions->command = CMD_HASH_PASSWORD;
+      newoptions->command_arg = tor_strdup( (i < argc-1) ? argv[i+1] : "");
       ++i;
     }
   }
@@ -1138,7 +1237,7 @@
   tor_assert(fname);
   log(LOG_DEBUG, "Opening config file '%s'", fname);
 
-  cf = fopen(fname, "r");
+  cf = read_file_to_str(fname, 0);
   if (!cf) {
     if (using_default_torrc == 1) {
       log(LOG_NOTICE, "Configuration file '%s' not present, "
@@ -1147,51 +1246,45 @@
     } else {
       log(LOG_WARN, "Unable to open configuration file '%s'.", fname);
       tor_free(fname);
-      return -1;
+      goto err;
     }
   } else { /* it opened successfully. use it. */
     tor_free(fname);
-    if (config_get_lines(cf, &cl)<0)
-      return -1;
-    if (config_assign(options,cl, 0) < 0)
-      return -1;
+    retval = config_get_lines(cf, &cl);
+    tor_free(cf);
+    if (retval < 0)
+      goto err;
+    retval = config_assign(newoptions, cl, 0);
     config_free_lines(cl);
-    fclose(cf);
+    if (retval < 0)
+      goto err;
   }
 
 /* go through command-line variables too */
   cl = config_get_commandlines(argc,argv);
-  if (config_assign(options,cl,0) < 0)
-    return -1;
+  retval = config_assign(newoptions,cl,0);
   config_free_lines(cl);
+  if (retval < 0)
+    goto err;
 
-/* Validate options */
-
-  /* first check if any of the previous options have changed but aren't allowed to */
-  if (previous_pidfile && strcmp(previous_pidfile,options->PidFile)) {
-    log_fn(LOG_WARN,"During reload, PidFile changed from %s to %s. Failing.",
-           previous_pidfile, options->PidFile);
-    return -1;
-  }
-  tor_free(previous_pidfile);
-
-  if (previous_runasdaemon && !options->RunAsDaemon) {
-    log_fn(LOG_WARN,"During reload, change from RunAsDaemon=1 to =0 not allowed. Failing.");
-    return -1;
-  }
+/* Validate newoptions */
+  if (options_validate(newoptions) < 0)
+    goto err;
 
-  if (previous_orport == 0 && options->ORPort > 0) {
-    log_fn(LOG_WARN,"During reload, change from ORPort=0 to >0 not allowed. Failing.");
-    return -1;
-  }
+  if (options_transition_allowed(oldoptions, newoptions) < 0)
+    goto err;
 
-  if (validate_options(options) < 0)
-    result = -1;
+  /* XXX now act on options */
+  if (rend_config_services(newoptions) < 0)
+    goto err;
 
-  if (rend_config_services(options) < 0) {
-    result = -1;
-  }
-  return result;
+  if(oldoptions)
+    options_free(oldoptions);
+  set_options(newoptions);
+  return 0;
+ err:
+  options_free(newoptions);
+  return -1;
 }
 
 static int
@@ -1282,6 +1375,7 @@
 {
   struct config_line_t *opt;
   int ok;
+  smartlist_t *elts;
   if (normalize_log_options(options))
     return -1;
 
@@ -1291,7 +1385,7 @@
   }
 
   ok = 1;
-  smartlist_t *elts = smartlist_create();
+  elts = smartlist_create();
   for (opt = options->Logs; opt; opt = opt->next) {
     int levelMin=LOG_DEBUG, levelMax=LOG_ERR;
     smartlist_split_string(elts, opt->value, " ",
@@ -1496,7 +1590,7 @@
   } else {
     if (parse_addr_port(smartlist_get(elements,1),NULL,&r->addr_dest,
                              &r->port_dest)) {
-      log_fn(LOG_WARN, "Error parseing dest address in RedirectExit line");
+      log_fn(LOG_WARN, "Error parsing dest address in RedirectExit line");
       goto err;
     }
     r->is_redirect = 1;
@@ -1565,17 +1659,15 @@
   done:
   SMARTLIST_FOREACH(items, char*, s, tor_free(s));
   smartlist_free(items);
-
-  if (address)
-    tor_free(address);
-
+  tor_free(address);
   return r;
 }
 
 const char *
-get_data_directory(or_options_t *options)
+get_data_directory(void)
 {
   const char *d;
+  or_options_t *options = get_options();
 
   if (options->DataDirectory) {
     d = options->DataDirectory;

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.282
retrieving revision 1.283
diff -u -d -r1.282 -r1.283
--- connection.c	4 Nov 2004 06:41:49 -0000	1.282
+++ connection.c	6 Nov 2004 05:18:11 -0000	1.283
@@ -12,8 +12,6 @@
 
 /********* START VARIABLES **********/
 
-extern or_options_t options; /* command-line and config-file options */
-
 /** Array of strings to make conn-\>type human-readable. */
 const char *conn_type_to_string[] = {
   "",            /* 0 */
@@ -488,6 +486,7 @@
 int connection_connect(connection_t *conn, char *address, uint32_t addr, uint16_t port) {
   int s;
   struct sockaddr_in dest_addr;
+  or_options_t *options = get_options();
 
   s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
   if (s < 0) {
@@ -496,15 +495,15 @@
     return -1;
   }
 
-  if (options.OutboundBindAddress) {
+  if (options->OutboundBindAddress) {
     struct sockaddr_in ext_addr;
 
     memset(&ext_addr, 0, sizeof(ext_addr));
     ext_addr.sin_family = AF_INET;
     ext_addr.sin_port = 0;
-    if (!tor_inet_aton(options.OutboundBindAddress, &ext_addr.sin_addr)) {
+    if (!tor_inet_aton(options->OutboundBindAddress, &ext_addr.sin_addr)) {
       log_fn(LOG_WARN,"Outbound bind address '%s' didn't parse. Ignoring.",
-             options.OutboundBindAddress);
+             options->OutboundBindAddress);
     } else {
       if(bind(s, (struct sockaddr*)&ext_addr, sizeof(ext_addr)) < 0) {
         log_fn(LOG_WARN,"Error binding network socket: %s",
@@ -641,18 +640,19 @@
  * connections for a given type.
  */
 int retry_all_listeners(int force) {
+  or_options_t *options = get_options();
 
-  if (retry_listeners(CONN_TYPE_OR_LISTENER, options.ORBindAddress,
-                      options.ORPort, "0.0.0.0", force)<0)
+  if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORBindAddress,
+                      options->ORPort, "0.0.0.0", force)<0)
     return -1;
-  if (retry_listeners(CONN_TYPE_DIR_LISTENER, options.DirBindAddress,
-                      options.DirPort, "0.0.0.0", force)<0)
+  if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirBindAddress,
+                      options->DirPort, "0.0.0.0", force)<0)
     return -1;
-  if (retry_listeners(CONN_TYPE_AP_LISTENER, options.SocksBindAddress,
-                      options.SocksPort, "127.0.0.1", force)<0)
+  if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksBindAddress,
+                      options->SocksPort, "127.0.0.1", force)<0)
     return -1;
   if (retry_listeners(CONN_TYPE_CONTROL_LISTENER, NULL,
-                      options.ControlPort, "127.0.0.1", force)<0)
+                      options->ControlPort, "127.0.0.1", force)<0)
     return -1;
 
   return 0;
@@ -702,11 +702,12 @@
   }
 }
 
-/** Initiatialize the global read bucket to options.BandwidthBurstBytes,
+/** Initiatialize the global read bucket to options->BandwidthBurstBytes,
  * and current_time to the current time. */
 void connection_bucket_init(void) {
-  global_read_bucket = options.BandwidthBurstBytes; /* start it at max traffic */
-  global_write_bucket = options.BandwidthBurstBytes; /* start it at max traffic */
+  or_options_t *options = get_options();
+  global_read_bucket = options->BandwidthBurstBytes; /* start it at max traffic */
+  global_write_bucket = options->BandwidthBurstBytes; /* start it at max traffic */
 }
 
 /** A second has rolled over; increment buckets appropriately. */
@@ -714,14 +715,15 @@
   int i, n;
   connection_t *conn;
   connection_t **carray;
+  or_options_t *options = get_options();
 
   /* refill the global buckets */
-  if(global_read_bucket < options.BandwidthBurstBytes) {
-    global_read_bucket += options.BandwidthRateBytes;
+  if(global_read_bucket < options->BandwidthBurstBytes) {
+    global_read_bucket += options->BandwidthRateBytes;
     log_fn(LOG_DEBUG,"global_read_bucket now %d.", global_read_bucket);
   }
-  if(global_write_bucket < options.BandwidthBurstBytes) {
-    global_write_bucket += options.BandwidthRateBytes;
+  if(global_write_bucket < options->BandwidthBurstBytes) {
+    global_write_bucket += options->BandwidthRateBytes;
     log_fn(LOG_DEBUG,"global_write_bucket now %d.", global_write_bucket);
   }
 

Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_edge.c,v
retrieving revision 1.224
retrieving revision 1.225
diff -u -d -r1.224 -r1.225
--- connection_edge.c	3 Nov 2004 23:13:28 -0000	1.224
+++ connection_edge.c	6 Nov 2004 05:18:11 -0000	1.225
@@ -10,8 +10,6 @@
 #include "or.h"
 #include "tree.h"
 
-extern or_options_t options; /* command-line and config-file options */
-
 static struct exit_policy_t *socks_policy = NULL;
 
 static int connection_ap_handshake_process_socks(connection_t *conn);
@@ -245,6 +243,7 @@
   circuit_t *circ;
   int n, i;
   time_t now = time(NULL);
+  or_options_t *options = get_options();
 
   get_connection_array(&carray, &n);
 
@@ -293,7 +292,7 @@
        * current streams on it to survive if they can: make it
        * unattractive to use for new streams */
       tor_assert(circ->timestamp_dirty);
-      circ->timestamp_dirty -= options.NewCircuitPeriod;
+      circ->timestamp_dirty -= options->NewCircuitPeriod;
       /* give our stream another 15 seconds to try */
       conn->timestamp_lastread += 15;
       /* attaching to a dirty circuit is fine */
@@ -899,6 +898,7 @@
   unsigned char connected_payload[4];
   uint32_t addr;
   uint16_t port;
+  or_options_t *options = get_options();
 
   if (!connection_edge_is_rendezvous_stream(conn) &&
       router_compare_to_my_exit_policy(conn) == ADDR_POLICY_REJECTED) {
@@ -911,7 +911,7 @@
 
   addr = conn->addr;
   port = conn->port;
-  SMARTLIST_FOREACH(options.RedirectExitList, exit_redirect_t *, r,
+  SMARTLIST_FOREACH(options->RedirectExitList, exit_redirect_t *, r,
     {
       if ((addr&r->mask)==(r->addr&r->mask) &&
           (r->port_min <= port) && (port <= r->port_max)) {
@@ -1003,7 +1003,7 @@
 
 /** A helper function for socks_policy_permits_address() below.
  *
- * Parse options.SocksPolicy in the same way that the exit policy
+ * Parse options->SocksPolicy in the same way that the exit policy
  * is parsed, and put the processed version in &socks_policy.
  * Ignore port specifiers.
  */
@@ -1014,7 +1014,7 @@
     exit_policy_free(socks_policy);
     socks_policy = NULL;
   }
-  config_parse_exit_policy(options.SocksPolicy, &socks_policy);
+  config_parse_exit_policy(get_options()->SocksPolicy, &socks_policy);
   /* ports aren't used. */
   for (n=socks_policy; n; n = n->next) {
     n->prt_min = 1;
@@ -1028,7 +1028,8 @@
 int socks_policy_permits_address(uint32_t addr)
 {
   int a;
-  if (options.SocksPolicy && !socks_policy)
+  or_options_t *options = get_options();
+  if (options->SocksPolicy && !socks_policy)
     parse_socks_policy();
 
   if(!socks_policy) /* 'no socks policy' means 'accept' */

Index: connection_or.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_or.c,v
retrieving revision 1.133
retrieving revision 1.134
diff -u -d -r1.133 -r1.134
--- connection_or.c	4 Nov 2004 03:25:43 -0000	1.133
+++ connection_or.c	6 Nov 2004 05:18:11 -0000	1.134
@@ -10,8 +10,6 @@
 
 #include "or.h"
 
-extern or_options_t options; /**< command-line and config-file options */
-
 static int connection_tls_finish_handshake(connection_t *conn);
 static int connection_or_process_cells_from_inbuf(connection_t *conn);
 
@@ -121,10 +119,10 @@
                                      uint32_t addr, uint16_t port,
                                      const char *id_digest)
 {
-  routerinfo_t *r;
   struct in_addr in;
   const char *n;
-  r = router_get_by_digest(id_digest);
+  or_options_t *options = get_options();
+  routerinfo_t *r = router_get_by_digest(id_digest);
   if (r) {
     connection_or_init_conn_from_router(conn,r);
     return;
@@ -132,7 +130,7 @@
   conn->addr = addr;
   conn->port = port;
   /* This next part isn't really right, but it's good enough for now. */
-  conn->receiver_bucket = conn->bandwidth = options.BandwidthBurstBytes;
+  conn->receiver_bucket = conn->bandwidth = options->BandwidthBurstBytes;
   memcpy(conn->identity_digest, id_digest, DIGEST_LEN);
   /* If we're an authoritative directory server, we may know a
    * nickname for this router. */
@@ -203,7 +201,7 @@
 
   tor_assert(id_digest);
 
-  if(server_mode() && (me=router_get_my_routerinfo()) &&
+  if(server_mode(get_options()) && (me=router_get_my_routerinfo()) &&
      !memcmp(me->identity_digest, id_digest,DIGEST_LEN)) {
     log_fn(LOG_WARN,"Request to connect to myself! Failing.");
     return NULL;
@@ -334,12 +332,13 @@
   connection_t *c;
   crypto_pk_env_t *identity_rcvd=NULL;
   char digest_rcvd[DIGEST_LEN];
+  or_options_t *options = get_options();
 
   conn->state = OR_CONN_STATE_OPEN;
   connection_watch_events(conn, POLLIN);
   log_fn(LOG_DEBUG,"tls handshake done. verifying.");
   if (! tor_tls_peer_has_cert(conn->tls)) { /* It's an OP. */
-    if (server_mode()) { /* I'm an OR; good. */
+    if (server_mode(options)) { /* I'm an OR; good. */
       conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP;
       return 0;
     } else { /* Neither side sent a certificate: ouch. */
@@ -376,7 +375,7 @@
   if (connection_or_nonopen_was_started_here(conn)) {
     /* I initiated this connection. */
     if (strcasecmp(conn->nickname, nickname)) {
-      log_fn(options.DirPort ? LOG_WARN : LOG_INFO,
+      log_fn(options->DirPort ? LOG_WARN : LOG_INFO,
              "Other side (%s:%d) is '%s', but we tried to connect to '%s'",
              conn->address, conn->port, nickname, conn->nickname);
       control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
@@ -390,7 +389,7 @@
     connection_or_init_conn_from_address(conn,conn->addr,conn->port,digest_rcvd);
   }
 
-  if (!server_mode()) { /* If I'm an OP... */
+  if (!server_mode(options)) { /* If I'm an OP... */
     conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP;
   }
   directory_set_dirty();

Index: control.c
===================================================================
RCS file: /home/or/cvsroot/src/or/control.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- control.c	4 Nov 2004 22:31:50 -0000	1.6
+++ control.c	6 Nov 2004 05:18:11 -0000	1.7
@@ -43,8 +43,6 @@
   "authenticate",
 };
 
-extern or_options_t options;
-
 static uint32_t global_event_mask = 0;
 
 #define AUTHENTICATION_COOKIE_LEN 32
@@ -141,26 +139,25 @@
 handle_control_setconf(connection_t *conn, uint16_t len,
                        char *body)
 {
-  char *k, *v;
-  struct config_line_t *lines = NULL;
-
-  /* XXXX009 move this logic into config.c someplace. */
+  struct config_line_t *lines=NULL;
+  or_options_t *options = get_options();
 
-  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);
+  if (config_get_lines(body, &lines) < 0) {
+    log_fn(LOG_WARN,"Controller gave us config lines we can't parse.");
+    send_control_error(conn, ERR_UNSPECIFIED, "Couldn't parse configuration");
+    return 0;
+  }
 
-  /* XXXX009 NM */
+  if (config_trial_assign(&options, lines, 1) < 0) {
+    log_fn(LOG_WARN,"Controller gave us config lines that didn't validate.");
+    send_control_error(conn, ERR_UNSPECIFIED, "Configuration was invalid");
+    config_free_lines(lines);
+    return 0;
+  }
 
-  return 0;
- err:
-  send_control_error(conn, ERR_UNSPECIFIED, "Couldn't parse configuration");
-  /* config_free_lines(lines); */
+  set_options(options); /* put the new one into place */
+  config_free_lines(lines);
+  send_control_done(conn);
   return 0;
 }
 
@@ -172,6 +169,7 @@
   smartlist_t *answers = NULL;
   char *msg = NULL;
   size_t msg_len;
+  or_options_t *options = get_options();
 
   questions = smartlist_create();
   smartlist_split_string(questions, body, "\n",
@@ -179,7 +177,7 @@
   answers = smartlist_create();
   SMARTLIST_FOREACH(questions, const char *, q,
   {
-    struct config_line_t *answer = config_get_assigned_option(&options,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;
@@ -245,16 +243,17 @@
 static int handle_control_authenticate(connection_t *conn, uint16_t len,
                                        const char *body)
 {
+  or_options_t *options = get_options();
   if (len == AUTHENTICATION_COOKIE_LEN &&
       authentication_cookie_is_set &&
       !memcmp(authentication_cookie, body, len)) {
     goto ok;
-  } else if (options.HashedControlPassword) {
+  } else if (options->HashedControlPassword) {
     char expected[S2K_SPECIFIER_LEN+DIGEST_LEN];
     char received[DIGEST_LEN];
     if (base64_decode(expected,sizeof(expected),
-                      options.HashedControlPassword,
-                      strlen(options.HashedControlPassword))<0) {
+                      options->HashedControlPassword,
+                      strlen(options->HashedControlPassword))<0) {
       /* XXXX009 NM we should warn sooner. */
       log_fn(LOG_WARN,"Couldn't decode HashedControlPassword: invalid base64");
       goto err;
@@ -448,7 +447,7 @@
   /* XXXX009 NM add config option to disable this. */
 
   tor_snprintf(fname, sizeof(fname), "%s/control_auth_cookie",
-               get_data_directory(&options));
+               get_data_directory());
   crypto_rand(authentication_cookie, AUTHENTICATION_COOKIE_LEN);
   authentication_cookie_is_set = 1;
   if (write_bytes_to_file(fname, authentication_cookie,

Index: cpuworker.c
===================================================================
RCS file: /home/or/cvsroot/src/or/cpuworker.c,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -d -r1.51 -r1.52
--- cpuworker.c	17 Oct 2004 21:51:20 -0000	1.51
+++ cpuworker.c	6 Nov 2004 05:18:11 -0000	1.52
@@ -11,7 +11,6 @@
  **/
 
 #include "or.h"
-extern or_options_t options; /* command-line and config-file options */
 
 /** The maximum number of cpuworker processes we will keep around. */
 #define MAX_CPUWORKERS 16
@@ -302,7 +301,7 @@
  * or kill idle ones.
  */
 static void spawn_enough_cpuworkers(void) {
-  int num_cpuworkers_needed = options.NumCpus;
+  int num_cpuworkers_needed = get_options()->NumCpus;
 
   if(num_cpuworkers_needed < MIN_CPUWORKERS)
     num_cpuworkers_needed = MIN_CPUWORKERS;

Index: directory.c
===================================================================
RCS file: /home/or/cvsroot/src/or/directory.c,v
retrieving revision 1.159
retrieving revision 1.160
diff -u -d -r1.159 -r1.160
--- directory.c	4 Nov 2004 23:39:57 -0000	1.159
+++ directory.c	6 Nov 2004 05:18:11 -0000	1.160
@@ -46,8 +46,6 @@
 
 /********* START VARIABLES **********/
 
-extern or_options_t options; /* command-line and config-file options */
-
 static struct exit_policy_t *dir_policy = NULL;
 
 #if 0 /* commented out for now, since for now what clients send is
@@ -67,7 +65,7 @@
 
 /** A helper function for dir_policy_permits_address() below.
  *
- * Parse options.DirPolicy in the same way that the exit policy
+ * Parse options->DirPolicy in the same way that the exit policy
  * is parsed, and put the processed version in &dir_policy.
  * Ignore port specifiers.
  */
@@ -78,7 +76,7 @@
     exit_policy_free(dir_policy);
     dir_policy = NULL;
   }
-  config_parse_exit_policy(options.DirPolicy, &dir_policy);
+  config_parse_exit_policy(get_options()->DirPolicy, &dir_policy);
   /* ports aren't used. */
   for (n=dir_policy; n; n = n->next) {
     n->prt_min = 1;
@@ -92,7 +90,7 @@
 int dir_policy_permits_address(uint32_t addr)
 {
   int a;
-  if (options.DirPolicy && !dir_policy)
+  if (get_options()->DirPolicy && !dir_policy)
     parse_dir_policy();
 
   if(!dir_policy) /* 'no dir policy' means 'accept' */
@@ -129,10 +127,10 @@
       /* Pay attention to fascistfirewall when we're uploading a
        * router descriptor, but not when uploading a service
        * descriptor -- those use Tor. */
-      if (options.FascistFirewall && purpose == DIR_PURPOSE_UPLOAD_DIR &&
-          !options.HttpProxy) {
+      if (get_options()->FascistFirewall && purpose == DIR_PURPOSE_UPLOAD_DIR &&
+          !get_options()->HttpProxy) {
         tor_snprintf(buf,sizeof(buf),"%d",ds->dir_port);
-        if (!smartlist_string_isin(options.FirewallPorts, buf))
+        if (!smartlist_string_isin(get_options()->FirewallPorts, buf))
           continue;
       }
       directory_initiate_command_trusted_dir(ds, purpose, payload, payload_len);
@@ -154,13 +152,13 @@
   if (purpose == DIR_PURPOSE_FETCH_DIR) {
     if (advertised_server_mode()) {
       /* only ask authdirservers, and don't ask myself */
-      ds = router_pick_trusteddirserver(1, options.FascistFirewall);
+      ds = router_pick_trusteddirserver(1, get_options()->FascistFirewall);
     } else {
       /* anybody with a non-zero dirport will do */
-      r = router_pick_directory_server(1, options.FascistFirewall);
+      r = router_pick_directory_server(1, get_options()->FascistFirewall);
       if (!r) {
         log_fn(LOG_INFO, "No router found for directory; falling back to dirserver list");
-        ds = router_pick_trusteddirserver(1, options.FascistFirewall);
+        ds = router_pick_trusteddirserver(1, get_options()->FascistFirewall);
       }
     }
   } else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC)
@@ -241,9 +239,9 @@
   conn->addr = addr;
   conn->port = dir_port;
 
-  if(options.HttpProxy) {
-    addr = options.HttpProxyAddr;
-    dir_port = options.HttpProxyPort;
+  if(get_options()->HttpProxy) {
+    addr = get_options()->HttpProxyAddr;
+    dir_port = get_options()->HttpProxyPort;
   }
 
   conn->address = tor_strdup(address);
@@ -327,7 +325,7 @@
   } else {
     tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",conn->address, conn->port);
   }
-  if(options.HttpProxy) {
+  if(get_options()->HttpProxy) {
     tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring);
   } else {
     proxystring[0] = 0;
@@ -768,7 +766,7 @@
 
   if(!strcmp(url,"/tor/running-routers")) { /* running-routers fetch */
     tor_free(url);
-    if(!authdir_mode()) {
+    if(!authdir_mode(get_options())) {
       /* XXX008 for now, we don't cache running-routers. Reject. */
       connection_write_to_buf(answer400, strlen(answer400), conn);
       return 0;
@@ -793,7 +791,7 @@
     const char *descp;
     size_t desc_len;
 
-    if(!authdir_mode()) {
+    if(!authdir_mode(get_options())) {
       /* We don't hand out rend descs. In fact, it could be a security
        * risk, since rend_cache_lookup_desc() below would provide it
        * if we're gone to the site recently, and 404 if we haven't.
@@ -845,7 +843,7 @@
 
   conn->state = DIR_CONN_STATE_SERVER_WRITING;
 
-  if(!authdir_mode()) {
+  if(!authdir_mode(get_options())) {
     /* we just provide cached directories; we don't want to
      * receive anything. */
     connection_write_to_buf(answer400, strlen(answer400), conn);

Index: dirserv.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dirserv.c,v
retrieving revision 1.110
retrieving revision 1.111
diff -u -d -r1.110 -r1.111
--- dirserv.c	3 Nov 2004 18:33:07 -0000	1.110
+++ dirserv.c	6 Nov 2004 05:18:11 -0000	1.111
@@ -14,8 +14,6 @@
 /** How many seconds do we wait before regenerating the directory? */
 #define DIR_REGEN_SLACK_TIME 10
 
-extern or_options_t options; /**< command-line and config-file options */
-
 /** Do we need to regenerate the directory when someone asks for it? */
 static int the_directory_is_dirty = 1;
 static int runningrouters_is_dirty = 1;
@@ -87,19 +85,29 @@
 int
 dirserv_parse_fingerprint_file(const char *fname)
 {
-  FILE *file;
-  char line[FINGERPRINT_LEN+MAX_NICKNAME_LEN+20+1];
+  char *cf;
   char *nickname, *fingerprint;
   smartlist_t *fingerprint_list_new;
   int i, result;
   fingerprint_entry_t *ent;
+  struct config_line_t *front=NULL, *list;
 
-  if(!(file = fopen(fname, "r"))) {
+  cf = read_file_to_str(fname, 0);
+  if (!cf) {
     log_fn(LOG_WARN, "Cannot open fingerprint file %s", fname);
     return -1;
   }
+  result = config_get_lines(cf, &front);
+  tor_free(cf);
+  if (result < 0) {
+    log_fn(LOG_WARN, "Error reading from fingerprint file");
+    return -1;
+  }
+
   fingerprint_list_new = smartlist_create();
-  while( (result=parse_line_from_file(line, sizeof(line),file,&nickname,&fingerprint)) > 0) {
+
+  for(list=front; list; list=list->next) {
+    nickname = list->key; fingerprint = list->value;
     if (strlen(nickname) > MAX_NICKNAME_LEN) {
       log(LOG_WARN, "Nickname %s too long in fingerprint file. Skipping.", nickname);
       continue;
@@ -125,24 +133,13 @@
       smartlist_add(fingerprint_list_new, ent);
     }
   }
-  fclose(file);
-  if(result == 0) { /* eof; replace the global fingerprints list. */
-    dirserv_free_fingerprint_list();
-    fingerprint_list = fingerprint_list_new;
-    /* Delete any routers whose fingerprints we no longer recognize */
-    directory_remove_unrecognized();
-    return 0;
-  }
-  /* error */
-  log_fn(LOG_WARN, "Error reading from fingerprint file");
-  for (i = 0; i < smartlist_len(fingerprint_list_new); ++i) {
-    ent = smartlist_get(fingerprint_list_new, i);
-    tor_free(ent->nickname);
-    tor_free(ent->fingerprint);
-    tor_free(ent);
-  }
-  smartlist_free(fingerprint_list_new);
-  return -1;
+
+  config_free_lines(front);
+  dirserv_free_fingerprint_list();
+  fingerprint_list = fingerprint_list_new;
+  /* Delete any routers whose fingerprints we no longer recognize */
+  directory_remove_unrecognized();
+  return 0;
 }
 
 /** Check whether <b>router</b> has a nickname/identity key combination that
@@ -607,7 +604,7 @@
     smartlist_t *versions;
     struct config_line_t *ln;
     versions = smartlist_create();
-    for (ln = options.RecommendedVersions; ln; ln = ln->next) {
+    for (ln = get_options()->RecommendedVersions; ln; ln = ln->next) {
       smartlist_split_string(versions, ln->value, ",", 
                              SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
     }
@@ -644,7 +641,7 @@
   */
   if (strlcat(s, "directory-signature ", maxlen) >= maxlen)
     goto truncated;
-  if (strlcat(s, options.Nickname, maxlen) >= maxlen)
+  if (strlcat(s, get_options()->Nickname, maxlen) >= maxlen)
     goto truncated;
   if (strlcat(s, "\n", maxlen) >= maxlen)
     goto truncated;
@@ -694,7 +691,7 @@
 {
   time_t now;
   char filename[512];
-  tor_assert(!options.AuthoritativeDir);
+  tor_assert(!get_options()->AuthoritativeDir);
   now = time(NULL);
   if (when<=cached_directory_published) {
     log_fn(LOG_INFO, "Ignoring old directory; not caching.");
@@ -713,8 +710,8 @@
       log_fn(LOG_WARN,"Error compressing cached directory");
     }
     cached_directory_published = when;
-    if(get_data_directory(&options)) {
-      tor_snprintf(filename,sizeof(filename),"%s/cached-directory", get_data_directory(&options));
+    if(get_data_directory()) {
+      tor_snprintf(filename,sizeof(filename),"%s/cached-directory", get_data_directory());
       if(write_str_to_file(filename,cached_directory,0) < 0) {
         log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring.");
       }
@@ -726,7 +723,7 @@
  * directory, generating a new one as necessary. */
 size_t dirserv_get_directory(const char **directory, int compress)
 {
-  if (!options.AuthoritativeDir) {
+  if (!get_options()->AuthoritativeDir) {
     if (compress?cached_directory_z:cached_directory) {
       *directory = compress?cached_directory_z:cached_directory;
       return compress?cached_directory_z_len:cached_directory_len;
@@ -835,7 +832,7 @@
              "opt dir-signing-key %s\n"
              "directory-signature %s\n"
              "-----BEGIN SIGNATURE-----\n",
-          published, router_status, identity_pkey, options.Nickname);
+          published, router_status, identity_pkey, get_options()->Nickname);
   tor_free(router_status);
   tor_free(identity_pkey);
   if (router_get_runningrouters_hash(s,digest)) {

Index: dns.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dns.c,v
retrieving revision 1.116
retrieving revision 1.117
diff -u -d -r1.116 -r1.117
--- dns.c	27 Oct 2004 18:14:38 -0000	1.116
+++ dns.c	6 Nov 2004 05:18:11 -0000	1.117
@@ -15,8 +15,6 @@
 #include "or.h"
 #include "tree.h"
 
-extern or_options_t options; /* command-line and config-file options */
-
 /** Longest hostname we're willing to resolve. */
 #define MAX_ADDRESSLEN 256
 

Index: hibernate.c
===================================================================
RCS file: /home/or/cvsroot/src/or/hibernate.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- hibernate.c	5 Nov 2004 17:55:34 -0000	1.5
+++ hibernate.c	6 Nov 2004 05:18:11 -0000	1.6
@@ -30,8 +30,6 @@
 
 #define SHUTDOWN_WAIT_LENGTH 30 /* seconds */
 
-extern or_options_t options;
-
 static int hibernate_state = HIBERNATE_STATE_LIVE;
 static time_t hibernate_timeout = 0;
 
@@ -97,12 +95,12 @@
   /* Only months are supported. */
   tm = gmtime(&now);
   /* If this is before the Nth, we want the Nth of last month. */
-  if (tm->tm_mday < options.AccountingStart) {
+  if (tm->tm_mday < get_options()->AccountingStart) {
     decr_month(tm, 1);
   }
   /* Otherwise, the month and year are correct.*/
 
-  tm->tm_mday = options.AccountingStart;
+  tm->tm_mday = get_options()->AccountingStart;
   tm->tm_hour = 0;
   tm->tm_min = 0;
   tm->tm_sec = 0;
@@ -146,7 +144,7 @@
 update_expected_bandwidth(void)
 {
   uint64_t used;
-  uint32_t max_configured = (options.BandwidthRateBytes * 60);
+  uint32_t max_configured = (get_options()->BandwidthRateBytes * 60);
 
   if (n_seconds_active_in_interval < 1800) {
     expected_bandwidth_usage = max_configured;
@@ -183,7 +181,7 @@
   static time_t last_time_noted = 0;
 
   /* ???? Maybe only do this if accountingmaxkb is set ?
-  if (!options.AccountingMaxKB)
+  if (!get_options()->AccountingMaxKB)
     return 0;
   */
 
@@ -233,7 +231,7 @@
   crypto_digest_get_digest(d, digest, DIGEST_LEN);
   crypto_free_digest_env(d);
 
-  n_days_to_exhaust_bw = (options.AccountingMaxKB/expected_bandwidth_usage)
+  n_days_to_exhaust_bw = (get_options()->AccountingMaxKB/expected_bandwidth_usage)
     /(24*60);
 
   tm = gmtime(&interval_start_time);
@@ -272,7 +270,7 @@
                (unsigned long)n_seconds_active_in_interval,
                (unsigned long)expected_bandwidth_usage);
   tor_snprintf(fname, sizeof(fname), "%s/bw_accounting",
-               get_data_directory(&options));
+               get_data_directory());
 
   return write_str_to_file(fname, buf, 0);
 }
@@ -288,7 +286,7 @@
   int ok;
 
   tor_snprintf(fname, sizeof(fname), "%s/bw_accounting",
-               get_data_directory(&options));
+               get_data_directory());
   if (!(s = read_file_to_str(fname, 0))) {
     return 0;
   }
@@ -356,7 +354,7 @@
 
 static int hibernate_hard_limit_reached(void)
 {
-  uint64_t hard_limit = options.AccountingMaxKB<<10;
+  uint64_t hard_limit = get_options()->AccountingMaxKB<<10;
   if (!hard_limit)
     return 0;
   return n_bytes_read_in_interval >= hard_limit
@@ -365,7 +363,7 @@
 
 static int hibernate_soft_limit_reached(void)
 {
-  uint64_t soft_limit = (uint64_t) ((options.AccountingMaxKB<<10) * .99);
+  uint64_t soft_limit = (uint64_t) ((get_options()->AccountingMaxKB<<10) * .99);
   if (!soft_limit)
     return 0;
   return n_bytes_read_in_interval >= soft_limit

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.354
retrieving revision 1.355
diff -u -d -r1.354 -r1.355
--- main.c	4 Nov 2004 22:33:06 -0000	1.354
+++ main.c	6 Nov 2004 05:18:11 -0000	1.355
@@ -16,7 +16,6 @@
 
 /********* START VARIABLES **********/
 
-or_options_t options; /**< Command-line and config-file options. */
 int global_read_bucket; /**< Max number of bytes I can read this second. */
 int global_write_bucket; /**< Max number of bytes I can write this second. */
 
@@ -84,7 +83,7 @@
   tor_assert(conn);
   tor_assert(conn->s >= 0);
 
-  if(nfds >= options.MaxConn-1) {
+  if(nfds >= get_options()->MaxConn-1) {
     log_fn(LOG_WARN,"failing because nfds is too high.");
     return -1;
   }
@@ -355,6 +354,7 @@
 
 /** This function is called whenever we successfully pull down a directory */
 void directory_has_arrived(time_t now) {
+  or_options_t *options = get_options();
 
   log_fn(LOG_INFO, "A directory has arrived.");
 
@@ -363,9 +363,9 @@
    * seconds after the directory we had when we started.
    */
   if (!time_to_fetch_directory)
-    time_to_fetch_directory = now + options.DirFetchPostPeriod;
+    time_to_fetch_directory = now + options->DirFetchPostPeriod;
 
-  if (server_mode() &&
+  if (server_mode(options) &&
       !we_are_hibernating()) { /* connect to the appropriate routers */
     router_retry_connections();
   }
@@ -378,6 +378,7 @@
 static void run_connection_housekeeping(int i, time_t now) {
   cell_t cell;
   connection_t *conn = connection_array[i];
+  or_options_t *options = get_options();
 
   /* Expire any directory connections that haven't sent anything for 5 min */
   if(conn->type == CONN_TYPE_DIR &&
@@ -391,12 +392,12 @@
   /* If we haven't written to an OR connection for a while, then either nuke
      the connection or send a keepalive, depending. */
   if(connection_speaks_cells(conn) &&
-     now >= conn->timestamp_lastwritten + options.KeepalivePeriod) {
+     now >= conn->timestamp_lastwritten + options->KeepalivePeriod) {
     routerinfo_t *router = router_get_by_digest(conn->identity_digest);
     if((!connection_state_is_open(conn)) ||
        (we_are_hibernating() && !circuit_get_by_conn(conn)) ||
-       (!clique_mode() && !circuit_get_by_conn(conn) &&
-       (!router || !server_mode() || !router_is_clique_mode(router)))) {
+       (!clique_mode(options) && !circuit_get_by_conn(conn) &&
+       (!router || !server_mode(options) || !router_is_clique_mode(router)))) {
       /* our handshake has expired; we're hibernating;
        * or we have no circuits and we're both either OPs or normal ORs,
        * then kill it. */
@@ -430,17 +431,18 @@
  */
 static int decide_if_publishable_server(time_t now) {
   int bw;
+  or_options_t *options = get_options();
 
   bw = rep_hist_bandwidth_assess();
   router_set_bandwidth_capacity(bw);
 
-  if(options.ClientOnly)
+  if(options->ClientOnly)
     return 0;
-  if(!options.ORPort)
+  if(!options->ORPort)
     return 0;
 
   /* XXX008 for now, you're only a server if you're a server */
-  return server_mode();
+  return server_mode(options);
 
   /* here, determine if we're reachable */
   if(0) { /* we've recently failed to reach our IP/ORPort from the outside */
@@ -449,7 +451,7 @@
 
   if(bw < MIN_BW_TO_PUBLISH_DESC)
     return 0;
-  if(options.AuthoritativeDir)
+  if(options->AuthoritativeDir)
     return 1;
   if(stats_n_seconds_uptime < MIN_UPTIME_TO_PUBLISH_DESC)
     return 0;
@@ -460,20 +462,20 @@
 /** Return true iff we believe ourselves to be an authoritative
  * directory server.
  */
-int authdir_mode(void) {
-  return (options.AuthoritativeDir != 0);
+int authdir_mode(or_options_t *options) {
+  return options->AuthoritativeDir != 0;
 }
 
 /** Return true iff we try to stay connected to all ORs at once.
  */
-int clique_mode(void) {
-  return authdir_mode();
+int clique_mode(or_options_t *options) {
+  return authdir_mode(options);
 }
 
 /** Return true iff we are trying to be a server.
  */
-int server_mode(void) {
-  return (options.ORPort != 0 || options.ORBindAddress);
+int server_mode(or_options_t *options) {
+  return (options->ORPort != 0 || options->ORBindAddress);
 }
 
 /** Remember if we've advertised ourselves to the dirservers. */
@@ -486,8 +488,8 @@
 }
 
 /** Return true iff we are trying to be a socks proxy. */
-int proxy_mode(void) {
-  return (options.SocksPort != 0 || options.SocksBindAddress);
+int proxy_mode(or_options_t *options) {
+  return (options->SocksPort != 0 || options->SocksBindAddress);
 }
 
 /** Perform regular maintenance tasks.  This function gets run once per
@@ -497,6 +499,7 @@
   static time_t last_uploaded_services = 0;
   static time_t last_rotated_certificate = 0;
   static time_t time_to_check_listeners = 0;
+  or_options_t *options = get_options();
   int i;
 
   /** 0. See if we've been asked to shut down and our timeout has
@@ -509,7 +512,8 @@
    *  shut down and restart all cpuworkers, and update the directory if
    *  necessary.
    */
-  if (server_mode() && get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME < now) {
+  if (server_mode(options) &&
+      get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME < now) {
     log_fn(LOG_INFO,"Rotating onion key.");
     rotate_onion_key();
     cpuworkers_rotate();
@@ -525,7 +529,7 @@
     last_rotated_certificate = now;
   if (last_rotated_certificate+MAX_SSL_KEY_LIFETIME < now) {
     log_fn(LOG_INFO,"Rotating tls context.");
-    if (tor_tls_context_new(get_identity_key(), 1, options.Nickname,
+    if (tor_tls_context_new(get_identity_key(), 1, get_options()->Nickname,
                             MAX_SSL_KEY_LIFETIME) < 0) {
       log_fn(LOG_WARN, "Error reinitializing TLS context");
     }
@@ -553,11 +557,11 @@
     /* purge obsolete entries */
     routerlist_remove_old_routers(ROUTER_MAX_AGE);
 
-    if(authdir_mode()) {
+    if(authdir_mode(options)) {
       /* We're a directory; dump any old descriptors. */
       dirserv_remove_old_servers(ROUTER_MAX_AGE);
     }
-    if(server_mode() && !we_are_hibernating()) {
+    if(server_mode(options) && !we_are_hibernating()) {
       /* dirservers try to reconnect, in case connections have failed;
        * and normal servers try to reconnect to dirservers */
       router_retry_connections();
@@ -572,7 +576,7 @@
     }
     rend_cache_clean(); /* should this go elsewhere? */
 
-    time_to_fetch_directory = now + options.DirFetchPostPeriod;
+    time_to_fetch_directory = now + get_options()->DirFetchPostPeriod;
   }
 
   /** 3a. Every second, we examine pending circuits and prune the
@@ -685,34 +689,38 @@
  * configuration file.
  */
 static int init_from_config(int argc, char **argv) {
-  /* read the configuration file. */
-  if(getconfig(argc,argv,&options)) {
+  or_options_t *options;
+
+  /* read the configuration file. init and assign options. */
+  if(getconfig(argc,argv) < 0) {
     log_fn(LOG_ERR,"Reading config failed--see warnings above. For usage, try -h.");
     return -1;
   }
 
+  options = get_options();
+
   /* Setuid/setgid as appropriate */
-  if(options.User || options.Group) {
-    if(switch_id(options.User, options.Group) != 0) {
+  if(options->User || options->Group) {
+    if(switch_id(options->User, options->Group) != 0) {
       return -1;
     }
   }
 
   /* Ensure data directory is private; create if possible. */
-  if (get_data_directory(&options) &&
-      check_private_dir(get_data_directory(&options), 1) != 0) {
+  if (get_data_directory() &&
+      check_private_dir(get_data_directory(), 1) != 0) {
     log_fn(LOG_ERR, "Couldn't access/create private data directory %s",
-           get_data_directory(&options));
+           get_data_directory());
     return -1;
   }
 
   /* Bail out at this point if we're not going to be a server: we want
    * to not fork, and to log stuff to stderr. */
-  if (options.command != CMD_RUN_TOR)
+  if (options->command != CMD_RUN_TOR)
     return 0;
 
   /* Configure the log(s) */
-  if (config_init_logs(&options)<0)
+  if (config_init_logs(options)<0)
     return -1;
   /* Close the temporary log we used while starting up, if it isn't already
    * gone. */
@@ -720,8 +728,8 @@
   add_callback_log(LOG_WARN, LOG_ERR, control_event_logmsg);
 
   /* Start backgrounding the process, if requested. */
-  if (options.RunAsDaemon) {
-    start_daemon(get_data_directory(&options));
+  if (options->RunAsDaemon) {
+    start_daemon(get_data_directory());
   }
 
   /* Set up our buckets */
@@ -730,15 +738,15 @@
   stats_prev_global_write_bucket = global_write_bucket;
 
   /* Finish backgrounding the process */
-  if(options.RunAsDaemon) {
+  if(options->RunAsDaemon) {
     /* XXXX Can we delay this any more? */
     finish_daemon();
   }
 
   /* Write our pid to the pid file. If we do not have write permissions we
    * will log a warning */
-  if(options.PidFile)
-    write_pidfile(options.PidFile);
+  if(options->PidFile)
+    write_pidfile(options->PidFile);
 
   return 0;
 }
@@ -765,9 +773,9 @@
     log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
     return -1;
   }
-  if(authdir_mode()) {
+  if(authdir_mode(get_options())) {
     /* reload the approved-routers file */
-    tor_snprintf(keydir,sizeof(keydir),"%s/approved-routers", get_data_directory(&options));
+    tor_snprintf(keydir,sizeof(keydir),"%s/approved-routers", get_data_directory());
     log_fn(LOG_INFO,"Reloading approved fingerprints from %s...",keydir);
     if(dirserv_parse_fingerprint_file(keydir) < 0) {
       log_fn(LOG_WARN, "Error reloading fingerprints. Continuing with old list.");
@@ -775,14 +783,14 @@
   }
   /* Fetch a new directory. Even authdirservers do this. */
   directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 0);
-  if(server_mode()) {
+  if(server_mode(get_options())) {
     /* Restart cpuworker and dnsworker processes, so they get up-to-date
      * configuration options. */
     cpuworkers_rotate();
     dnsworkers_rotate();
     /* Rebuild fresh descriptor as needed. */
     router_rebuild_descriptor();
-    tor_snprintf(keydir,sizeof(keydir),"%s/router.desc", get_data_directory(&options));
+    tor_snprintf(keydir,sizeof(keydir),"%s/router.desc", get_data_directory());
     log_fn(LOG_INFO,"Dumping descriptor to %s...",keydir);
     if (write_str_to_file(keydir, router_get_my_descriptor(), 0)) {
       return -1;
@@ -817,12 +825,12 @@
     return -1;
   }
 
-  if(authdir_mode()) {
+  if(authdir_mode(get_options())) {
     /* the directory is already here, run startup things */
     router_retry_connections();
   }
 
-  if(server_mode()) {
+  if(server_mode(get_options())) {
     /* launch cpuworkers. Need to do this *after* we've read the onion key. */
     cpu_init();
   }
@@ -841,7 +849,7 @@
 #endif
 #ifndef MS_WINDOWS /* do signal stuff only on unix */
     if(please_shutdown) {
-      if(!server_mode()) { /* do it now */
+      if(!server_mode(get_options())) { /* do it now */
         log(LOG_NOTICE,"Interrupt: exiting cleanly.");
         tor_cleanup();
         exit(0);
@@ -1074,16 +1082,16 @@
     log_fn(LOG_WARN,"You are running Tor as root. You don't need to, and you probably shouldn't.");
 #endif
 
-  if(server_mode()) { /* only spawn dns handlers if we're a router */
+  if(server_mode(get_options())) { /* only spawn dns handlers if we're a router */
     dns_init(); /* initialize the dns resolve tree, and spawn workers */
   }
-  if(proxy_mode()) {
+  if(proxy_mode(get_options())) {
     client_dns_init(); /* init the client dns cache */
   }
 
   handle_signals(1);
 
-  if (set_max_file_descriptors(options.MaxConn) < 0)
+  if (set_max_file_descriptors(get_options()->MaxConn) < 0)
     return -1;
 
   crypto_global_init();
@@ -1093,10 +1101,11 @@
 
 /** Do whatever cleanup is necessary before shutting Tor down. */
 void tor_cleanup(void) {
+  or_options_t *options = get_options();
   /* Remove our pid file. We don't care if there was an error when we
    * unlink, nothing we could do about it anyways. */
-  if(options.PidFile && options.command == CMD_RUN_TOR)
-    unlink(options.PidFile);
+  if(options->PidFile && options->command == CMD_RUN_TOR)
+    unlink(options->PidFile);
   crypto_global_cleanup();
 }
 
@@ -1117,8 +1126,7 @@
     log_fn(LOG_ERR, "Error computing fingerprint");
     return;
   }
-  /*XXX is options.Nickname for-sure defined yet here? */
-  printf("%s %s\n", options.Nickname, buf);
+  printf("%s %s\n", get_options()->Nickname, buf);
 }
 
 /** DOCDOC **/
@@ -1131,7 +1139,7 @@
   crypto_rand(key, S2K_SPECIFIER_LEN-1);
   key[S2K_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */
   secret_to_key(key+S2K_SPECIFIER_LEN, DIGEST_LEN,
-                options.command_arg, strlen(options.command_arg),
+                get_options()->command_arg, strlen(get_options()->command_arg),
                 key);
   if (base64_encode(output, sizeof(output), key, sizeof(key))<0) {
     log_fn(LOG_ERR, "Unable to compute base64");
@@ -1209,7 +1217,7 @@
 #else
   if (tor_init(argc, argv)<0)
     return -1;
-  switch (options.command) {
+  switch (get_options()->command) {
   case CMD_RUN_TOR:
     do_main_loop();
     break;
@@ -1221,7 +1229,7 @@
     break;
   default:
     log_fn(LOG_ERR, "Illegal command number %d: internal error.",
-           options.command);
+           get_options()->command);
   }
   tor_cleanup();
   return -1;

Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/src/or/onion.c,v
retrieving revision 1.167
retrieving revision 1.168
diff -u -d -r1.167 -r1.168
--- onion.c	2 Nov 2004 02:28:51 -0000	1.167
+++ onion.c	6 Nov 2004 05:18:11 -0000	1.168
@@ -10,8 +10,6 @@
 
 #include "or.h"
 
-extern or_options_t options; /**< command-line and config-file options */
-
 struct onion_queue_t {
   circuit_t *circ;
   struct onion_queue_t *next;
@@ -44,7 +42,7 @@
   tor_assert(ol_list);
   tor_assert(!ol_tail->next);
 
-  if(ol_length >= options.MaxOnionsPending) {
+  if(ol_length >= get_options()->MaxOnionsPending) {
     log_fn(LOG_WARN,"Already have %d onions queued. Closing.", ol_length);
     tor_free(tmp);
     return -1;

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.463
retrieving revision 1.464
diff -u -d -r1.463 -r1.464
--- or.h	5 Nov 2004 05:50:35 -0000	1.463
+++ or.h	6 Nov 2004 05:18:11 -0000	1.464
@@ -1089,14 +1089,20 @@
   struct config_line_t *next;
 };
 
-int config_assign_default_dirservers(void);
+or_options_t *get_options(void);
+void set_options(or_options_t *new);
+
+int config_get_lines(char *string, struct config_line_t **result);
+void config_free_lines(struct config_line_t *front);
+int config_trial_assign(or_options_t **options, struct config_line_t *list, int reset);
 int resolve_my_address(const char *address, uint32_t *addr);
-int getconfig(int argc, char **argv, or_options_t *options);
+void options_init(or_options_t *options);
+int getconfig(int argc, char **argv);
 int config_init_logs(or_options_t *options);
 void config_parse_exit_policy(struct config_line_t *cfg,
                               struct exit_policy_t **dest);
 void exit_policy_free(struct exit_policy_t *p);
-const char *get_data_directory(or_options_t *options);
+const char *get_data_directory(void);
 struct config_line_t *config_get_assigned_option(or_options_t *options,
                                                  const char *key);
 struct config_line_t *config_line_prepend(struct config_line_t *front,
@@ -1330,11 +1336,11 @@
 void connection_start_writing(connection_t *conn);
 
 void directory_has_arrived(time_t now);
-int authdir_mode(void);
-int clique_mode(void);
-int server_mode(void);
+int authdir_mode(or_options_t *options);
+int clique_mode(or_options_t *options);
+int server_mode(or_options_t *options);
 int advertised_server_mode(void);
-int proxy_mode(void);
+int proxy_mode(or_options_t *options);
 
 void handle_signals(int is_parent);
 void tor_cleanup(void);

Index: relay.c
===================================================================
RCS file: /home/or/cvsroot/src/or/relay.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- relay.c	2 Nov 2004 03:02:17 -0000	1.16
+++ relay.c	6 Nov 2004 05:18:11 -0000	1.17
@@ -10,8 +10,6 @@
 
 #include "or.h"
 
-extern or_options_t options; /* command-line and config-file options */
-
 static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
                 crypt_path_t **layer_hint, char *recognized);
 static connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction);
@@ -546,7 +544,7 @@
         conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
         circuit_detach_stream(circ,conn);
         tor_assert(circ->timestamp_dirty);
-        circ->timestamp_dirty -= options.NewCircuitPeriod;
+        circ->timestamp_dirty -= get_options()->NewCircuitPeriod;
         /* make sure not to expire/retry the stream quite yet */
         conn->timestamp_lastread = time(NULL);
         if(connection_ap_handshake_attach_circuit(conn) >= 0)

Index: rendservice.c
===================================================================
RCS file: /home/or/cvsroot/src/or/rendservice.c,v
retrieving revision 1.100
retrieving revision 1.101
diff -u -d -r1.100 -r1.101
--- rendservice.c	2 Nov 2004 02:28:51 -0000	1.100
+++ rendservice.c	6 Nov 2004 05:18:11 -0000	1.101
@@ -9,8 +9,6 @@
 
 #include "or.h"
 
-extern or_options_t options; /* command-line and config-file options */
-
 static circuit_t *find_intro_circuit(routerinfo_t *router, const char *pk_digest);
 
 /** Represents the mapping from a virtual port of a rendezvous service to
@@ -846,7 +844,7 @@
     for (j=prev_intro_nodes; j < NUM_INTRO_POINTS; ++j) {
       router = router_choose_random_node(service->intro_prefer_nodes,
                service->intro_exclude_nodes, exclude_routers, 1, 0,
-               options._AllowUnverified & ALLOW_UNVERIFIED_INTRODUCTION, 0);
+               get_options()->_AllowUnverified & ALLOW_UNVERIFIED_INTRODUCTION, 0);
       if (!router) {
         log_fn(LOG_WARN, "Could only establish %d introduction points for %s",
                smartlist_len(service->intro_nodes), service->service_id);

Index: router.c
===================================================================
RCS file: /home/or/cvsroot/src/or/router.c,v
retrieving revision 1.109
retrieving revision 1.110
diff -u -d -r1.109 -r1.110
--- router.c	4 Nov 2004 03:25:43 -0000	1.109
+++ router.c	6 Nov 2004 05:18:11 -0000	1.110
@@ -10,7 +10,6 @@
  * and uploading server descriptors, retrying OR connections.
  **/
 
-extern or_options_t options; /* command-line and config-file options */
 extern long stats_n_seconds_uptime;
 
 /** Exposed for test.c. */ void get_platform_str(char *platform, size_t len);
@@ -102,9 +101,9 @@
   char fname_prev[512];
   crypto_pk_env_t *prkey;
   tor_snprintf(fname,sizeof(fname),
-           "%s/keys/secret_onion_key",get_data_directory(&options));
+           "%s/keys/secret_onion_key",get_data_directory());
   tor_snprintf(fname_prev,sizeof(fname_prev),
-           "%s/keys/secret_onion_key.old",get_data_directory(&options));
+           "%s/keys/secret_onion_key.old",get_data_directory());
   if (!(prkey = crypto_new_pk_env())) {
     log(LOG_ERR, "Error creating crypto environment.");
     goto error;
@@ -231,13 +230,14 @@
   const char *tmp, *mydesc, *datadir;
   crypto_pk_env_t *prkey;
   char digest[20];
+  or_options_t *options = get_options();
 
   if (!key_lock)
     key_lock = tor_mutex_new();
 
   /* OP's don't need persistant keys; just make up an identity and
    * initialize the TLS context. */
-  if (!server_mode()) {
+  if (!server_mode(options)) {
     if (!(prkey = crypto_new_pk_env()))
       return -1;
     if (crypto_pk_generate_key(prkey))
@@ -245,8 +245,8 @@
     set_identity_key(prkey);
     /* XXX NM: do we have a convention for what client's Nickname is?
      * No.  Let me propose one: */
-    if (tor_tls_context_new(get_identity_key(), 1, 
-                            options.Nickname ? options.Nickname : "client",
+    if (tor_tls_context_new(get_identity_key(), 1,
+                            options->Nickname ? options->Nickname : "client",
                             MAX_SSL_KEY_LIFETIME) < 0) {
       log_fn(LOG_ERR, "Error creating TLS context for OP.");
       return -1;
@@ -254,7 +254,7 @@
     return 0;
   }
   /* Make sure DataDirectory exists, and is private. */
-  datadir = get_data_directory(&options);
+  datadir = get_data_directory();
   tor_assert(datadir);
   if (strlen(datadir) > (512-128)) {
     log_fn(LOG_ERR, "DataDirectory is too long.");
@@ -292,7 +292,7 @@
   }
 
   /* 3. Initialize link key and TLS context. */
-  if (tor_tls_context_new(get_identity_key(), 1, options.Nickname,
+  if (tor_tls_context_new(get_identity_key(), 1, options->Nickname,
                           MAX_SSL_KEY_LIFETIME) < 0) {
     log_fn(LOG_ERR, "Error initializing TLS context");
     return -1;
@@ -304,9 +304,9 @@
     log_fn(LOG_ERR, "Error initializing descriptor.");
     return -1;
   }
-  if(authdir_mode()) {
+  if(authdir_mode(options)) {
     /* We need to add our own fingerprint so it gets recognized. */
-    if (dirserv_add_own_fingerprint(options.Nickname, get_identity_key())) {
+    if (dirserv_add_own_fingerprint(options->Nickname, get_identity_key())) {
       log_fn(LOG_ERR, "Error adding own fingerprint to approved set");
       return -1;
     }
@@ -324,8 +324,8 @@
   /* 5. Dump fingerprint to 'fingerprint' */
   tor_snprintf(keydir,sizeof(keydir),"%s/fingerprint", datadir);
   log_fn(LOG_INFO,"Dumping fingerprint to %s...",keydir);
-  tor_assert(strlen(options.Nickname) <= MAX_NICKNAME_LEN);
-  strlcpy(fingerprint, options.Nickname, sizeof(fingerprint));
+  tor_assert(strlen(options->Nickname) <= MAX_NICKNAME_LEN);
+  strlcpy(fingerprint, options->Nickname, sizeof(fingerprint));
   strlcat(fingerprint, " ", sizeof(fingerprint));
   if (crypto_pk_get_fingerprint(get_identity_key(),
                                 fingerprint+strlen(fingerprint), 1)<0) {
@@ -335,7 +335,7 @@
   strlcat(fingerprint, "\n", sizeof(fingerprint));
   if (write_str_to_file(keydir, fingerprint, 0))
     return -1;
-  if(!authdir_mode())
+  if(!authdir_mode(options))
     return 0;
   /* 6. [authdirserver only] load approved-routers file */
   tor_snprintf(keydir,sizeof(keydir),"%s/approved-routers", datadir);
@@ -347,7 +347,7 @@
   /* 6b. [authdirserver only] add own key to approved directories. */
   crypto_pk_get_digest(get_identity_key(), digest);
   if (!router_digest_is_trusted_dir(digest)) {
-    add_trusted_dir_server(options.Address, (uint16_t)options.DirPort, digest);
+    add_trusted_dir_server(options->Address, (uint16_t)options->DirPort, digest);
   }
   /* 7. [authdirserver only] load old directory, if it's there */
   tor_snprintf(keydir,sizeof(keydir),"%s/cached-directory", datadir);
@@ -380,8 +380,9 @@
   int i;
   routerinfo_t *router;
   routerlist_t *rl;
+  or_options_t *options = get_options();
 
-  tor_assert(server_mode());
+  tor_assert(server_mode(options));
 
   router_get_routerlist(&rl);
   if (!rl) return;
@@ -389,7 +390,7 @@
     router = smartlist_get(rl->routers, i);
     if(router_is_me(router))
       continue;
-    if(!clique_mode() && !router_is_clique_mode(router))
+    if(!clique_mode(options) && !router_is_clique_mode(router))
       continue;
     if(!connection_get_by_identity_digest(router->identity_digest,
                                           CONN_TYPE_OR)) {
@@ -438,7 +439,7 @@
 static void router_add_exit_policy_from_config(routerinfo_t *router) {
   struct exit_policy_t *ep;
   struct config_line_t default_policy;
-  config_parse_exit_policy(options.ExitPolicy, &router->exit_policy);
+  config_parse_exit_policy(get_options()->ExitPolicy, &router->exit_policy);
 
   for (ep = router->exit_policy; ep; ep = ep->next) {
     if (ep->msk == 0 && ep->prt_min <= 1 && ep->prt_max >= 65535) {
@@ -487,7 +488,7 @@
  * necessary.  Return NULL on error, or if called on an OP. */
 routerinfo_t *router_get_my_routerinfo(void)
 {
-  if (!server_mode())
+  if (!server_mode(get_options()))
     return NULL;
 
   if (!desc_routerinfo) {
@@ -517,20 +518,21 @@
   uint32_t addr;
   char platform[256];
   struct in_addr in;
+  or_options_t *options = get_options();
 
-  if(resolve_my_address(options.Address, &addr) < 0) {
-    log_fn(LOG_WARN,"options.Address didn't resolve into an IP.");
+  if(resolve_my_address(options->Address, &addr) < 0) {
+    log_fn(LOG_WARN,"options->Address didn't resolve into an IP.");
     return -1;
   }
 
   ri = tor_malloc_zero(sizeof(routerinfo_t));
   in.s_addr = htonl(addr);
   ri->address = tor_strdup(inet_ntoa(in));
-  ri->nickname = tor_strdup(options.Nickname);
+  ri->nickname = tor_strdup(options->Nickname);
   ri->addr = addr;
-  ri->or_port = options.ORPort;
-  ri->socks_port = options.SocksPort;
-  ri->dir_port = options.DirPort;
+  ri->or_port = options->ORPort;
+  ri->socks_port = options->SocksPort;
+  ri->dir_port = options->DirPort;
   ri->published_on = time(NULL);
   ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from main thread */
   ri->identity_pkey = crypto_pk_dup_key(get_identity_key());
@@ -540,15 +542,15 @@
   }
   get_platform_str(platform, sizeof(platform));
   ri->platform = tor_strdup(platform);
-  ri->bandwidthrate = options.BandwidthRateBytes;
-  ri->bandwidthburst = options.BandwidthBurstBytes;
+  ri->bandwidthrate = options->BandwidthRateBytes;
+  ri->bandwidthburst = options->BandwidthBurstBytes;
   ri->bandwidthcapacity = router_get_bandwidth_capacity();
   router_add_exit_policy_from_config(ri);
   if(desc_routerinfo) /* inherit values */
     ri->is_verified = desc_routerinfo->is_verified;
-  if (options.MyFamily) {
+  if (options->MyFamily) {
     ri->declared_family = smartlist_create();
-    smartlist_split_string(ri->declared_family, options.MyFamily, ",",
+    smartlist_split_string(ri->declared_family, options->MyFamily, ",",
                            SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
   }
 
@@ -686,9 +688,9 @@
   /* From now on, we use 'written' to remember the current length of 's'. */
   written = result;
 
-  if (options.ContactInfo && strlen(options.ContactInfo)) {
+  if (get_options()->ContactInfo && strlen(get_options()->ContactInfo)) {
     result = tor_snprintf(s+written,maxlen-written, "opt contact %s\n",
-                      options.ContactInfo);
+                      get_options()->ContactInfo);
     if (result<0 || result+written > maxlen)
       return -1;
     written += result;

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routerlist.c,v
retrieving revision 1.176
retrieving revision 1.177
diff -u -d -r1.176 -r1.177
--- routerlist.c	4 Nov 2004 23:39:57 -0000	1.176
+++ routerlist.c	6 Nov 2004 05:18:11 -0000	1.177
@@ -14,10 +14,6 @@
 
 /****************************************************************************/
 
-extern or_options_t options; /**< command-line and config-file options */
-
-/* ********************************************************************** */
-
 static smartlist_t *trusted_dir_servers = NULL;
 
 /* static function prototypes */
@@ -50,9 +46,9 @@
   char filename[512];
   int is_recent;
   struct stat st;
-  if (get_data_directory(&options)) {
+  if (get_data_directory()) {
     char *s;
-    tor_snprintf(filename,sizeof(filename),"%s/cached-directory", get_data_directory(&options));
+    tor_snprintf(filename,sizeof(filename),"%s/cached-directory", get_data_directory());
     if (stat(filename, &st)) {
       log_fn(LOG_WARN, "Unable to check status for '%s': %s", filename,
              strerror(errno));
@@ -114,7 +110,7 @@
     return choice;
 
   log_fn(LOG_INFO,"Still no %s router entries. Reloading and trying again.",
-         options.FascistFirewall ? "reachable" : "known");
+         get_options()->FascistFirewall ? "reachable" : "known");
   has_fetched_directory=0; /* reset it */
   if(router_reload_router_list()) {
     return NULL;
@@ -141,7 +137,7 @@
     return choice;
 
   log_fn(LOG_WARN,"Still no dirservers %s. Reloading and trying again.",
-         options.FascistFirewall ? "reachable" : "known");
+         get_options()->FascistFirewall ? "reachable" : "known");
   has_fetched_directory=0; /* reset it */
   if(router_reload_router_list()) {
     return NULL;
@@ -165,7 +161,7 @@
   if(!routerlist)
     return NULL;
 
-  if(options.HttpProxy)
+  if(get_options()->HttpProxy)
     fascistfirewall = 0;
 
   /* Find all the running dirservers we know about. */
@@ -178,7 +174,7 @@
       continue;
     if(fascistfirewall) {
       tor_snprintf(buf,sizeof(buf),"%d",router->dir_port);
-      if (!smartlist_string_isin(options.FirewallPorts, buf))
+      if (!smartlist_string_isin(get_options()->FirewallPorts, buf))
         continue;
     }
     smartlist_add(sl, router);
@@ -202,7 +198,7 @@
   if (!trusted_dir_servers)
     return NULL;
 
-  if(options.HttpProxy)
+  if(get_options()->HttpProxy)
     fascistfirewall = 0;
 
   SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
@@ -213,7 +209,7 @@
         continue;
       if (fascistfirewall) {
         tor_snprintf(buf,sizeof(buf),"%d",d->dir_port);
-        if (!smartlist_string_isin(options.FirewallPorts, buf))
+        if (!smartlist_string_isin(get_options()->FirewallPorts, buf))
           continue;
       }
       smartlist_add(sl, d);
@@ -276,7 +272,7 @@
     });
 
 
-  for (cl = options.NodeFamilies; cl; cl = cl->next) {
+  for (cl = get_options()->NodeFamilies; cl; cl = cl->next) {
     if (router_nickname_is_in_list(router, cl->value)) {
       add_nickname_list_to_smartlist(sl, cl->value, 0);
     }
@@ -867,7 +863,7 @@
     log_fn(LOG_WARN, "Error resolving routerlist");
     return -1;
   }
-  if (options.AuthoritativeDir) {
+  if (get_options()->AuthoritativeDir) {
     /* Learn about the descriptors in the directory. */
     dirserv_load_from_directory_string(s);
   }

Index: routerparse.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routerparse.c,v
retrieving revision 1.70
retrieving revision 1.71
diff -u -d -r1.70 -r1.71
--- routerparse.c	2 Nov 2004 03:02:17 -0000	1.70
+++ routerparse.c	6 Nov 2004 05:18:11 -0000	1.71
@@ -12,8 +12,6 @@
 
 /****************************************************************************/
 
-extern or_options_t options; /* command-line and config-file options */
-
 /** Enumeration of possible token types.  The ones starting with K_
  * correspond to directory 'keywords'.  _UNRECOGNIZED is for an
  * unrecognized keyword; _ERR is an error in the tokenizing process,
@@ -351,7 +349,7 @@
 
   /* Now that we know the signature is okay, check the version. */
   if (check_version)
-    check_software_version_against_directory(str, options.IgnoreVersion);
+    check_software_version_against_directory(str, get_options()->IgnoreVersion);
 
   /* Now try to parse the first part of the directory. */
   if ((end = strstr(str,"\nrouter "))) {

Index: test.c
===================================================================
RCS file: /home/or/cvsroot/src/or/test.c,v
retrieving revision 1.140
retrieving revision 1.141
diff -u -d -r1.140 -r1.141
--- test.c	4 Nov 2004 22:29:45 -0000	1.140
+++ test.c	6 Nov 2004 05:18:11 -0000	1.141
@@ -16,8 +16,6 @@
 #include "../common/test.h"
 #include "../common/torgzip.h"
 
-extern or_options_t options;
-
 int have_failed = 0;
 
 /* These functions are file-local, but are exposed so we can test. */
@@ -1094,7 +1092,7 @@
   test_assert(router_dump_router_to_string(buf, 2048, &r2, pk1)>0);
   cp = buf;
   test_eq(dirserv_add_descriptor((const char**)&cp), 1);
-  options.Nickname = tor_strdup("DirServer");
+  get_options()->Nickname = tor_strdup("DirServer");
   test_assert(!dirserv_dump_directory_to_string(buf,8192,pk3));
   cp = buf;
   test_assert(!router_parse_routerlist_from_directory(buf, &dir1, pk3, 1));
@@ -1202,12 +1200,9 @@
 
 int
 main(int c, char**v){
-#if 0
-  or_options_t options; /* command-line and config-file options */
-
-  if(getconfig(c,v,&options))
-    exit(1);
-#endif
+  or_options_t *options = tor_malloc_zero(sizeof(or_options_t));
+  options_init(options);
+  set_options(options);
 
   crypto_seed_rng();
   setup_directory();



More information about the tor-commits mailing list