[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[or-cvs] directory servers in and functional



Update of /home/or/cvsroot/src/or
In directory moria.seul.org:/home/arma/work/onion/cvs/src/or

Modified Files:
	Makefile.am config.c connection.c connection_exit.c 
	connection_or.c main.c or.h routers.c 
Added Files:
	directory.c 
Log Message:
directory servers in and functional

proxies now periodically pull down an hourly-updated directory,
and replace their router list with it if it parses correctly.


--- NEW FILE: directory.c ---
(This appears to be a binary file; contents omitted.)

Index: Makefile.am
===================================================================
RCS file: /home/or/cvsroot/src/or/Makefile.am,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- Makefile.am	3 Sep 2002 22:53:34 -0000	1.7
+++ Makefile.am	26 Sep 2002 12:09:09 -0000	1.8
@@ -9,7 +9,7 @@
 
 or_SOURCES = buffers.c cell.c circuit.c command.c connection.c \
              connection_exit.c connection_ap.c connection_op.c connection_or.c config.c \
-             main.c onion.c routers.c
+             main.c onion.c routers.c directory.c
 
 test_config_SOURCES = test_config.c
 

Index: config.c
===================================================================
RCS file: /home/or/cvsroot/src/or/config.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- config.c	4 Sep 2002 06:29:27 -0000	1.16
+++ config.c	26 Sep 2002 12:09:09 -0000	1.17
@@ -85,6 +85,8 @@
          0, "onion proxy port",                                "<port>" },
       { "ORPort",          'p',  POPT_ARG_INT,     &options->ORPort,
          0, "onion router port",                               "<port>" },
+      { "DirPort",         'd',  POPT_ARG_INT,     &options->DirPort,
+         0, "directory server port",                           "<port>" },
       { "PrivateKeyFile",  'k',  POPT_ARG_STRING,  &options->PrivateKeyFile,
          0, "maximum number of incoming connections",          "<file>" },
       { "RouterFile",      'r',  POPT_ARG_STRING,  &options->RouterFile,
@@ -92,8 +94,14 @@
       { "TrafficShaping",  't',  POPT_ARG_INT,     &options->TrafficShaping,
          0, "which traffic shaping policy to use",             "<policy>" },
       { "LinkPadding",     'P',  POPT_ARG_INT,     &options->LinkPadding,
-	 0, "whether to use link padding",                     "<padding>" },
-      { "Role",            'g',  POPT_ARG_INT,     &options->Role,
+         0, "whether to use link padding",                     "<padding>" },
+      { "DirRebuildPeriod",'D',  POPT_ARG_INT,     &options->DirRebuildPeriod,
+         0, "how many seconds between directory rebuilds",     "<rebuildperiod>" },
+      { "DirFetchPeriod",  'F',  POPT_ARG_INT,     &options->DirFetchPeriod,
+         0, "how many seconds between directory fetches",     "<fetchperiod>" },
+//      { "ReconnectPeriod", 'e',  POPT_ARG_INT,     &options->ReconnectPeriod,
+//         0, "how many seconds between retrying all OR connections", "<reconnectperiod>" },
+      { "Role",            'R',  POPT_ARG_INT,     &options->Role,
          0, "4-bit global role id",                            "<role>" },
       { "Verbose",         'v',  POPT_ARG_NONE,    &Verbose,
          0, "display options selected before execution",       NULL },
@@ -112,7 +120,11 @@
    options->loglevel = LOG_DEBUG;
    options->CoinWeight = 0.8;
    options->LinkPadding = 0;
-   options->Role = ROLE_OR_LISTEN | ROLE_OR_CONNECT_ALL | ROLE_OP_LISTEN | ROLE_AP_LISTEN;
+   options->DirRebuildPeriod = 600;
+   options->DirFetchPeriod = 6000;
+//   options->ReconnectPeriod = 6001;
+   options->Role = ROLE_OR_LISTEN | ROLE_OR_CONNECT_ALL | ROLE_OP_LISTEN | ROLE_AP_LISTEN |
+                   ROLE_DIR_LISTEN | ROLE_DIR_SERVER;
 
    code = poptGetNextOpt(optCon);         /* first we handle command-line args */
    if ( code == -1 )
@@ -151,14 +163,17 @@
       printf("RouterFile=%s, PrivateKeyFile=%s\n",
              options->RouterFile,
              options->PrivateKeyFile);
-      printf("ORPort=%d, OPPort=%d, APPort=%d\n",
+      printf("ORPort=%d, OPPort=%d, APPort=%d DirPort=%d\n",
              options->ORPort,options->OPPort,
-             options->APPort);
+             options->APPort,options->DirPort);
       printf("CoinWeight=%6.4f, MaxConn=%d, TrafficShaping=%d, LinkPadding=%d\n",
              options->CoinWeight,
              options->MaxConn,
              options->TrafficShaping,
              options->LinkPadding);
+      printf("DirRebuildPeriod=%d, DirFetchPeriod=%d\n",
+             options->DirRebuildPeriod,
+             options->DirFetchPeriod);
    }
 
    /* Validate options */
@@ -188,9 +203,9 @@
       }
    }
 
-   if ( options->Role < 0 || options->Role > 15 )
+   if ( options->Role < 0 || options->Role > 63 )
    {
-      log(LOG_ERR,"Role option must be an integer between 0 and 15 (inclusive).");
+      log(LOG_ERR,"Role option must be an integer between 0 and 63 (inclusive).");
       code = -1;
    }
 
@@ -224,6 +239,12 @@
       code = -1;
    }
 
+   if ( (options->Role & ROLE_DIR_LISTEN) && options->DirPort < 1 )
+   {
+      log(LOG_ERR,"DirPort option required and must be a positive integer value.");
+      code = -1;
+   }
+
    if ( (options->Role & ROLE_AP_LISTEN) &&
         (options->CoinWeight < 0.0 || options->CoinWeight >= 1.0) )
    {
@@ -252,6 +273,18 @@
    if ( options->LinkPadding != 0 && options->LinkPadding != 1 )
    {
       log(LOG_ERR,"LinkPadding option must be either 0 or 1.");
+      code = -1;
+   }
+
+   if ( options->DirRebuildPeriod < 1)
+   {
+      log(LOG_ERR,"DirRebuildPeriod option must be positive.");
+      code = -1;
+   }
+
+   if ( options->DirFetchPeriod < 1)
+   {
+      log(LOG_ERR,"DirFetchPeriod option must be positive.");
       code = -1;
    }
 

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- connection.c	24 Sep 2002 10:43:56 -0000	1.24
+++ connection.c	26 Sep 2002 12:09:10 -0000	1.25
@@ -16,10 +16,12 @@
   "OR",          /* 4 */
   "Exit",        /* 5 */
   "App listener",/* 6 */
-  "App"          /* 7 */
+  "App",         /* 7 */
+  "Dir listener",/* 8 */
+  "Dir",         /* 9 */
 };
 
-char *conn_state_to_string[][10] = {
+char *conn_state_to_string[][15] = {
   { },         /* no type associated with 0 */
   { "ready" }, /* op listener, 0 */
   { "awaiting keys", /* op, 0 */
@@ -43,7 +45,13 @@
   { "ready" }, /* app listener, 0 */
   { "awaiting dest info",         /* app, 0 */
     "waiting for OR connection",       /* 1 */
-    "open" }                           /* 2 */
+    "open" },                          /* 2 */
+  { "ready" }, /* dir listener, 0 */
+  { "connecting",                      /* 0 */
+    "sending command",                 /* 1 */
+    "reading",                         /* 2 */
+    "awaiting command",                /* 3 */
+    "writing" },                       /* 4 */
 };
 
 /********* END VARIABLES ************/
@@ -261,27 +269,20 @@
   return 0;
 }
 
-int retry_all_connections(int role, routerinfo_t **router_array, int rarray_len,
-  crypto_pk_env_t *prkey, uint16_t or_listenport, uint16_t op_listenport, uint16_t ap_listenport) {
+int retry_all_connections(int role, crypto_pk_env_t *prkey, uint16_t or_listenport,
+  uint16_t op_listenport, uint16_t ap_listenport, uint16_t dir_listenport) {
 
   /* start all connections that should be up but aren't */
 
-  routerinfo_t *router;
-  int i;
   struct sockaddr_in local; /* local address */
 
   if(learn_local(&local) < 0)
     return -1;
 
   local.sin_port = htons(or_listenport);
+
   if(role & ROLE_OR_CONNECT_ALL) {
-    for (i=0;i<rarray_len;i++) {
-      router = router_array[i];
-      if(!connection_exact_get_by_addr_port(router->addr,router->or_port)) { /* not in the list */
-        log(LOG_DEBUG,"retry_all_connections(): connecting to OR %s:%u.",router->address,router->or_port);
-        connection_or_connect_as_or(router, prkey, &local);
-      }
-    }
+    router_retry_connections(prkey, &local);
   }
 
   if(role & ROLE_OR_LISTEN) {
@@ -303,6 +304,13 @@
       connection_ap_create_listener(NULL, &local); /* no need to tell it the private key. */
     }
   }
+
+  if(role & ROLE_DIR_LISTEN) {
+    local.sin_port = htons(dir_listenport);
+    if(!connection_get_by_type(CONN_TYPE_DIR_LISTENER)) {
+      connection_dir_create_listener(NULL, &local); /* no need to tell it the private key. */
+    }
+  }
  
   return 0;
 }
@@ -415,7 +423,8 @@
 int connection_is_listener(connection_t *conn) {
   if(conn->type == CONN_TYPE_OP_LISTENER ||
      conn->type == CONN_TYPE_OR_LISTENER ||
-     conn->type == CONN_TYPE_AP_LISTENER)
+     conn->type == CONN_TYPE_AP_LISTENER ||
+     conn->type == CONN_TYPE_DIR_LISTENER)
     return 1;
   return 0;
 }
@@ -586,6 +595,8 @@
       return connection_exit_process_inbuf(conn);
     case CONN_TYPE_AP:
       return connection_ap_process_inbuf(conn);
+    case CONN_TYPE_DIR:
+      return connection_dir_process_inbuf(conn);
     default:
       log(LOG_DEBUG,"connection_process_inbuf() got unexpected conn->type.");
       return -1;
@@ -709,6 +720,8 @@
       return connection_or_finished_flushing(conn);
     case CONN_TYPE_EXIT:
       return connection_exit_finished_flushing(conn);
+    case CONN_TYPE_DIR:
+      return connection_dir_finished_flushing(conn);
     default:
       log(LOG_DEBUG,"connection_finished_flushing() got unexpected conn->type.");
       return -1;

Index: connection_exit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_exit.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- connection_exit.c	22 Sep 2002 11:09:07 -0000	1.11
+++ connection_exit.c	26 Sep 2002 12:09:10 -0000	1.12
@@ -179,8 +179,8 @@
         /* also, deliver a 'connected' cell back through the circuit. */
         return connection_exit_send_connected(conn);
       } else {
-	log(LOG_DEBUG,"connection_exit_process_data_cell(): in connecting_wait, but I've already received everything. Closing.");
-	return -1;
+        log(LOG_DEBUG,"connection_exit_process_data_cell(): in connecting_wait, but I've already received everything. Closing.");
+        return -1;
       }
       return 0;
     case EXIT_CONN_STATE_CONNECTING:

Index: connection_or.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_or.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- connection_or.c	24 Sep 2002 10:43:56 -0000	1.14
+++ connection_or.c	26 Sep 2002 12:09:10 -0000	1.15
@@ -66,7 +66,7 @@
       if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0)  { /* not yet */
         if(errno != EINPROGRESS){
           /* yuck. kill it. */
-          log(LOG_DEBUG,"connection_or_finished_flushing(): in-progress connect failed. Removing.");	
+          log(LOG_DEBUG,"connection_or_finished_flushing(): in-progress connect failed. Removing.");
           return -1;
         } else {
           return 0; /* no change, see if next time is better */

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- main.c	24 Sep 2002 10:43:56 -0000	1.24
+++ main.c	26 Sep 2002 12:09:10 -0000	1.25
@@ -21,10 +21,6 @@
 /* private key */
 static crypto_pk_env_t *prkey;
 
-/* router array */
-static routerinfo_t **router_array = NULL;
-static int rarray_len = 0;
-
 /********* END VARIABLES ************/
 
 /****************************************************************************
@@ -154,44 +150,6 @@
 
 
 
-/* the next 4 functions should move to routers.c once we get it
- * cleaned up more. The router_array and rarray_len variables should
- * move there too.
- */
-
-routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
-  int i;
-  routerinfo_t *router;
-
-  assert(router_array);
-
-  for(i=0;i<rarray_len;i++) {
-    router = router_array[i];
-    if ((router->addr == addr) && (router->or_port == port))
-      return router;
-  }
-
-  return NULL;
-}
-
-routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen) {
-  return router_array[route[routelen-1]];
-}
-
-/* a wrapper around new_route. put all these in routers.c perhaps? */
-unsigned int *router_new_route(int *routelen) {
-  return new_route(options.CoinWeight, router_array, rarray_len, routelen);
-}
-
-/* a wrapper around create_onion */
-unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath) {
-  return create_onion(router_array,rarray_len,route,routelen,len,cpath);
-}
-
-
-
-
-
 /* FIXME can we cut this function out? */
 connection_t *connect_to_router_as_op(routerinfo_t *router) {
   return connection_connect_to_router_as_op(router, options.ORPort);
@@ -252,12 +210,13 @@
       retval = connection_or_handle_listener_read(conn);
     } else if (conn->type == CONN_TYPE_AP_LISTENER) {
       retval = connection_ap_handle_listener_read(conn);
+    } else if (conn->type == CONN_TYPE_DIR_LISTENER) {
+      retval = connection_dir_handle_listener_read(conn);
     } else {
-      /* else it's an OP, OR, or exit */
       retval = connection_read_to_buf(conn);
       if (retval >= 0) { /* all still well */
         retval = connection_process_inbuf(conn);
-//	log(LOG_DEBUG,"check_conn_read(): connection_process_inbuf returned %d.",retval);
+//      log(LOG_DEBUG,"check_conn_read(): connection_process_inbuf returned %d.",retval);
         if(retval >= 0 && !connection_state_is_open(conn) && conn->receiver_bucket == 0) {
           log(LOG_DEBUG,"check_conn_read(): receiver bucket reached 0 before handshake finished. Closing.");
           retval = -1;
@@ -286,8 +245,7 @@
     conn = connection_array[i];
 //    log(LOG_DEBUG,"check_conn_write(): socket %d wants to write.",conn->s);
 
-    if(conn->type == CONN_TYPE_OP_LISTENER ||
-       conn->type == CONN_TYPE_OR_LISTENER) {
+    if(connection_is_listener(conn)) {
       log(LOG_DEBUG,"check_conn_write(): Got a listener socket. Can't happen!");
       retval = -1;
     } else {
@@ -337,6 +295,8 @@
   connection_t *tmpconn;
   struct timeval now, soonest;
   static int current_second = 0; /* from previous calls to gettimeofday */
+  static int time_to_rebuild_directory = 0;
+  static int time_to_fetch_directory = 0;
   int ms_until_conn;
 
   *timeout = -1; /* set it to never timeout, possibly overridden below */
@@ -352,6 +312,34 @@
   if(gettimeofday(&now,NULL) < 0)
     return -1;
 
+  if(options.Role & ROLE_DIR_SERVER) {
+    if(time_to_rebuild_directory < now.tv_sec) {
+      /* it's time to rebuild our directory */
+      if(time_to_rebuild_directory == 0) { 
+        /* we just started up. if we build a directory now it will be meaningless. */
+        log(LOG_DEBUG,"prepare_for_poll(): Delaying initial dir build for 15 seconds.");
+        time_to_rebuild_directory = now.tv_sec + 15; /* try in 15 seconds */
+      } else {
+        directory_rebuild();
+        time_to_rebuild_directory = now.tv_sec + options.DirRebuildPeriod;
+      }
+    }
+    *timeout = 1000*(time_to_rebuild_directory - now.tv_sec) + (1000 - (now.tv_usec / 1000));
+//    log(LOG_DEBUG,"prepare_for_poll(): DirBuild timeout is %d",*timeout);
+  }
+
+  if(!(options.Role & ROLE_DIR_SERVER)) {
+    if(time_to_fetch_directory < now.tv_sec) {
+      /* it's time to fetch a new directory */
+      /* NOTE directory servers do not currently fetch directories.
+       * Hope this doesn't bite us later.
+       */
+      directory_initiate_fetch(router_pick_directory_server());
+      time_to_fetch_directory = now.tv_sec + options.DirFetchPeriod;
+    }
+    *timeout = 1000*(time_to_fetch_directory - now.tv_sec) + (1000 - (now.tv_usec / 1000));
+  }
+
   if(need_to_refill_buckets) {
     if(now.tv_sec > current_second) { /* the second has already rolled over! */
 //      log(LOG_DEBUG,"prepare_for_poll(): The second has rolled over, immediately refilling.");
@@ -359,8 +347,8 @@
         connection_increment_receiver_bucket(connection_array[i]);
       current_second = now.tv_sec; /* remember which second it is, for next time */
     }
+    /* this timeout is definitely sooner than either of the above two */
     *timeout = 1000 - (now.tv_usec / 1000); /* how many milliseconds til the next second? */
-//    log(LOG_DEBUG,"prepare_for_poll(): %d milliseconds til next second.",*timeout);
   }
 
   if(options.LinkPadding) {
@@ -406,9 +394,7 @@
   int poll_result;
 
   /* load the routers file */
-  router_array = router_get_list_from_file(options.RouterFile,&rarray_len, options.ORPort);
-  if (!router_array)
-  {
+  if(router_get_list_from_file(options.RouterFile, options.ORPort) < 0) {
     log(LOG_ERR,"Error loading router list.");
     return -1;
   }
@@ -429,8 +415,8 @@
 
   /* start-up the necessary connections based on global_role. This is where we
    * try to connect to all the other ORs, and start the listeners */
-  retry_all_connections(options.Role, router_array, rarray_len, prkey, 
-		        options.ORPort, options.OPPort, options.APPort);
+  retry_all_connections(options.Role, prkey, options.ORPort,
+                        options.OPPort, options.APPort, options.DirPort);
 
   for(;;) {
     if(please_dumpstats) {
@@ -496,7 +482,7 @@
   int i;
   connection_t *conn;
   extern char *conn_type_to_string[];
-  extern char *conn_state_to_string[][10];
+  extern char *conn_state_to_string[][15];
 
   printf("Dumping stats:\n");
 
@@ -513,6 +499,53 @@
   }
 
   please_dumpstats = 0;
+}
+
+void dump_directory_to_string(char *s, int maxlen) {
+  int i;
+  connection_t *conn;
+  char *pkey;
+  int pkeylen;
+  int written;
+  routerinfo_t *router;
+
+  for(i=0;i<nfds;i++) {
+    conn = connection_array[i];
+
+    if(conn->type != CONN_TYPE_OR)
+      continue; /* we only want to list ORs */
+    router = router_get_by_addr_port(conn->addr,conn->port);
+    if(!router) {
+      log(LOG_ERR,"dump_directory_to_string(): couldn't find router %d:%d!",conn->addr,conn->port);
+      return;
+    }
+    if(crypto_pk_write_public_key_to_string(router->pkey,&pkey,&pkeylen)<0) {
+      log(LOG_ERR,"dump_directory_to_string(): write pkey to string failed!");
+      return;
+    }
+    written = snprintf(s, maxlen, "%s %d %d %d %d %d\n%s\n",
+      router->address,
+      router->or_port,
+      router->op_port,
+      router->ap_port,
+      router->dir_port,
+      router->bandwidth,
+      pkey);
+
+    free(pkey);
+
+    if(written < 0 || written > maxlen) { 
+      /* apparently different glibcs do different things on error.. so check both */
+      log(LOG_ERR,"dump_directory_to_string(): tried to exceed string length.");
+      s[maxlen-1] = 0; /* make sure it's null terminated */
+      return;
+    }
+  
+    maxlen -= written;
+    s += written;
+
+  }
+
 }
 
 int main(int argc, char *argv[]) {

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- or.h	24 Sep 2002 10:43:57 -0000	1.26
+++ or.h	26 Sep 2002 12:09:10 -0000	1.27
@@ -58,6 +58,8 @@
 #define ROLE_OR_CONNECT_ALL 2
 #define ROLE_OP_LISTEN 4
 #define ROLE_AP_LISTEN 8
+#define ROLE_DIR_LISTEN 16
+#define ROLE_DIR_SERVER 32
 
 #define ROLE_IS_OR(role) ((role & ROLE_OR_LISTEN) || (role & ROLE_OR_CONNECT_ALL) || (role & ROLE_OP_LISTEN))
 
@@ -68,6 +70,8 @@
 #define CONN_TYPE_EXIT 5
 #define CONN_TYPE_AP_LISTENER 6
 #define CONN_TYPE_AP 7
+#define CONN_TYPE_DIR_LISTENER 8
+#define CONN_TYPE_DIR 9
 
 #define LISTENER_STATE_READY 0
 
@@ -105,6 +109,12 @@
 #define AP_CONN_STATE_OR_WAIT 1
 #define AP_CONN_STATE_OPEN 2
 
+#define DIR_CONN_STATE_CONNECTING 0
+#define DIR_CONN_STATE_SENDING_COMMAND 1
+#define DIR_CONN_STATE_READING 2
+#define DIR_CONN_STATE_COMMAND_WAIT 3
+#define DIR_CONN_STATE_WRITING 4
+
 #define CIRCUIT_STATE_OPEN_WAIT 0 /* receiving/processing the onion */
 #define CIRCUIT_STATE_OR_WAIT 1 /* I'm at the beginning of the path, my firsthop is still connecting */
 #define CIRCUIT_STATE_OPEN 2 /* onion processed, ready to send data along the connection */
@@ -342,9 +352,12 @@
    int ORPort;
    int OPPort;
    int APPort;
+   int DirPort;
    int MaxConn;
    int TrafficShaping;
    int LinkPadding;
+   int DirRebuildPeriod;
+   int DirFetchPeriod;
    int Role;
    int loglevel;
 } or_options_t;
@@ -441,8 +454,8 @@
 int connection_handle_listener_read(connection_t *conn, int new_type, int new_state);
 
 /* start all connections that should be up but aren't */
-int retry_all_connections(int role, routerinfo_t **router_array, int rarray_len,
-		  crypto_pk_env_t *prkey, uint16_t or_port, uint16_t op_port, uint16_t ap_port);
+int retry_all_connections(int role, crypto_pk_env_t *prkey, uint16_t or_listenport, 
+  uint16_t op_listenport, uint16_t ap_listenport, uint16_t dir_listenport);
 connection_t *connection_connect_to_router_as_op(routerinfo_t *router, uint16_t local_or_port);
 
 int connection_read_to_buf(connection_t *conn);
@@ -548,6 +561,18 @@
 int connection_or_create_listener(crypto_pk_env_t *prkey, struct sockaddr_in *local);
 int connection_or_handle_listener_read(connection_t *conn);
 
+/********************************* directory.c ***************************/
+
+void directory_initiate_fetch(routerinfo_t *router);
+int directory_send_command(connection_t *conn);
+void directory_rebuild(void);
+int connection_dir_process_inbuf(connection_t *conn);
+int directory_handle_command(connection_t *conn);
+int directory_handle_reading(connection_t *conn);
+int connection_dir_finished_flushing(connection_t *conn);
+int connection_dir_create_listener(crypto_pk_env_t *prkey, struct sockaddr_in *local);
+int connection_dir_handle_listener_read(connection_t *conn);
+
 /********************************* main.c ***************************/
 
 int connection_add(connection_t *conn);
@@ -559,10 +584,6 @@
 
 connection_t *connection_get_by_type(int type);
 
-routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
-unsigned int *router_new_route(int *routelen);
-unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath);
-routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen);
 connection_t *connect_to_router_as_op(routerinfo_t *router);
 
 void connection_watch_events(connection_t *conn, short events);
@@ -582,6 +603,7 @@
 void catchint();
 void catchusr1();
 void dumpstats(void);
+void dump_directory_to_string(char *s, int maxlen);
 
 int main(int argc, char *argv[]);
 
@@ -625,6 +647,13 @@
 
 /********************************* routers.c ***************************/
 
-routerinfo_t **router_get_list_from_file(char *routerfile, int *len, uint16_t or_listenport);
+void router_retry_connections(crypto_pk_env_t *prkey, struct sockaddr_in *local);
+routerinfo_t *router_pick_directory_server(void);
+routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
+unsigned int *router_new_route(int *routelen);
+unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath);
+routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen);
+int router_get_list_from_file(char *routerfile, uint16_t or_listenport);
+int router_get_list_from_string(char *s, uint16_t or_listenport);
 
 #endif

Index: routers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routers.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- routers.c	24 Sep 2002 10:43:57 -0000	1.11
+++ routers.c	26 Sep 2002 12:09:10 -0000	1.12
@@ -13,7 +13,16 @@
 
 #include "or.h"
 
+/****************************************************************************/
+
+/* router array */
+static routerinfo_t **router_array = NULL;
+static int rarray_len = 0;
+
 extern int global_role; /* from main.c */
+extern or_options_t options; /* command-line and config-file options */
+
+/****************************************************************************/
 
 /* static function prototypes */
 static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport);
@@ -23,6 +32,67 @@
 static char *find_whitespace(char *s);
 static routerinfo_t *router_get_entry_from_string(char **s);
 
+/****************************************************************************/
+
+void router_retry_connections(crypto_pk_env_t *prkey, struct sockaddr_in *local) {
+  int i;
+  routerinfo_t *router;
+
+  for (i=0;i<rarray_len;i++) {
+    router = router_array[i];
+    if(!connection_exact_get_by_addr_port(router->addr,router->or_port)) { /* not in the list */
+      log(LOG_DEBUG,"retry_all_connections(): connecting to OR %s:%u.",router->address,router->or_port);
+      connection_or_connect_as_or(router, prkey, local);
+    }
+  }
+}
+
+routerinfo_t *router_pick_directory_server(void) {
+  /* currently, pick the first router with a positive dir_port */
+  int i;
+  routerinfo_t *router;
+  
+  if(!router_array)
+    return NULL;
+
+  for(i=0;i<rarray_len;i++) {
+    router = router_array[i];
+    if(router->dir_port > 0)
+      return router;
+  }
+
+  return NULL;
+}
+
+routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
+  int i;
+  routerinfo_t *router;
+
+  assert(router_array);
+
+  for(i=0;i<rarray_len;i++) {
+    router = router_array[i];
+    if ((router->addr == addr) && (router->or_port == port))
+      return router;
+  }
+
+  return NULL;
+}
+
+routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen) {
+  return router_array[route[routelen-1]];
+}
+
+/* a wrapper around new_route. put all these in routers.c perhaps? */
+unsigned int *router_new_route(int *routelen) {
+  return new_route(options.CoinWeight, router_array, rarray_len, routelen);
+}
+
+/* a wrapper around create_onion */
+unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath) {
+  return create_onion(router_array,rarray_len,route,routelen,len,cpath);
+}
+
 /* private function, to determine whether the current entry in the router list is actually us */
 static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport)
 {
@@ -58,8 +128,8 @@
     a = (struct in_addr *)addr;
 
     tmp1 = strdup(inet_ntoa(*a)); /* can't call inet_ntoa twice in the same
-				     printf, since it overwrites its static
-				     memory each time */
+                                     printf, since it overwrites its static
+                                     memory each time */
     log(LOG_DEBUG,"router_is_me(): Comparing '%s' to '%s'.",tmp1,
        inet_ntoa( *((struct in_addr *)&or_address) ) );
     free(tmp1);
@@ -151,64 +221,87 @@
 
 
 /* load the router list */
-routerinfo_t **router_get_list_from_file(char *routerfile, int *len, uint16_t or_listenport)
+int router_get_list_from_file(char *routerfile, uint16_t or_listenport)
 {
-  routerinfo_t *routerlist=NULL;
-  routerinfo_t *router;
   int fd; /* router file */
   struct stat statbuf;
   char *string;
-  char *tmps;
 
-  assert(routerfile && len);
+  assert(routerfile);
   
   if (strcspn(routerfile,CONFIG_LEGAL_FILENAME_CHARACTERS) != 0) {
     log(LOG_ERR,"router_get_list_from_file(): Filename %s contains illegal characters.",routerfile);
-    return NULL;
+    return -1;
   }
   
   if(stat(routerfile, &statbuf) < 0) {
     log(LOG_ERR,"router_get_list_from_file(): Could not stat %s.",routerfile);
-    return NULL;
+    return -1;
   }
 
   /* open the router list */
   fd = open(routerfile,O_RDONLY,0);
   if (fd<0) {
     log(LOG_ERR,"router_get_list_from_file(): Could not open %s.",routerfile);
-    return NULL;
+    return -1;
   }
 
   string = malloc(statbuf.st_size+1);
   if(!string) {
     log(LOG_ERR,"router_get_list_from_file(): Out of memory.");
-    return NULL;
+    return -1;
   }
 
   if(read(fd,string,statbuf.st_size) != statbuf.st_size) {
     log(LOG_ERR,"router_get_list_from_file(): Couldn't read all %d bytes of file '%s'.",statbuf.st_size,routerfile);
-    return NULL;
+    free(string);
+    close(fd);
+    return -1;
   }
   close(fd);
   
   string[statbuf.st_size] = 0; /* null terminate it */
-  tmps = string;
-  while(*tmps) { /* while not at the end of the string */
-    router = router_get_entry_from_string(&tmps);
+
+  if(router_get_list_from_string(string, or_listenport) < 0) {
+    log(LOG_ERR,"router_get_list_from_file(): The routerfile itself was corrupt.");
+    free(string);
+    return -1;
+  }
+
+  free(string);
+  return 0;
+} 
+
+int router_get_list_from_string(char *s, uint16_t or_listenport) {
+  routerinfo_t *routerlist=NULL;
+  routerinfo_t *router;
+  routerinfo_t **new_router_array;
+  int new_rarray_len;
+
+  assert(s);
+
+  while(*s) { /* while not at the end of the string */
+    router = router_get_entry_from_string(&s);
     if(router == NULL) {
       routerlist_free(routerlist);
-      free(string);
-      return NULL;
+      return -1;
     }
     if(!router_is_me(router->addr, router->or_port, or_listenport)) {
       router->next = routerlist;
       routerlist = router;
     }
-    tmps = eat_whitespace(tmps);
+    s = eat_whitespace(s);
   }
-  free(string);
-  return make_rarray(routerlist, len);
-} 
+ 
+  new_router_array = make_rarray(routerlist, &new_rarray_len);
+  if(new_router_array) { /* success! replace the old one */
+    rarray_free(router_array); /* free the old one first */
+    router_array = new_router_array;
+    rarray_len = new_rarray_len;
+    return 0;
+  }
+  return -1;
+}
 
 /* return the first char of s that is not whitespace and not a comment */
 static char *eat_whitespace(char *s) {
@@ -322,7 +415,7 @@
   next = strchr(next, '\n');
   assert(next); /* can't fail, we just checked it was here */
   *next = 0;
-  log(LOG_DEBUG,"Key about to be read is: '%s'",*s);
+//  log(LOG_DEBUG,"Key about to be read is: '%s'",*s);
   if((crypto_pk_read_public_key_from_string(router->pkey, *s, strlen(*s))<0)) {
     log(LOG_ERR,"router_get_entry_from_string(): Couldn't read pk from string");
     goto router_read_failed;