[or-cvs] Refactor buffers; implement descriptors.

Nick Mathewson nickm at seul.org
Thu Sep 25 05:17:14 UTC 2003


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv24061/src/or

Modified Files:
	buffers.c circuit.c config.c connection.c connection_edge.c 
	connection_or.c cpuworker.c directory.c dns.c main.c onion.c 
	or.h routers.c test.c 
Log Message:
Refactor buffers; implement descriptors.

'buf_t' is now an opaque type defined in buffers.c .

Router descriptors now include all keys; routers generate keys as 
needed on startup (in a newly defined "data directory"), and generate
their own descriptors.  Descriptors are now self-signed.

Implementation is not complete: descriptors are never published; and
upon receiving a descriptor, the directory doesn't do anything with
it.

At least "routers.or" and orkeygen are now obsolete, BTW.



Index: buffers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/buffers.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -d -r1.36 -r1.37
--- buffers.c	24 Sep 2003 21:24:52 -0000	1.36
+++ buffers.c	25 Sep 2003 05:17:10 -0000	1.37
@@ -8,50 +8,103 @@
 
 extern or_options_t options; /* command-line and config-file options */
 
-/* Create a new buf of size MAX_BUF_SIZE. Write a pointer to it
- * into *buf, write MAX_BUF_SIZE into *buflen, and initialize
- * *buf_datalen to 0. Return 0.
+struct buf_t {
+  char *buf;
+  size_t len;
+  size_t datalen;
+};
+
+#define BUF_OK(b) ((b) && (b)->buf && (b)->datalen <= (b)->len)
+
+/* Find the first instance of str on buf.  If none exists, return -1.
+ * Otherwise, return index of the first character in buf _after_ the
+ * first instance of str.
  */
-int buf_new(char **buf, int *buflen, int *buf_datalen) {
+static int find_str_in_str(const char *str, int str_len, 
+                           const char *buf, int buf_len)
+{
+  const char *location;
+  const char *last_possible = buf + buf_len - str_len;
 
-  assert(buf && buflen && buf_datalen);
+  assert(str && str_len > 0 && buf);
 
-  *buf = (char *)tor_malloc(MAX_BUF_SIZE);
-//  memset(*buf,0,MAX_BUF_SIZE);
-  *buflen = MAX_BUF_SIZE;
-  *buf_datalen = 0;
+  if(buf_len < str_len)
+    return -1;
 
-  return 0;
+  for(location = buf; location <= last_possible; location++)
+    if((*location == *str) && !memcmp(location+1, str+1, str_len-1))
+      return location-buf+str_len;
+
+  return -1;
 }
 
-void buf_free(char *buf) {
+/* Create and return a new buf of size 'size'
+ */
+buf_t *buf_new_with_capacity(size_t size) {
+  buf_t *buf;
+  buf = (buf_t*)tor_malloc(sizeof(buf_t));
+  buf->buf = (char *)tor_malloc(size);
+  buf->len = size;
+  buf->datalen = 0;
+//  memset(buf->buf,0,size);
+
+  assert(BUF_OK(buf));
+  return buf;
+}
+
+buf_t *buf_new()
+{
+  return buf_new_with_capacity(MAX_BUF_SIZE);
+}
+
+
+size_t buf_datalen(const buf_t *buf)
+{
+  return buf->datalen;
+}
+
+size_t buf_capacity(const buf_t *buf)
+{
+  return buf->len;
+}
+
+const char *_buf_peek_raw_buffer(const buf_t *buf)
+{
+  return buf->buf;
+}
+
+void buf_free(buf_t *buf) {
+  assert(buf && buf->buf);
+  free(buf->buf);
   free(buf);
 }
 
-/* read from socket s, writing onto buf+buf_datalen.
+
+
+/* read from socket s, writing onto end of buf.
  * read at most 'at_most' bytes, and in any case don't read more than will fit based on buflen.
  * If read() returns 0, set *reached_eof to 1 and return 0. If you want to tear
  * down the connection return -1, else return the number of bytes read.
  */
-int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, int *reached_eof) {
+int read_to_buf(int s, int at_most, buf_t *buf, int *reached_eof) {
 
   int read_result;
 #ifdef MS_WINDOWS
   int e;
 #endif
 
-  assert(buf && *buf && buflen && buf_datalen && reached_eof && (s>=0));
+  assert(BUF_OK(buf) && reached_eof && (s>=0));
 
   /* this is the point where you would grow the buffer, if you want to */
 
-  if(at_most > *buflen - *buf_datalen)
-    at_most = *buflen - *buf_datalen; /* take the min of the two */
+  if(at_most > buf->len - buf->datalen)
+    at_most = buf->len - buf->datalen; /* take the min of the two */
 
   if(at_most == 0)
     return 0; /* we shouldn't read anything */
 
 //  log_fn(LOG_DEBUG,"reading at most %d bytes.",at_most);
-  read_result = read(s, *buf+*buf_datalen, at_most);
+  read_result = read(s, buf->buf+buf->datalen, at_most);
   if (read_result < 0) {
     if(!ERRNO_EAGAIN(errno)) { /* it's a real error */
       return -1;
@@ -68,31 +121,33 @@
     *reached_eof = 1;
     return 0;
   } else { /* we read some bytes */
-    *buf_datalen += read_result;
-    log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",read_result, *buf_datalen);
+    buf->datalen += read_result;
+    log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",read_result,
+           (int)buf->datalen);
     return read_result;
   }
 }
 
-int read_to_buf_tls(tor_tls *tls, int at_most, char **buf, int *buflen, int *buf_datalen) {
+int read_to_buf_tls(tor_tls *tls, int at_most, buf_t *buf) {
   int r;
-  assert(tls && *buf && buflen && buf_datalen);
+  assert(tls && BUF_OK(buf));
   
-  if (at_most > *buflen - *buf_datalen)
-    at_most = *buflen - *buf_datalen;
+  if (at_most > buf->len - buf->datalen)
+    at_most = buf->len - buf->datalen;
 
   if (at_most == 0)
     return 0;
   
-  r = tor_tls_read(tls, *buf+*buf_datalen, at_most);
+  r = tor_tls_read(tls, buf->buf+buf->datalen, at_most);
   if (r<0) 
     return r;
-  *buf_datalen += r;
-  log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",r, *buf_datalen);
+  buf->datalen += r;
+  log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",r, (int)buf->datalen);
   return r;
 } 
 
-int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen) {
+int flush_buf(int s, buf_t *buf, int *buf_flushlen) 
+{
 
   /* push from buf onto s
    * then memmove to front of buf
@@ -103,14 +158,12 @@
   int e;
 #endif
 
-  assert(buf && *buf && buflen && buf_flushlen && buf_datalen && (s>=0) && (*buf_flushlen <= *buf_datalen));
+  assert(BUF_OK(buf) && buf_flushlen && (s>=0) && (*buf_flushlen <= buf->datalen));
 
   if(*buf_flushlen == 0) /* nothing to flush */
     return 0;
 
-  /* this is the point where you would grow the buffer, if you want to */
-
-  write_result = write(s, *buf, *buf_flushlen);
+  write_result = write(s, buf->buf, *buf_flushlen);
   if (write_result < 0) {
     if(!ERRNO_EAGAIN(errno)) { /* it's a real error */
       return -1;
@@ -124,72 +177,70 @@
     log_fn(LOG_DEBUG,"write() would block, returning.");
     return 0;
   } else {
-    *buf_datalen -= write_result;
+    buf->datalen -= write_result;
     *buf_flushlen -= write_result;
-    memmove(*buf, *buf+write_result, *buf_datalen);
+    memmove(buf->buf, buf->buf+write_result, buf->datalen);
     log_fn(LOG_DEBUG,"%d: flushed %d bytes, %d ready to flush, %d remain.",
-      s,write_result,*buf_flushlen,*buf_datalen);
+           s,write_result,*buf_flushlen,(int)buf->datalen);
     return *buf_flushlen;
     /* XXX USE_TLS should change to return write_result like any sane function would */
   }
 }
 
-int flush_buf_tls(tor_tls *tls, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen)
+int flush_buf_tls(tor_tls *tls, buf_t *buf, int *buf_flushlen) 
 {
   int r;
-  assert(tls && *buf && buflen && buf_datalen);
+  assert(tls && BUF_OK(buf) && buf_flushlen);
 
   /* we want to let tls write even if flushlen is zero, because it might
    * have a partial record pending */
-  r = tor_tls_write(tls, *buf, *buf_flushlen);
+  r = tor_tls_write(tls, buf->buf, *buf_flushlen);
   if (r < 0) {
     return r;
   }
-  *buf_datalen -= r;
+  buf->datalen -= r;
   *buf_flushlen -= r;
-  memmove(*buf, *buf+r, *buf_datalen);
+  memmove(buf->buf, buf->buf+r, buf->datalen);
   log_fn(LOG_DEBUG,"flushed %d bytes, %d ready to flush, %d remain.",
-    r,*buf_flushlen,*buf_datalen);
+    r,*buf_flushlen,(int)buf->datalen);
   return r;
 }
 
-int write_to_buf(char *string, int string_len,
-                 char **buf, int *buflen, int *buf_datalen) {
+int write_to_buf(char *string, int string_len, buf_t *buf) {
 
   /* append string to buf (growing as needed, return -1 if "too big")
    * return total number of bytes on the buf
    */
 
-  assert(string && buf && *buf && buflen && buf_datalen);
+  assert(string && BUF_OK(buf));
 
   /* this is the point where you would grow the buffer, if you want to */
 
-  if (string_len + *buf_datalen > *buflen) { /* we're out of luck */
+  if (string_len + buf->datalen > buf->len) { /* we're out of luck */
     log_fn(LOG_DEBUG, "buflen too small. Time to implement growing dynamic bufs.");
     return -1;
   }
 
-  memcpy(*buf+*buf_datalen, string, string_len);
-  *buf_datalen += string_len;
-  log_fn(LOG_DEBUG,"added %d bytes to buf (now %d total).",string_len, *buf_datalen);
-  return *buf_datalen;
+  memcpy(buf->buf+buf->datalen, string, string_len);
+  buf->datalen += string_len;
+  log_fn(LOG_DEBUG,"added %d bytes to buf (now %d total).",string_len, (int)buf->datalen);
+  return buf->datalen;
 }
 
-int fetch_from_buf(char *string, int string_len,
-                   char **buf, int *buflen, int *buf_datalen) {
+int fetch_from_buf(char *string, int string_len, buf_t *buf) {
 
   /* There must be string_len bytes in buf; write them onto string,
    * then memmove buf back (that is, remove them from buf).
    *
    * Return the number of bytes still on the buffer. */
 
-  assert(string && buf && *buf && buflen && buf_datalen);
-  assert(string_len <= *buf_datalen); /* make sure we don't ask for too much */
+  assert(string && BUF_OK(buf));
+  assert(string_len <= buf->datalen); /* make sure we don't ask for too much */
 
-  memcpy(string,*buf,string_len);
-  *buf_datalen -= string_len;
-  memmove(*buf, *buf+string_len, *buf_datalen);
-  return *buf_datalen;
+  memcpy(string,buf->buf,string_len);
+  buf->datalen -= string_len;
+  memmove(buf->buf, buf->buf+string_len, buf->datalen);
+  return buf->datalen;
 }
 
 /* There is a (possibly incomplete) http statement on *buf, of the
@@ -204,24 +255,24 @@
  * 
  * Else, change nothing and return 0.
  */
-int fetch_from_buf_http(char *buf, int *buf_datalen,
+int fetch_from_buf_http(buf_t *buf,
                         char *headers_out, int max_headerlen,
                         char *body_out, int max_bodylen) {
   char *headers, *body;
   int i;
   int headerlen, bodylen, contentlen;
 
-  assert(buf && buf_datalen);
+  assert(BUF_OK(buf));
 
-  headers = buf;
-  i = find_on_inbuf("\r\n\r\n", 4, buf, *buf_datalen);
+  headers = buf->buf;
+  i = find_on_inbuf("\r\n\r\n", 4, buf);
   if(i < 0) {
     log_fn(LOG_DEBUG,"headers not all here yet.");
     return 0;
   }
-  body = buf+i;
+  body = buf->buf+i;
   headerlen = body-headers; /* includes the CRLFCRLF */
-  bodylen = *buf_datalen - headerlen;
+  bodylen = buf->datalen - headerlen;
   log_fn(LOG_DEBUG,"headerlen %d, bodylen %d.",headerlen,bodylen);
 
   if(headers_out && max_headerlen <= headerlen) {
@@ -234,9 +285,11 @@
   }
 
 #define CONTENT_LENGTH "\r\nContent-Length: "
-  i = find_on_inbuf(CONTENT_LENGTH, strlen(CONTENT_LENGTH), headers, headerlen);
+  i = find_str_in_str(CONTENT_LENGTH, sizeof(CONTENT_LENGTH), 
+                      headers, headerlen);
   if(i > 0) {
     contentlen = atoi(headers+i);
+    /* XXX What if content-length is malformed? */
     if(bodylen < contentlen) {
       log_fn(LOG_DEBUG,"body not all here yet.");
       return 0; /* not all there yet */
@@ -246,15 +299,15 @@
   }
   /* all happy. copy into the appropriate places, and return 1 */
   if(headers_out) {
-    memcpy(headers_out,buf,headerlen);
+    memcpy(headers_out,buf->buf,headerlen);
     headers_out[headerlen] = 0; /* null terminate it */
   }
   if(body_out) {
-    memcpy(body_out,buf+headerlen,bodylen);
+    memcpy(body_out,buf->buf+headerlen,bodylen);
     body_out[bodylen] = 0; /* null terminate it */
   }
-  *buf_datalen -= (headerlen+bodylen);
-  memmove(buf, buf+headerlen+bodylen, *buf_datalen);
+  buf->datalen -= (headerlen+bodylen);
+  memmove(buf, buf->buf+headerlen+bodylen, buf->datalen);
 
   return 1;
 }
@@ -269,7 +322,7 @@
  * If it's invalid or too big, return -1.
  * Else it's not all there yet, change nothing and return 0.
  */
-int fetch_from_buf_socks(char *buf, int *buf_datalen,
+int fetch_from_buf_socks(buf_t *buf,
                          char *addr_out, int max_addrlen,
                          uint16_t *port_out) {
   socks4_t socks4_info;
@@ -278,14 +331,14 @@
   enum {socks4, socks4a } socks_prot = socks4a;
   char *next, *startaddr;
 
-  if(*buf_datalen < sizeof(socks4_t)) /* basic info available? */
+  if(buf->datalen < sizeof(socks4_t)) /* basic info available? */
     return 0; /* not yet */
 
   /* an inlined socks4_unpack() */
-  socks4_info.version = *buf;
-  socks4_info.command = *(buf+1);
-  socks4_info.destport = ntohs(*(uint16_t*)(buf+2));
-  socks4_info.destip = ntohl(*(uint32_t*)(buf+4));
+  socks4_info.version = (unsigned char) *(buf->buf);
+  socks4_info.command = (unsigned char) *(buf->buf+1);
+  socks4_info.destport = ntohs(*(uint16_t*)(buf->buf+2));
+  socks4_info.destip = ntohl(*(uint32_t*)(buf->buf+4));
 
   if(socks4_info.version != 4) {
     log_fn(LOG_NOTICE,"Unrecognized version %d.",socks4_info.version);
@@ -321,7 +374,7 @@
     socks_prot = socks4;
   }
 
-  next = memchr(buf+SOCKS4_NETWORK_LEN, 0, *buf_datalen);
+  next = memchr(buf->buf+SOCKS4_NETWORK_LEN, 0, buf->datalen);
   if(!next) {
     log_fn(LOG_DEBUG,"Username not here yet.");
     return 0;
@@ -329,7 +382,7 @@
 
   startaddr = next+1;
   if(socks_prot == socks4a) {
-    next = memchr(startaddr, 0, buf+*buf_datalen-startaddr);
+    next = memchr(startaddr, 0, buf->buf+buf->datalen-startaddr);
     if(!next) {
       log_fn(LOG_DEBUG,"Destaddr not here yet.");
       return 0;
@@ -342,32 +395,19 @@
   log_fn(LOG_DEBUG,"Everything is here. Success.");
   *port_out = port; 
   strcpy(addr_out, socks_prot == socks4 ? tmpbuf : startaddr);
-  *buf_datalen -= (next-buf+1); /* next points to the final \0 on inbuf */
-  memmove(buf, next+1, *buf_datalen);
+  buf->datalen -= (next-buf->buf+1); /* next points to the final \0 on inbuf */
+  memmove(buf->buf, next+1, buf->datalen);
 //  log_fn(LOG_DEBUG,"buf_datalen is now %d:'%s'",*buf_datalen,buf);
   return 1;
 }
 
-int find_on_inbuf(char *string, int string_len,
-                  char *buf, int buf_datalen) {
+int find_on_inbuf(char *string, int string_len, buf_t *buf) {
   /* find first instance of needle 'string' on haystack 'buf'. return how
    * many bytes from the beginning of buf to the end of string.
    * If it's not there, return -1.
    */
 
-  char *location;
-  char *last_possible = buf + buf_datalen - string_len;
-
-  assert(string && string_len > 0 && buf);
-
-  if(buf_datalen < string_len)
-    return -1;
-
-  for(location = buf; location <= last_possible; location++)
-    if((*location == *string) && !memcmp(location+1, string+1, string_len-1))
-      return location-buf+string_len;
-
-  return -1;
+  return find_str_in_str(string, string_len, buf->buf, buf->datalen);
 }
 
 /*

Index: circuit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuit.c,v
retrieving revision 1.67
retrieving revision 1.68
diff -u -d -r1.67 -r1.68
--- circuit.c	24 Sep 2003 21:24:52 -0000	1.67
+++ circuit.c	25 Sep 2003 05:17:10 -0000	1.68
@@ -751,7 +751,7 @@
     cell.aci = circ->n_aci;
     cell.length = DH_ONIONSKIN_LEN;
 
-    if(onion_skin_create(circ->n_conn->pkey, &(circ->cpath->handshake_state), cell.payload) < 0) {
+    if(onion_skin_create(circ->n_conn->onion_pkey, &(circ->cpath->handshake_state), cell.payload) < 0) {
       log_fn(LOG_INFO,"onion_skin_create (first hop) failed.");
       return -1;
     }
@@ -791,7 +791,7 @@
     cell.length = RELAY_HEADER_SIZE + 6 + DH_ONIONSKIN_LEN;
     *(uint32_t*)(cell.payload+RELAY_HEADER_SIZE) = htonl(hop->addr);
     *(uint16_t*)(cell.payload+RELAY_HEADER_SIZE+4) = htons(hop->port);
-    if(onion_skin_create(router->pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) {
+    if(onion_skin_create(router->onion_pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) {
       log_fn(LOG_INFO,"onion_skin_create failed.");
       return -1;
     }

Index: config.c
===================================================================
RCS file: /home/or/cvsroot/src/or/config.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- config.c	24 Sep 2003 21:24:52 -0000	1.43
+++ config.c	25 Sep 2003 05:17:10 -0000	1.44
@@ -189,10 +189,8 @@
 
     /* string options */
     config_compare(list, "LogLevel",       CONFIG_TYPE_STRING, &options->LogLevel) ||
-    config_compare(list, "PrivateKeyFile", CONFIG_TYPE_STRING, &options->PrivateKeyFile) ||
-    config_compare(list, "SigningPrivateKeyFile", CONFIG_TYPE_STRING, &options->SigningPrivateKeyFile) ||
+    config_compare(list, "DataDirectory",  CONFIG_TYPE_STRING, &options->DataDirectory) ||
     config_compare(list, "RouterFile",     CONFIG_TYPE_STRING, &options->RouterFile) ||
-    config_compare(list, "CertFile",       CONFIG_TYPE_STRING, &options->CertFile) ||
     config_compare(list, "Nickname",       CONFIG_TYPE_STRING, &options->Nickname) ||
 
     /* int options */
@@ -238,6 +236,7 @@
   memset(options,0,sizeof(or_options_t));
   options->LogLevel = "debug";
   options->loglevel = LOG_DEBUG;
+  options->DataDirectory = NULL;
   options->CoinWeight = 0.8;
   options->MaxConn = 900;
   options->DirFetchPeriod = 600;
@@ -246,7 +245,6 @@
   options->NewCircuitPeriod = 60; /* once a minute */
   options->TotalBandwidth = 800000; /* at most 800kB/s total sustained incoming */
   options->NumCpus = 1;
-  options->CertFile = "default.cert";
 
 /* learn config file name, get config lines, assign them */
   i = 1;
@@ -316,18 +314,13 @@
     result = -1;
   }
 
-  if(options->OnionRouter && options->PrivateKeyFile == NULL) {
-    log(LOG_ERR,"PrivateKeyFile option required for OnionRouter, but not found.");
+  if(options->OnionRouter && options->DataDirectory == NULL) {
+    log(LOG_ERR,"DataDirectory option required for OnionRouter, but not found.");
     result = -1;
   }
 
   if(options->OnionRouter && options->Nickname == NULL) {
     log_fn(LOG_ERR,"Nickname required for OnionRouter, but not found.");
-    result = -1;
-  }
-
-  if(options->DirPort > 0 && options->SigningPrivateKeyFile == NULL) {
-    log(LOG_ERR,"SigningPrivateKeyFile option required for DirServer, but not found.");
     result = -1;
   }
 

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.101
retrieving revision 1.102
diff -u -d -r1.101 -r1.102
--- connection.c	24 Sep 2003 21:24:52 -0000	1.101
+++ connection.c	25 Sep 2003 05:17:10 -0000	1.102
@@ -80,8 +80,8 @@
   memset(conn,0,sizeof(connection_t)); /* zero it out to start */
 
   conn->type = type;
-  if(buf_new(&conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen) < 0 ||
-     buf_new(&conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen) < 0)
+  if(!(conn->inbuf = buf_new()) ||
+     !(conn->outbuf = buf_new())) 
     return NULL;
 
   conn->receiver_bucket = 50000; /* should be enough to do the handshake */
@@ -108,8 +108,12 @@
       tor_tls_free(conn->tls);
   }
 
-  if (conn->pkey)
-    crypto_free_pk_env(conn->pkey);
+  if (conn->onion_pkey)
+    crypto_free_pk_env(conn->onion_pkey);
+  if (conn->link_pkey)
+    crypto_free_pk_env(conn->link_pkey);
+  if (conn->identity_pkey)
+    crypto_free_pk_env(conn->identity_pkey);
 
   if(conn->s > 0) {
     log_fn(LOG_INFO,"closing fd %d.",conn->s);
@@ -287,14 +291,14 @@
         log_fn(LOG_INFO,"Other side has a cert but it's bad. Closing.");
         return -1;
       }
-      router = router_get_by_pk(pk);
+      router = router_get_by_link_pk(pk);
       if (!router) {
         log_fn(LOG_INFO,"Unrecognized public key from peer. Closing.");
         crypto_free_pk_env(pk);
         return -1;
       }
-      if(conn->pkey) { /* I initiated this connection. */
-        if(crypto_pk_cmp_keys(conn->pkey, pk)) {
+      if(conn->link_pkey) { /* I initiated this connection. */
+        if(crypto_pk_cmp_keys(conn->link_pkey, pk)) {
           log_fn(LOG_INFO,"We connected to '%s' but he gave us a different key. Closing.", router->nickname);
           crypto_free_pk_env(pk);
           return -1;
@@ -306,7 +310,7 @@
           log_fn(LOG_INFO,"That router is already connected. Dropping.");
           return -1;
         }
-        conn->pkey = pk;
+        conn->link_pkey = pk;
         conn->bandwidth = router->bandwidth;
         conn->addr = router->addr, conn->port = router->or_port;
         if(conn->address)
@@ -326,13 +330,13 @@
       log_fn(LOG_INFO,"Other side has a cert but it's bad. Closing.");
       return -1;
     }
-    router = router_get_by_pk(pk);
+    router = router_get_by_link_pk(pk);
     if (!router) {
       log_fn(LOG_INFO,"Unrecognized public key from peer. Closing.");
       crypto_free_pk_env(pk);
       return -1;
     }
-    if(crypto_pk_cmp_keys(conn->pkey, pk)) {
+    if(crypto_pk_cmp_keys(conn->link_pkey, pk)) {
       log_fn(LOG_INFO,"We connected to '%s' but he gave us a different key. Closing.", router->nickname);
       crypto_free_pk_env(pk);
       return -1;
@@ -494,8 +498,7 @@
       return connection_tls_continue_handshake(conn);
 
     /* else open, or closing */
-    result = read_to_buf_tls(conn->tls, at_most, &conn->inbuf,
-                             &conn->inbuflen, &conn->inbuf_datalen);
+    result = read_to_buf_tls(conn->tls, at_most, conn->inbuf);
 
     switch(result) {
       case TOR_TLS_ERROR:
@@ -510,8 +513,9 @@
         return 0;
     }
   } else {
-    result = read_to_buf(conn->s, at_most, &conn->inbuf, &conn->inbuflen,
-                         &conn->inbuf_datalen, &conn->inbuf_reached_eof);
+    result = read_to_buf(conn->s, at_most, conn->inbuf,
+                         &conn->inbuf_reached_eof);
+
 //  log(LOG_DEBUG,"connection_read_to_buf(): read_to_buf returned %d.",read_result);
 
     if(result < 0)
@@ -534,11 +538,11 @@
 }
 
 int connection_fetch_from_buf(char *string, int len, connection_t *conn) {
-  return fetch_from_buf(string, len, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen);
+  return fetch_from_buf(string, len, conn->inbuf);
 }
 
 int connection_find_on_inbuf(char *string, int len, connection_t *conn) {
-  return find_on_inbuf(string, len, conn->inbuf, conn->inbuf_datalen);
+  return find_on_inbuf(string, len, conn->inbuf);
 }
 
 int connection_wants_to_flush(connection_t *conn) {
@@ -550,8 +554,7 @@
 }
 
 int connection_flush_buf(connection_t *conn) {
-  return flush_buf(conn->s, &conn->outbuf, &conn->outbuflen,
-                   &conn->outbuf_flushlen, &conn->outbuf_datalen);
+  return flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen);
 }
 
 /* return -1 if you want to break the conn, else return 0 */
@@ -573,8 +576,7 @@
     }
 
     /* else open, or closing */
-    switch(flush_buf_tls(conn->tls, &conn->outbuf, &conn->outbuflen,
-                         &conn->outbuf_flushlen, &conn->outbuf_datalen)) {
+    switch(flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen)) {
       case TOR_TLS_ERROR:
       case TOR_TLS_CLOSE:
         log_fn(LOG_DEBUG,"tls error. breaking.");
@@ -601,8 +603,7 @@
        */  
     }
   } else {
-    if(flush_buf(conn->s, &conn->outbuf, &conn->outbuflen,
-                 &conn->outbuf_flushlen, &conn->outbuf_datalen) < 0)
+    if(flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen) < 0)
       return -1;
       /* conns in CONNECTING state will fall through... */
   }
@@ -631,7 +632,7 @@
     conn->outbuf_flushlen += len;
   }
 
-  return write_to_buf(string, len, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen);
+  return write_to_buf(string, len, conn->outbuf);
 }
 
 int connection_receiver_bucket_should_increase(connection_t *conn) {
@@ -741,29 +742,25 @@
   
   /* buffers */
   assert(conn->inbuf);
-  assert(conn->inbuflen >= conn->inbuf_datalen);
-  assert(conn->inbuflen >= 0);
-  assert(conn->inbuf_datalen >= 0);
   assert(conn->outbuf);
-  assert(conn->outbuflen >= conn->outbuf_datalen);
-  assert(conn->outbuflen >= 0);
-  assert(conn->outbuf_datalen >= 0);
 
   assert(!now || conn->timestamp_lastread <= now);
   assert(!now || conn->timestamp_lastwritten <= now);
   assert(conn->timestamp_created <= conn->timestamp_lastread);
   assert(conn->timestamp_created <= conn->timestamp_lastwritten);
   
+  /* XXX Fix this; no longer so.*/
+#if 0
   if(conn->type != CONN_TYPE_OR && conn->type != CONN_TYPE_DIR)
     assert(!conn->pkey);
   /* pkey is set if we're a dir client, or if we're an OR in state OPEN
    * connected to another OR.
    */
+#endif
 
   if (conn->type != CONN_TYPE_OR) {
     assert(conn->bandwidth == -1);
     assert(conn->receiver_bucket == -1);
-    /* Addr, port, address XXX */
     assert(!conn->tls);
   } else {
     assert(conn->bandwidth);

Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_edge.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- connection_edge.c	21 Sep 2003 06:15:43 -0000	1.24
+++ connection_edge.c	25 Sep 2003 05:17:10 -0000	1.25
@@ -336,7 +336,7 @@
     return 0;
   }
  
-  amount_to_process = conn->inbuf_datalen;
+  amount_to_process = buf_datalen(conn->inbuf);
  
   if(!amount_to_process)
     return 0;
@@ -352,7 +352,8 @@
  
   connection_fetch_from_buf(cell.payload+RELAY_HEADER_SIZE, cell.length, conn);
  
-  log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).",conn->s,cell.length, conn->inbuf_datalen);
+  log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).",conn->s,cell.length,
+         (int)buf_datalen(conn->inbuf));
  
   cell.command = CELL_RELAY;
   SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_DATA);
@@ -440,7 +441,7 @@
 
   log_fn(LOG_DEBUG,"entered.");
 
-  switch(fetch_from_buf_socks(conn->inbuf,&conn->inbuf_datalen,
+  switch(fetch_from_buf_socks(conn->inbuf,
                               destaddr, sizeof(destaddr), &destport)) {
     case -1:
       log_fn(LOG_DEBUG,"Fetching socks handshake failed. Closing.");

Index: connection_or.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_or.c,v
retrieving revision 1.52
retrieving revision 1.53
diff -u -d -r1.52 -r1.53
--- connection_or.c	24 Sep 2003 21:24:52 -0000	1.52
+++ connection_or.c	25 Sep 2003 05:17:10 -0000	1.53
@@ -99,7 +99,8 @@
   conn->addr = router->addr;
   conn->port = router->or_port;
   conn->bandwidth = router->bandwidth;
-  conn->pkey = crypto_pk_dup_key(router->pkey);
+  conn->onion_pkey = crypto_pk_dup_key(router->onion_pkey);
+  conn->link_pkey = crypto_pk_dup_key(router->link_pkey);
   conn->address = strdup(router->address);
 
   if(connection_add(conn) < 0) { /* no space, forget it */
@@ -148,9 +149,9 @@
 int connection_process_cell_from_inbuf(connection_t *conn) {
   char buf[CELL_NETWORK_SIZE];
   cell_t cell;
- 
-  log_fn(LOG_DEBUG,"%d: starting, inbuf_datalen %d.",conn->s,conn->inbuf_datalen);
-  if(conn->inbuf_datalen < CELL_NETWORK_SIZE) /* entire response available? */
+
+  log_fn(LOG_DEBUG,"%d: starting, inbuf_datalen %d.",conn->s,buf_datalen(conn->inbuf));
+  if(buf_datalen(conn->inbuf) < CELL_NETWORK_SIZE) /* entire response available? */
     return 0; /* not yet */
  
   connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, conn);

Index: cpuworker.c
===================================================================
RCS file: /home/or/cvsroot/src/or/cpuworker.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- cpuworker.c	16 Sep 2003 01:58:46 -0000	1.5
+++ cpuworker.c	25 Sep 2003 05:17:11 -0000	1.6
@@ -73,9 +73,9 @@
   }
 
   if(conn->state == CPUWORKER_STATE_BUSY_ONION) {
-    if(conn->inbuf_datalen < LEN_ONION_RESPONSE) /* entire answer available? */
+    if(buf_datalen(conn->inbuf) < LEN_ONION_RESPONSE) /* entire answer available? */
       return 0; /* not yet */
-    assert(conn->inbuf_datalen == LEN_ONION_RESPONSE);
+    assert(buf_datalen(conn->inbuf) == LEN_ONION_RESPONSE);
 
     connection_fetch_from_buf(buf,LEN_ONION_RESPONSE,conn);
 
@@ -147,7 +147,7 @@
     }
 
     if(question_type == CPUWORKER_TASK_ONION) {
-      if(onion_skin_server_handshake(question, get_privatekey(),
+      if(onion_skin_server_handshake(question, get_onion_key(),
         reply_to_proxy, keys, 32) < 0) {
         /* failure */
         log_fn(LOG_ERR,"onion_skin_server_handshake failed.");

Index: directory.c
===================================================================
RCS file: /home/or/cvsroot/src/or/directory.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- directory.c	22 Sep 2003 06:22:00 -0000	1.30
+++ directory.c	25 Sep 2003 05:17:11 -0000	1.31
@@ -53,11 +53,11 @@
   conn->address = strdup(router->address);
   conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */
   conn->bandwidth = -1;
-  if (router->signing_pkey)
-    conn->pkey = crypto_pk_dup_key(router->signing_pkey);
+  if (router->identity_pkey)
+    conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
   else {
     log_fn(LOG_ERR, "No signing key known for dirserver %s; signature won't be checked", conn->address);
-    conn->pkey = NULL;
+    conn->identity_pkey = NULL;
   }
 
   if(connection_add(conn) < 0) { /* no space, forget it */
@@ -124,7 +124,7 @@
 static void directory_rebuild(void) {
   if(directory_dirty) {
     if (dump_signed_directory_to_string(the_directory, MAX_DIR_SIZE,
-                                        get_signing_privatekey())) {
+                                        get_identity_key())) {
       log(LOG_ERR, "Error writing directory");
       return;
     }
@@ -144,7 +144,7 @@
     switch(conn->state) {
       case DIR_CONN_STATE_CLIENT_READING_FETCH:
         /* kill it, but first process the_directory and learn about new routers. */
-        switch(fetch_from_buf_http(conn->inbuf,&conn->inbuf_datalen,
+        switch(fetch_from_buf_http(conn->inbuf,
                                    NULL, 0, the_directory, MAX_DIR_SIZE)) {
           case -1: /* overflow */
             log_fn(LOG_DEBUG,"'fetch' response too large. Failing.");
@@ -161,11 +161,11 @@
           log_fn(LOG_DEBUG,"Empty directory. Ignoring.");
           return -1;
         }
-        if(router_get_dir_from_string(the_directory, conn->pkey) < 0) {
+        if(router_get_dir_from_string(the_directory, conn->identity_pkey) < 0){
           log_fn(LOG_DEBUG,"...but parsing failed. Ignoring.");
         } else {
           log_fn(LOG_DEBUG,"and got an %s directory; updated routers.", 
-              conn->pkey ? "authenticated" : "unauthenticated");
+              conn->identity_pkey ? "authenticated" : "unauthenticated");
         }
         if(options.OnionRouter) { /* connect to them all */
           router_retry_connections();
@@ -196,7 +196,7 @@
 
   assert(conn && conn->type == CONN_TYPE_DIR);
 
-  switch(fetch_from_buf_http(conn->inbuf,&conn->inbuf_datalen,
+  switch(fetch_from_buf_http(conn->inbuf,
                              headers, sizeof(headers), body, sizeof(body))) {
     case -1: /* overflow */
       log_fn(LOG_DEBUG,"input too large. Failing.");

Index: dns.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dns.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- dns.c	16 Sep 2003 01:58:46 -0000	1.25
+++ dns.c	25 Sep 2003 05:17:11 -0000	1.26
@@ -309,9 +309,9 @@
   }
 
   assert(conn->state == DNSWORKER_STATE_BUSY);
-  if(conn->inbuf_datalen < 4) /* entire answer available? */
+  if(buf_datalen(conn->inbuf) < 4) /* entire answer available? */
     return 0; /* not yet */
-  assert(conn->inbuf_datalen == 4);
+  assert(buf_datalen(conn->inbuf) == 4);
 
   connection_fetch_from_buf((char*)&answer,sizeof(answer),conn);
 

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.100
retrieving revision 1.101
diff -u -d -r1.100 -r1.101
--- main.c	24 Sep 2003 21:24:52 -0000	1.100
+++ main.c	25 Sep 2003 05:17:11 -0000	1.101
@@ -7,6 +7,7 @@
 /********* START PROTOTYPES **********/
 
 static void dumpstats(void); /* dump stats to stdout */
+static int init_descriptor(void);
 
 /********* START VARIABLES **********/
 
@@ -29,30 +30,42 @@
 static int please_reap_children=0; /* whether we should waitpid for exited children*/
 #endif /* signal stuff */
 
-/* private key */
-static crypto_pk_env_t *privatekey=NULL;
-static crypto_pk_env_t *signing_privatekey=NULL;
+/* private keys */
+static crypto_pk_env_t *onionkey=NULL;
+static crypto_pk_env_t *linkkey=NULL;
+static crypto_pk_env_t *identitykey=NULL;
 
 routerinfo_t *my_routerinfo=NULL;
 
 /********* END VARIABLES ************/
 
-void set_privatekey(crypto_pk_env_t *k) {
-  privatekey = k;
+void set_onion_key(crypto_pk_env_t *k) {
+  onionkey = k;
 }
 
-crypto_pk_env_t *get_privatekey(void) {
-  assert(privatekey);
-  return privatekey;
+crypto_pk_env_t *get_onion_key(void) {
+  assert(onionkey);
+  return onionkey;
 }
 
-void set_signing_privatekey(crypto_pk_env_t *k) {
-  signing_privatekey = k;
+void set_link_key(crypto_pk_env_t *k)
+{
+  linkkey = k;
 }
 
-crypto_pk_env_t *get_signing_privatekey(void) {
-  assert(signing_privatekey);
-  return signing_privatekey;
+crypto_pk_env_t *get_link_key(void)
+{
+  assert(linkkey);
+  return linkkey;
+}
+
+void set_identity_key(crypto_pk_env_t *k) {
+  identitykey = k;
+}
+
+crypto_pk_env_t *get_identity_key(void) {
+  assert(identitykey);
+  return identitykey;
 }
 
 /****************************************************************************
@@ -69,7 +82,7 @@
     log(LOG_INFO,"connection_add(): failing because nfds is too high.");
     return -1;
   }
-
+  
   conn->poll_index = nfds;
   connection_set_poll_socket(conn);
   connection_array[nfds] = conn;
@@ -146,7 +159,7 @@
     assert(conn);
     if(connection_state_is_open(conn) &&
        !conn->marked_for_close &&
-       !crypto_pk_cmp_keys(conn->pkey, router->pkey)) {
+       !crypto_pk_cmp_keys(conn->onion_pkey, router->onion_pkey)) {
       log(LOG_INFO,"connection_twin_get_by_addr_port(): Found twin (%s).",conn->address);
       return conn;
     }
@@ -308,13 +321,11 @@
     if(conn->s >= 0) { /* might be an incomplete edge connection */
       /* FIXME there's got to be a better way to check for this -- and make other checks? */
       if(connection_speaks_cells(conn) && conn->state != OR_CONN_STATE_CONNECTING)
-        flush_buf_tls(conn->tls, &conn->outbuf, &conn->outbuflen,
-                      &conn->outbuf_flushlen, &conn->outbuf_datalen);
+        flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen);
       else
-        flush_buf(conn->s, &conn->outbuf, &conn->outbuflen,
-                  &conn->outbuf_flushlen, &conn->outbuf_datalen);
+        flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen);
       if(connection_wants_to_flush(conn)) /* not done flushing */
-        log_fn(LOG_WARNING,"Conn (socket %d) still wants to flush. Losing %d bytes!",conn->s, conn->inbuf_datalen);
+        log_fn(LOG_WARNING,"Conn (socket %d) still wants to flush. Losing %d bytes!",conn->s, (int)buf_datalen(conn->inbuf));
     }
     connection_remove(conn);
     connection_free(conn);
@@ -420,68 +431,218 @@
   return (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */
 }
 
-static int do_main_loop(void) {
-  int i;
-  int timeout;
-  int poll_result;
-  crypto_pk_env_t *prkey;
+#define FN_ERROR -1
+#define FN_NOENT 0
+#define FN_FILE 1
+#define FN_DIR 2
+static int fn_exists(const char *fname)
+{
+  struct stat st;
+  if (stat(fname, &st)) {
+    if (errno == ENOENT) {
+      return FN_NOENT;
+    }
+    return FN_ERROR;
+  }
+  if (st.st_mode & S_IFDIR) 
+    return FN_DIR;
+  else
+    return FN_FILE;
+}
 
-  /* load the routers file */
-  if(router_get_list_from_file(options.RouterFile) < 0) {
-    log(LOG_ERR,"Error loading router list.");
-    return -1;
+static crypto_pk_env_t *init_key_from_file(const char *fname)
+{
+  crypto_pk_env_t *prkey = NULL;
+  int fd = -1;
+  FILE *file = NULL;
+
+  if (!(prkey = crypto_new_pk_env(CRYPTO_PK_RSA))) {
+    log(LOG_ERR, "Error creating crypto environment.");
+    goto error;
   }
 
-  /* load the private key, if we're supposed to have one */
-  if(options.OnionRouter) {
-    prkey = crypto_new_pk_env(CRYPTO_PK_RSA);
-    if (!prkey) {
-      log(LOG_ERR,"Error creating a crypto environment.");
-      return -1;
+  switch(fn_exists(fname)) {
+  case FN_DIR:
+  case FN_ERROR:
+    log(LOG_ERR, "Can't read key from %s", fname);
+    goto error;
+  case FN_NOENT:
+    log(LOG_INFO, "No key found in %s; generating fresh key.", fname);
+    if (crypto_pk_generate_key(prkey)) {
+      log(LOG_ERR, "Error generating key: %s", crypto_perror());
+      goto error;
     }
-    if (crypto_pk_read_private_key_from_filename(prkey, options.PrivateKeyFile)) {
-      log(LOG_ERR,"Error loading private key.");
-      return -1;
+    if (crypto_pk_check_key(prkey) <= 0) {
+      log(LOG_ERR, "Generated key seems invalid");
+      goto error;
     }
-    set_privatekey(prkey);
-    cpu_init(); /* launch cpuworkers. Need to do this *after* we've read the private key. */
-  }
-
-  /* load the directory private key, if we're supposed to have one */
-  if(options.DirPort) {
-    prkey = crypto_new_pk_env(CRYPTO_PK_RSA);
-    if (!prkey) {
-      log(LOG_ERR,"Error creating a crypto environment.");
-      return -1;
+    log(LOG_INFO, "Generated key seems valid");
+    fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0400);
+    if (fd == -1) {
+      log(LOG_ERR, "Can't open %s for writing", fname);
+      goto error;
     }
-    if (crypto_pk_read_private_key_from_filename(prkey, options.SigningPrivateKeyFile)) {
-      log(LOG_ERR,"Error loading private key.");
-      return -1;
+    file = fdopen(fd, "w");
+    if (!file) {
+      log(LOG_ERR, "Can't fdopen %s for writing", fname);
+      goto error;
     }
-    set_signing_privatekey(prkey);
+    if (crypto_pk_write_private_key_to_file(prkey, file) < 0) {
+      log(LOG_ERR, "Can't write private key to %s", fname);
+      goto error;
+    }
+    fclose(file);
+    /* XXX fingerprint */
+    return prkey;
+  case FN_FILE:
+    if (crypto_pk_read_private_key_from_filename(prkey, fname)) {
+      log(LOG_ERR, "Error loading private key.");
+      goto error;
+    }
+    return prkey;
+  default: 
+    assert(0);
   }
 
-  if(options.OnionRouter) {
-    struct stat statbuf;
-    if(stat(options.CertFile, &statbuf) < 0) {
-      log_fn(LOG_INFO,"CertFile %s is missing. Generating.", options.CertFile);
-      if(tor_tls_write_certificate(options.CertFile,
-                                   get_privatekey(),
-                                   options.Nickname) < 0) {
-        log_fn(LOG_ERR,"Couldn't write CertFile %s. Dying.", options.CertFile);
-        return -1;
-      }
-    }
+ error:
+  if (prkey)
+    crypto_free_pk_env(prkey);
+  if (fd >= 0 && !file)
+    close(fd);
+  if (file)
+    fclose(file);
+  return NULL;
+}
 
-    if(tor_tls_context_new(options.CertFile, get_privatekey(), 1) < 0) {
-      log_fn(LOG_ERR,"Error creating tls context.");
+static int init_keys(void)
+{
+  char keydir[512];
+  char fingerprint[FINGERPRINT_LEN+1];
+  char *cp;
+  crypto_pk_env_t *prkey;
+  FILE *file;
+
+  /* OP's don't need keys.  Just initialize the TLS context.*/
+  if (!options.OnionRouter && !options.DirPort) {
+    if (tor_tls_context_new(NULL, 0, NULL)<0) {
+      log_fn(LOG_ERR, "Error creating TLS context for OP.");
       return -1;
     }
-  } else { /* just a proxy, the context is easy */
-    if(tor_tls_context_new(NULL, NULL, 0) < 0) {
-      log_fn(LOG_ERR,"Error creating tls context.");
+    return 0;
+  }
+  assert(options.DataDirectory);
+  if (strlen(options.DataDirectory) > (512-128)) {
+    log_fn(LOG_ERR, "DataDirectory is too long.");
+    return -1;
+  }
+  strcpy(keydir, options.DataDirectory);
+  switch (fn_exists(keydir)) {
+  case FN_NOENT:
+    log_fn(LOG_ERR, "DataDirectory does not exist");
+    return -1;
+  case FN_ERROR:
+    log_fn(LOG_ERR, "DataDirectory can't be read");
+    return -1;
+  case FN_FILE:
+    log_fn(LOG_ERR, "DataDirectory is not a directory.");
+    return -1;
+  }
+  strcat(keydir, "/keys");
+  switch (fn_exists(keydir)) {
+  case FN_NOENT:
+    if (mkdir(keydir, 0700)) {
+      log_fn(LOG_ERR, "Error making key directory.");
       return -1;
     }
+    break;
+  case FN_ERROR:
+    log_fn(LOG_ERR, "Error reading key directory.");
+    return -1;
+  case FN_FILE:
+    log_fn(LOG_ERR, "Key directory is not a directory.");
+    return -1;
+  case FN_DIR:
+    chmod(keydir, 0700);
+    break;
+  }
+  cp = keydir + strlen(keydir); /* End of string. */
+  assert(!*cp);
+  
+  /* 1. Read identity key. Make it if none is found. */
+  strcat(keydir, "/identity.key");
+  prkey = init_key_from_file(keydir);
+  if (!prkey) return -1;
+  set_identity_key(prkey);
+  /* 2. Read onion key.  Make it if none is found. */
+  *cp = '\0';
+  strcat(keydir, "/onion.key");
+  prkey = init_key_from_file(keydir);
+  if (!prkey) return -1;
+  set_onion_key(prkey);
+  
+  /* 3. Initialize link key and TLS context. */
+  *cp = '\0';
+  strcat(keydir, "/link.key");
+  prkey = init_key_from_file(keydir);
+  if (!prkey) return -1;
+  set_link_key(prkey);
+  if (tor_tls_context_new(prkey, 1, options.Nickname) < 0) {
+    log_fn(LOG_ERR, "Error initializing TLS context");
+    return -1;
+  }
+  /* 4. Dump router descriptor to 'router.desc' */
+  /* Must be called after keys are initialized. */
+  if (init_descriptor()<0) {
+    log_fn(LOG_ERR, "Error initializing descriptor.");
+    return -1;
+  }
+  strcpy(keydir, options.DataDirectory);
+  strcat(keydir, "/router.desc");
+  file = fopen(keydir, "w");
+  if (!file) {
+    log_fn(LOG_ERR, "Error opening %s for writing", keydir);
+    return -1;
+  }
+  fputs(router_get_my_descriptor(), file);
+  fclose(file);
+  /* 5. Dump fingerprint to 'fingerprint' */
+  strcpy(keydir, options.DataDirectory);
+  strcat(keydir, "/fingerprint");
+  file = fopen(keydir, "w");
+  if (!file) {
+    log_fn(LOG_ERR, "Error opening %s for writing", keydir);
+    return -1;
+  }
+  if (crypto_pk_get_fingerprint(get_identity_key(), fingerprint)<0) {
+    log_fn(LOG_ERR, "Error computing fingerprint");
+    return -1;
+  }
+  fprintf(file, "%s %s\n", options.Nickname, fingerprint);
+  fclose(file);
+
+  return 0;
+}
+
+static int do_main_loop(void) {
+  int i;
+  int timeout;
+  int poll_result;
+  
+  /* load the routers file */
+  if(router_get_list_from_file(options.RouterFile) < 0) {
+    log_fn(LOG_ERR,"Error loading router list.");
+    return -1;
+  }
+
+  /* load the private keys, if we're supposed to have them, and set up the
+   * TLS context. */
+  if (init_keys() < 0) {
+    log_fn(LOG_ERR,"Error initializing keys; exiting");
+    return -1;
+  }
+
+  if(options.OnionRouter) {
+    cpu_init(); /* launch cpuworkers. Need to do this *after* we've read the private key. */
   }
 
   /* start up the necessary connections based on which ports are
@@ -590,9 +751,10 @@
       conn->state, conn_state_to_string[conn->type][conn->state], now.tv_sec - conn->timestamp_created);
     if(!connection_is_listener(conn)) {
       printf("Conn %d is to '%s:%d'.\n",i,conn->address, conn->port);
-      printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i,conn->inbuf_datalen,
-        now.tv_sec - conn->timestamp_lastread);
-      printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i,conn->outbuf_datalen, 
+      printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i,
+             (int)buf_datalen(conn->inbuf),
+             now.tv_sec - conn->timestamp_lastread);
+      printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i,(int)buf_datalen(conn->outbuf),
         now.tv_sec - conn->timestamp_lastwritten);
     }
     circuit_dump_by_conn(conn); /* dump info about all the circuits using this conn */
@@ -601,42 +763,50 @@
 
 }
 
-int dump_router_to_string(char *s, int maxlen, routerinfo_t *router) {
-  char *pkey;
-  char *signing_pkey, *signing_pkey_tag;
-  int pkeylen, signing_pkeylen;
+int dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
+                          crypto_pk_env_t *ident_key) {
+  char *onion_pkey;
+  char *link_pkey;
+  char *identity_pkey;
+  char digest[20];
+  char signature[128];
+  int onion_pkeylen, link_pkeylen, identity_pkeylen;
   int written;
   int result=0;
   struct exit_policy_t *tmpe;
 
-  if(crypto_pk_write_public_key_to_string(router->pkey,&pkey,&pkeylen)<0) {
-    log(LOG_ERR,"dump_router_to_string(): write pkey to string failed!");
-    return 0;
+  if(crypto_pk_write_public_key_to_string(router->onion_pkey,
+                                          &onion_pkey,&onion_pkeylen)<0) {
+    log_fn(LOG_ERR,"write onion_pkey to string failed!");
+    return -1;
   }
 
-  signing_pkey = "";
-  signing_pkey_tag = "";
-  if (router->signing_pkey) {
-    if(crypto_pk_write_public_key_to_string(router->signing_pkey,
-                                         &signing_pkey,&signing_pkeylen)<0) {
-      log(LOG_ERR,"dump_router_to_string(): write signing_pkey to string failed!");
-      return 0;
-    }
-    signing_pkey_tag = "signing-key\n";
+  if(crypto_pk_write_public_key_to_string(router->identity_pkey,
+                                          &identity_pkey,&identity_pkeylen)<0) {
+    log_fn(LOG_ERR,"write identity_pkey to string failed!");
+    return -1;
+  }
+
+  if(crypto_pk_write_public_key_to_string(router->link_pkey,
+                                          &link_pkey,&link_pkeylen)<0) {
+    log_fn(LOG_ERR,"write link_pkey to string failed!");
+    return -1;
   }
   
-  result = snprintf(s, maxlen, "router %s %d %d %d %d\n%s%s%s",
+  result = snprintf(s, maxlen, 
+                    "router %s %d %d %d %d\nonion-key\n%s"
+                    "link-key\n%s"
+                    "signing-key\n%s",
     router->address,
     router->or_port,
     router->ap_port,
     router->dir_port,
     router->bandwidth,
-    pkey,
-    signing_pkey_tag, signing_pkey);
+    onion_pkey, link_pkey, identity_pkey);
 
-  free(pkey);
-  if (*signing_pkey)
-    free(signing_pkey);
+  free(onion_pkey);
+  free(link_pkey);
+  free(identity_pkey);
 
   if(result < 0 || result > maxlen) {
     /* apparently different glibcs do different things on snprintf error.. so check both */
@@ -654,19 +824,34 @@
     }
     written += result;
   }
+  if (written > maxlen-256) /* Not enough room for signature. */
+    return -1;
 
-  if(written > maxlen-2) {
-    return -1; /* not enough space for \n\0 */
-  }
-  /* XXX count fenceposts here. They're probably wrong. In general,
-   * we need a better way to handle overruns in building the directory
-   * string, and a better way to handle directory string size in general. */
+  strcat(s+written, "router-signature\n");
+  written += strlen(s+written);
+  s[written] = '\0';
+  if (router_get_router_hash(s, digest) < 0)
+    return -1;
 
+  if (crypto_pk_private_sign(ident_key, digest, 20, signature) < 0) {
+    log_fn(LOG_ERR, "Error signing digest");
+    return -1;
+  }
+  strcat(s+written, "-----BEGIN SIGNATURE-----\n");
+  written += strlen(s+written);
+  if (base64_encode(s+written, maxlen-written, signature, 128) < 0) {
+    log_fn(LOG_ERR, "Couldn't base64-encode signature");
+  }
+  written += strlen(s+written);
+  strcat(s+written, "-----END SIGNATURE-----\n");
+  written += strlen(s+written);
+  
+  if (written > maxlen-2) 
+    return -1;
   /* include a last '\n' */
   s[written] = '\n';
   s[written+1] = 0;
   return written+1;
-
 }
 
 static int 
@@ -738,7 +923,10 @@
   cp = s+i;
   for (i = 0; i < dir->n_routers; ++i) {
     router = dir->routers[i];
-    written = dump_router_to_string(cp, eos-cp, router);
+    /* XXX This is wrong; we shouldn't sign routers, but rather propagate
+     * XXX the original router blocks, unaltered.
+     */
+    written = dump_router_to_string(cp, eos-cp, router, private_key);
 
     if(written < 0) { 
       log(LOG_ERR,"dump_signed_directory_to_string(): tried to exceed string length.");
@@ -789,8 +977,35 @@
   return 0;
 }
 
-char *router_get_my_descriptor(void) {
-  return "this is bob's descriptor";
+static char descriptor[8192];
+/* XXX should this replace my_routerinfo? */
+static routerinfo_t *desc_routerinfo; 
+const char *router_get_my_descriptor(void) {
+  return descriptor;
+}
+
+static int init_descriptor(void) {
+  routerinfo_t *ri;
+  ri = tor_malloc(sizeof(routerinfo_t));
+  ri->address = strdup("XXXXXXX"); /*XXX*/
+  ri->nickname = strdup(options.Nickname);
+  /* No need to set addr. ???? */
+  ri->or_port = options.ORPort;
+  ri->ap_port = options.APPort;
+  ri->dir_port = options.DirPort;
+  ri->onion_pkey = crypto_pk_dup_key(get_onion_key());
+  ri->link_pkey = crypto_pk_dup_key(get_link_key());
+  ri->identity_pkey = crypto_pk_dup_key(get_identity_key());
+  ri->bandwidth = options.TotalBandwidth;
+  ri->exit_policy = NULL; /* XXX implement this. */
+  if (desc_routerinfo)
+    routerinfo_free(desc_routerinfo);
+  desc_routerinfo = ri;
+  if (dump_router_to_string(descriptor, 8192, ri, get_identity_key())<0) {
+    log_fn(LOG_ERR, "Couldn't dump router to string.");
+    return -1;
+  }
+  return 0;
 }
 
 void daemonize(void) {
@@ -840,7 +1055,7 @@
   crypto_seed_rng();
   retval = do_main_loop();
   crypto_global_cleanup();
-
+  
   return retval;
 }
 

Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/src/or/onion.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -d -r1.65 -r1.66
--- onion.c	16 Sep 2003 20:57:08 -0000	1.65
+++ onion.c	25 Sep 2003 05:17:11 -0000	1.66
@@ -231,7 +231,7 @@
     choice = choice % rarray_len;
     log(LOG_DEBUG,"new_route(): Contemplating router %u.",choice);
     if(choice == oldchoice ||
-      (oldchoice < rarray_len && !crypto_pk_cmp_keys(rarray[choice]->pkey, rarray[oldchoice]->pkey)) ||
+       (oldchoice < rarray_len && !crypto_pk_cmp_keys(rarray[choice]->onion_pkey, rarray[oldchoice]->onion_pkey)) ||
       (options.OnionRouter && !connection_twin_get_by_addr_port(rarray[choice]->addr, rarray[choice]->or_port))) {
       /* Same router as last choice, or router twin,
        *   or no routers with that key are connected to us.
@@ -263,7 +263,7 @@
       }
     }
     for(j=0;j<i;j++) {
-      if(!crypto_pk_cmp_keys(rarray[i]->pkey, rarray[j]->pkey)) {
+      if(!crypto_pk_cmp_keys(rarray[i]->onion_pkey, rarray[j]->onion_pkey)) {
         /* these guys are twins. so we've already counted him. */
         log(LOG_DEBUG,"Nope, %d is a twin of %d.",i,j);
         goto next_i_loop;
@@ -311,8 +311,8 @@
     log(LOG_DEBUG,"onion_generate_cpath(): %u : %s:%u, %u/%u",routelen-i,
         inet_ntoa(netaddr),
         (rarray[route[i]])->or_port,
-        (int) (rarray[route[i]])->pkey,
-        crypto_pk_keysize((rarray[route[i]])->pkey));
+        (int) (rarray[route[i]])->onion_pkey,
+        crypto_pk_keysize((rarray[route[i]])->onion_pkey));
   }
 
   /* create the cpath layer by layer, starting at the last hop */

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.136
retrieving revision 1.137
diff -u -d -r1.136 -r1.137
--- or.h	24 Sep 2003 21:24:52 -0000	1.136
+++ or.h	25 Sep 2003 05:17:11 -0000	1.137
@@ -245,6 +245,8 @@
 
 #define ZERO_STREAM "\0\0\0\0\0\0\0\0"
 
+typedef struct buf_t buf_t;
+
 struct connection_t { 
 
   uint8_t type;
@@ -261,16 +263,12 @@
                          * iteration of the main loop?
                          */
 
-  char *inbuf;
-  int inbuflen; /* how many bytes are alloc'ed for inbuf? */
-  int inbuf_datalen; /* how many bytes of data are on inbuf? */
+  buf_t *inbuf;
   int inbuf_reached_eof; /* did read() return 0 on this conn? */
   long timestamp_lastread; /* when was the last time poll() said we could read? */
 
-  char *outbuf;
-  int outbuflen; /* how many bytes are allocated for the outbuf? */
+  buf_t *outbuf;
   int outbuf_flushlen; /* how much data should we try to flush from the outbuf? */
-  int outbuf_datalen; /* how much data is there total on the outbuf? */
   long timestamp_lastwritten; /* when was the last time poll() said we could write? */
 
   long timestamp_created; /* when was this connection_t created? */
@@ -287,7 +285,9 @@
   char *address; /* FQDN (or IP) of the guy on the other end.
                   * strdup into this, because free_connection frees it
                   */
-  crypto_pk_env_t *pkey; /* public RSA key for the other side */
+  crypto_pk_env_t *onion_pkey; /* public RSA key for the other side's onions */
+  crypto_pk_env_t *link_pkey; /* public RSA key for the other side's TLS */
+  crypto_pk_env_t *identity_pkey; /* public RSA key for the other side's signing */
 
 /* Used only by OR connections: */
   tor_tls *tls;
@@ -331,8 +331,9 @@
   uint16_t ap_port;
   uint16_t dir_port;
  
-  crypto_pk_env_t *pkey; /* public RSA key */
-  crypto_pk_env_t *signing_pkey; /* May be null */
+  crypto_pk_env_t *onion_pkey; /* public RSA key for onions */
+  crypto_pk_env_t *link_pkey;  /* public RSA key for TLS */
+  crypto_pk_env_t *identity_pkey;  /* public RSA key for signing */
  
   /* link info */
   uint32_t bandwidth;
@@ -405,10 +406,8 @@
 
 typedef struct {
    char *LogLevel;
+   char *DataDirectory;
    char *RouterFile;
-   char *SigningPrivateKeyFile;
-   char *PrivateKeyFile;
-   char *CertFile;
    char *Nickname;
    double CoinWeight;
    int Daemon;
@@ -435,24 +434,29 @@
 
 /********************************* buffers.c ***************************/
 
-int buf_new(char **buf, int *buflen, int *buf_datalen);
-void buf_free(char *buf);
+buf_t *buf_new();
+buf_t *buf_new_with_capacity(size_t size);
+void buf_free(buf_t *buf);
 
-int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, int *reached_eof);
-int read_to_buf_tls(tor_tls *tls, int at_most, char **buf, int *buflen, int *buf_datalen);
+size_t buf_datalen(const buf_t *buf);
+size_t buf_capacity(const buf_t *buf);
+const char *_buf_peek_raw_buffer(const buf_t *buf);
 
-int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen);
-int flush_buf_tls(tor_tls *tls, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen);
+int read_to_buf(int s, int at_most, buf_t *buf, int *reached_eof);
+int read_to_buf_tls(tor_tls *tls, int at_most, buf_t *buf);
 
-int write_to_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen);
-int fetch_from_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen);
-int fetch_from_buf_http(char *buf, int *buf_datalen,
+int flush_buf(int s, buf_t *buf, int *buf_flushlen);
+int flush_buf_tls(tor_tls *tls, buf_t *buf, int *buf_flushlen);
+
+int write_to_buf(char *string, int string_len, buf_t *buf);
+int fetch_from_buf(char *string, int string_len, buf_t *buf);
+int fetch_from_buf_http(buf_t *buf,
                         char *headers_out, int max_headerlen,
                         char *body_out, int max_bodylen);
-int fetch_from_buf_socks(char *buf, int *buf_datalen,
+int fetch_from_buf_socks(buf_t *buf,
                          char *addr_out, int max_addrlen,
                          uint16_t *port_out);
-int find_on_inbuf(char *string, int string_len, char *buf, int buf_datalen);
+int find_on_inbuf(char *string, int string_len, buf_t *buf);
 
 /********************************* circuit.c ***************************/
 
@@ -589,10 +593,10 @@
 
 /********************************* main.c ***************************/
 
-void set_privatekey(crypto_pk_env_t *k);
-crypto_pk_env_t *get_privatekey(void);
-void set_signing_privatekey(crypto_pk_env_t *k);
-crypto_pk_env_t *get_signing_privatekey(void);
+void set_onion_key(crypto_pk_env_t *k);
+crypto_pk_env_t *get_onion_key(void);
+void set_identity_key(crypto_pk_env_t *k);
+crypto_pk_env_t *get_identity_key(void);
 int connection_add(connection_t *conn);
 int connection_remove(connection_t *conn);
 void connection_set_poll_socket(connection_t *conn);
@@ -617,7 +621,7 @@
 int dump_signed_directory_to_string_impl(char *s, int maxlen, 
                                          directory_t *dir, 
                                          crypto_pk_env_t *private_key); 
-char *router_get_my_descriptor(void);
+const char *router_get_my_descriptor(void);
 
 int main(int argc, char *argv[]);
 
@@ -655,16 +659,20 @@
 void router_retry_connections(void);
 routerinfo_t *router_pick_directory_server(void);
 routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
-routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk);
+routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk);
+#if 0
+routerinfo_t *router_get_by_identity_pk(crypto_pk_env_t *pk);
+#endif
 void router_get_directory(directory_t **pdirectory);
 int router_is_me(uint32_t addr, uint16_t port);
 void router_forget_router(uint32_t addr, uint16_t port);
 int router_get_list_from_file(char *routerfile);
+int router_get_router_hash(char *s, char *digest);
 
 /* Reads a list of known routers, unsigned. */
 int router_get_list_from_string(char *s);
 /* Exported for debugging */
-int router_get_list_from_string_impl(char *s, directory_t **dest);
+int router_get_list_from_string_impl(char **s, directory_t **dest);
 /* Reads a signed directory. */
 int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey);
 /* Exported or debugging */

Index: routers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routers.c,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -d -r1.49 -r1.50
--- routers.c	18 Sep 2003 08:11:31 -0000	1.49
+++ routers.c	25 Sep 2003 05:17:11 -0000	1.50
@@ -28,10 +28,6 @@
 static char *eat_whitespace_no_nl(char *s);
 static char *find_whitespace(char *s);
 static void router_free_exit_policy(routerinfo_t *router);
-static routerinfo_t *router_get_entry_from_string_tok(char**s, 
-                                                      directory_token_t *tok);
-static int router_get_list_from_string_tok(char **s, directory_t **dest,
-                                           directory_token_t *tok);
 static int router_add_exit_policy(routerinfo_t *router, 
                                   directory_token_t *tok);
 static int 
@@ -119,7 +115,7 @@
   return NULL;
 }
 
-routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk) 
+routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk) 
 {
   int i;
   routerinfo_t *router;
@@ -128,14 +124,32 @@
 
   for(i=0;i<directory->n_routers;i++) {
     router = directory->routers[i];
-    /* XXX Should this really be a separate link key? */
-    if (0 == crypto_pk_cmp_keys(router->pkey, pk))
+    if (0 == crypto_pk_cmp_keys(router->link_pkey, pk))
       return router;
   }
   
   return NULL;
 }
+
+#if 0 
+routerinfo_t *router_get_by_identity_pk(crypto_pk_env_t *pk) 
+{
+  int i;
+  routerinfo_t *router;
+
+  assert(directory);
+
+  for(i=0;i<directory->n_routers;i++) {
+    router = directory->routers[i];
+    /* XXX Should this really be a separate link key? */
+    if (0 == crypto_pk_cmp_keys(router->identity_pkey, pk))
+      return router;
+  }
   
+  return NULL;
+}
+#endif
+ 
 
 void router_get_directory(directory_t **pdirectory) {
   *pdirectory = directory;
@@ -174,10 +188,12 @@
 
   if (router->address)
     free(router->address);
-  if (router->pkey)
-    crypto_free_pk_env(router->pkey);
-  if (router->signing_pkey)
-    crypto_free_pk_env(router->signing_pkey);
+  if (router->onion_pkey)
+    crypto_free_pk_env(router->onion_pkey);
+  if (router->link_pkey)
+    crypto_free_pk_env(router->link_pkey);
+  if (router->identity_pkey)
+    crypto_free_pk_env(router->identity_pkey);
   e = router->exit_policy;
   while (e) {
     etmp = e->next;
@@ -195,7 +211,8 @@
   int i;
   for (i = 0; i < directory->n_routers; ++i)
     routerinfo_free(directory->routers[i]);
-  free(directory->routers);
+  if (directory->routers)
+    free(directory->routers);
   if(directory->software_versions)
     free(directory->software_versions);
   free(directory);
@@ -282,6 +299,9 @@
   K_ROUTER, 
   K_SIGNED_DIRECTORY,
   K_SIGNING_KEY,
+  K_ONION_KEY,
+  K_LINK_KEY,
+  K_ROUTER_SIGNATURE,
   _SIGNATURE, 
   _PUBLIC_KEY, 
   _ERR, 
@@ -298,6 +318,9 @@
   { "recommended-software", K_RECOMMENDED_SOFTWARE },
   { "signed-directory", K_SIGNED_DIRECTORY },
   { "signing-key", K_SIGNING_KEY },
+  { "onion-key", K_ONION_KEY },
+  { "link-key", K_LINK_KEY },
+  { "router-signature", K_ROUTER_SIGNATURE },
   { NULL, -1 }
 };
 
@@ -450,6 +473,9 @@
     case K_ROUTER: printf("Router"); break;
     case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break;
     case K_SIGNING_KEY: printf("Signing-Key"); break;
+    case K_ONION_KEY: printf("Onion-key"); break;
+    case K_LINK_KEY: printf("Link-key"); break;
+    case K_ROUTER_SIGNATURE: printf("Router-signature"); break;
     default:
       printf("?????? %d\n", tok->tp); return;
     }
@@ -459,7 +485,6 @@
   printf("\n");
   return;
 }
-
 static int
 router_get_next_token(char **s, directory_token_t *tok) {
   int i;
@@ -508,7 +533,7 @@
 
 int router_get_list_from_string(char *s) 
 {
-  if (router_get_list_from_string_impl(s, &directory)) {
+  if (router_get_list_from_string_impl(&s, &directory)) {
     log(LOG_ERR, "Error parsing router file");
     return -1;
   }
@@ -519,43 +544,46 @@
   return 0;
 }
 
-int router_get_list_from_string_impl(char *s, directory_t **dest) {
-  directory_token_t tok;
-  if (router_get_next_token(&s, &tok)) {
-    log(LOG_ERR, "Error reading routers: %s", tok.val.error); 
-    return -1;
-  }
-  return router_get_list_from_string_tok(&s, dest, &tok);
-}
-
-static int router_get_dir_hash(char *s, char *digest)
+static int router_get_hash_impl(char *s, char *digest, const char *start_str,
+                                const char *end_str) 
 {
   char *start, *end;
-  start = strstr(s, "signed-directory");
+  start = strstr(s, start_str);
   if (!start) {
-    log(LOG_ERR,"router_get_dir_hash(): couldn't find \"signed-directory\"");
+    log_fn(LOG_ERR,"couldn't find \"%s\"",start_str);
     return -1;
   }
-  end = strstr(start, "directory-signature");
+  end = strstr(start+strlen(start_str), end_str);
   if (!end) {
-    log(LOG_ERR,"router_get_dir_hash(): couldn't find \"directory-signature\"");
+    log_fn(LOG_ERR,"couldn't find \"%s\"",end_str);
     return -1;
   }
   end = strchr(end, '\n');
   if (!end) {
-    log(LOG_ERR,"router_get_dir_hash(): couldn't find EOL");
+    log_fn(LOG_ERR,"couldn't find EOL");
     return -1;
   }
   ++end;
   
   if (crypto_SHA_digest(start, end-start, digest)) {
-    log(LOG_ERR,"router_get_dir_hash(): couldn't compute digest");
+    log_fn(LOG_ERR,"couldn't compute digest");
     return -1;
   }
 
   return 0;
 }
 
+static int router_get_dir_hash(char *s, char *digest)
+{
+  return router_get_hash_impl(s,digest,
+                              "signed-directory","directory-signature");
+}
+int router_get_router_hash(char *s, char *digest)
+{
+  return router_get_hash_impl(s,digest,
+                              "router ","router-signature");
+}
+
 /* return 0 if myversion is in start. Else return -1. */
 int compare_recommended_versions(char *myversion, char *start) {
   int len_myversion = strlen(myversion);
@@ -621,12 +649,11 @@
       log(LOG_ERR, "Error reading directory: expected %s", name);       \
       return -1;                                                        \
     } } while(0)
-  
+
   if (router_get_dir_hash(s, digest)) {
     log(LOG_ERR, "Unable to compute digest of directory");
-    return -1;
+    goto err;
   }
-
   NEXT_TOK();
   TOK_IS(K_SIGNED_DIRECTORY, "signed-directory");
 
@@ -634,17 +661,17 @@
   TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software");
   if (tok.val.cmd.n_args != 1) {
     log(LOG_ERR, "Invalid recommded-software line");
-    return -1;
+    goto err;
   }
   versions = strdup(tok.val.cmd.args[0]);
   
-  NEXT_TOK();
-  if (router_get_list_from_string_tok(&s, &new_dir, &tok)) {
+  if (router_get_list_from_string_impl(&s, &new_dir)) {
     log(LOG_ERR, "Error reading routers from directory");
-    return -1;
+    goto err;
   }
   new_dir->software_versions = versions;
-  
+
+  NEXT_TOK();
   TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature");
   NEXT_TOK();
   TOK_IS(_SIGNATURE, "signature");
@@ -653,12 +680,12 @@
         != 20) {
       log(LOG_ERR, "Error reading directory: invalid signature.");
       free(tok.val.signature);
-      return -1;
+      goto err;
     }
     if (memcmp(digest, signed_digest, 20)) {
       log(LOG_ERR, "Error reading directory: signature does not match.");
       free(tok.val.signature);
-      return -1;
+      goto err;
     }
   }
   free(tok.val.signature);
@@ -671,12 +698,16 @@
   *dest = new_dir;
 
   return 0;
+
+ err:
+  if (new_dir)
+    directory_free(new_dir);
+  return -1;
 #undef NEXT_TOK
 #undef TOK_IS
 }
 
-static int router_get_list_from_string_tok(char **s, directory_t **dest,
-                                           directory_token_t *tok)
+int router_get_list_from_string_impl(char **s, directory_t **dest)
 {
   routerinfo_t *router;
   routerinfo_t **rarray;
@@ -686,8 +717,11 @@
 
   rarray = (routerinfo_t **)tor_malloc((sizeof(routerinfo_t *))*MAX_ROUTERS_IN_DIR);
 
-  while (tok->tp == K_ROUTER) {
-    router = router_get_entry_from_string_tok(s, tok);
+  while (1) {
+    *s = eat_whitespace(*s);
+    if (strncmp(*s, "router ", 7)!=0)
+      break;
+    router = router_get_entry_from_string(s);
     if (!router) {
       log(LOG_ERR, "Error reading router");
       return -1;
@@ -755,34 +789,32 @@
   return 0;
 }
 
-
-routerinfo_t *router_get_entry_from_string(char **s) {
-  directory_token_t tok;
-  routerinfo_t *router;
-  if (router_get_next_token(s, &tok)) return NULL;
-  router = router_get_entry_from_string_tok(s, &tok);
-  if (tok.tp != _EOF) {
-    router_release_token(&tok);
-    return NULL;
-  }
-  return router;
-}
-
 /* reads a single router entry from s.
  * updates s so it points to after the router it just read.
  * mallocs a new router, returns it if all goes well, else returns NULL.
  */
-static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t *tok) {
+routerinfo_t *router_get_entry_from_string(char**s) {
   routerinfo_t *router = NULL;
+#if 0
+  char signed_digest[128];
+#endif
+  char digest[128];
+  directory_token_t _tok;
+  directory_token_t *tok = &_tok;
 
-#define NEXT_TOKEN()                                                    \
-  do { if (router_get_next_token(s, tok)) {                             \
-      log(LOG_ERR, "Error reading directory: %s", tok->val.error);      \
-      goto err;                                                         \
+#define NEXT_TOKEN()                                                     \
+  do { if (router_get_next_token(s, tok)) {                              \
+      log(LOG_ERR, "Error reading directory: %s", tok->val.error);       \
+      goto err;                                                          \
     } } while(0)
 
 #define ARGS tok->val.cmd.args
 
+  if (router_get_router_hash(*s, digest) < 0)
+    return NULL;
+
+  NEXT_TOKEN();
+
   if (tok->tp != K_ROUTER) {
     router_release_token(tok);
     log(LOG_ERR,"router_get_entry_from_string(): Entry does not start with \"router\"");
@@ -793,7 +825,7 @@
   memset(router,0,sizeof(routerinfo_t)); /* zero it out first */
   /* C doesn't guarantee that NULL is represented by 0 bytes.  You'll
      thank me for this someday. */
-  router->pkey = router->signing_pkey = NULL; 
+  router->onion_pkey = router->identity_pkey = router->link_pkey = NULL; 
 
   if (tok->val.cmd.n_args != 5) {
     log(LOG_ERR,"router_get_entry_from_string(): Wrong # of arguments to \"router\"");
@@ -828,38 +860,77 @@
     router->or_port, router->ap_port, router->dir_port, router->bandwidth);
 
   NEXT_TOKEN();
+  if (tok->tp != K_ONION_KEY) {
+    log_fn(LOG_ERR, "Missing onion-key"); goto err;
+  }
+  NEXT_TOKEN();
   if (tok->tp != _PUBLIC_KEY) {
-    log(LOG_ERR,"router_get_entry_from_string(): Missing public key");
-    goto err;
-  } /* Check key length */
-  router->pkey = tok->val.public_key;
+    log_fn(LOG_ERR, "Missing onion key"); goto err;
+  } /* XXX Check key length */
+  router->onion_pkey = tok->val.public_key;
 
   NEXT_TOKEN();
-  if (tok->tp == K_SIGNING_KEY) {
-    NEXT_TOKEN();
-    if (tok->tp != _PUBLIC_KEY) {
-      log(LOG_ERR,"router_get_entry_from_string(): Missing signing key");
-      goto err;
-    }
-    router->signing_pkey = tok->val.public_key;
-    NEXT_TOKEN();
-  } 
+  if (tok->tp != K_LINK_KEY) {
+    log_fn(LOG_ERR, "Missing link-key");  goto err;
+  }
+  NEXT_TOKEN();
+  if (tok->tp != _PUBLIC_KEY) {
+    log_fn(LOG_ERR, "Missing link key"); goto err;
+  } /* XXX Check key length */
+  router->link_pkey = tok->val.public_key;
 
+  NEXT_TOKEN();
+  if (tok->tp != K_SIGNING_KEY) {
+    log_fn(LOG_ERR, "Missing signing-key"); goto err;
+  }
+  NEXT_TOKEN();
+  if (tok->tp != _PUBLIC_KEY) {
+    log_fn(LOG_ERR, "Missing signing key"); goto err;
+  }
+  router->identity_pkey = tok->val.public_key;
+
+  NEXT_TOKEN();
   while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) {
     router_add_exit_policy(router, tok);
     NEXT_TOKEN();
   }
   
+  if (tok->tp != K_ROUTER_SIGNATURE) {
+    log_fn(LOG_ERR,"Missing router signature");
+    goto err;
+  }
+  NEXT_TOKEN();
+  if (tok->tp != _SIGNATURE) {
+    log_fn(LOG_ERR,"Missing router signature");
+    goto err;
+  }
+  assert (router->identity_pkey);
+#if 0
+  /* XXX This should get re-enabled, once directory servers properly
+   * XXX relay signed router blocks. */
+  if (crypto_pk_public_checksig(router->identity_pkey, tok->val.signature,
+                                128, signed_digest) != 20) {
+    log_fn(LOG_ERR, "Invalid signature");
+    goto err;
+  }
+  if (memcmp(digest, signed_digest, 20)) {
+    log_fn(LOG_ERR, "Mismatched signature");
+    goto err;
+  }
+#endif
+  
   return router;
 
  err:
   router_release_token(tok); 
   if(router->address)
     free(router->address);
-  if(router->pkey)
-    crypto_free_pk_env(router->pkey);
-  if(router->signing_pkey)
-    crypto_free_pk_env(router->signing_pkey);
+  if(router->link_pkey)
+    crypto_free_pk_env(router->link_pkey);
+  if(router->onion_pkey)
+    crypto_free_pk_env(router->onion_pkey);
+  if(router->identity_pkey)
+    crypto_free_pk_env(router->identity_pkey);
   router_free_exit_policy(router);
   free(router);
   return NULL;

Index: test.c
===================================================================
RCS file: /home/or/cvsroot/src/or/test.c,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- test.c	10 Sep 2003 00:47:24 -0000	1.37
+++ test.c	25 Sep 2003 05:17:11 -0000	1.38
@@ -49,19 +49,19 @@
   char str[256];
   char str2[256];
 
-  char *buf;
-  int buflen, buf_datalen;
+  buf_t *buf;
+  buf_t *buf2;
 
   int s, i, j, eof;
 
   /****
    * buf_new
    ****/
-  if (buf_new(&buf, &buflen, &buf_datalen))
+  if (!(buf = buf_new()))
     test_fail();
 
-  test_eq(buflen, MAX_BUF_SIZE);
-  test_eq(buf_datalen, 0);
+  test_eq(buf_capacity(buf), MAX_BUF_SIZE);
+  test_eq(buf_datalen(buf), 0);
 
   /****
    * read_to_buf
@@ -75,52 +75,52 @@
   
   s = open("/tmp/tor_test/data", O_RDONLY, 0);
   eof = 0;
-  i = read_to_buf(s, 10, &buf, &buflen, &buf_datalen, &eof);
-  test_eq(buflen, MAX_BUF_SIZE);
-  test_eq(buf_datalen, 10);
+  i = read_to_buf(s, 10, buf, &eof);
+  test_eq(buf_capacity(buf), MAX_BUF_SIZE);
+  test_eq(buf_datalen(buf), 10);
   test_eq(eof, 0);
   test_eq(i, 10);
-  test_memeq(str, buf, 10);
+  test_memeq(str, (char*)_buf_peek_raw_buffer(buf), 10);
 
   /* Test reading 0 bytes. */
-  i = read_to_buf(s, 0, &buf, &buflen, &buf_datalen, &eof);
-  test_eq(buflen, MAX_BUF_SIZE);
-  test_eq(buf_datalen, 10);
+  i = read_to_buf(s, 0, buf, &eof);
+  test_eq(buf_capacity(buf), MAX_BUF_SIZE);
+  test_eq(buf_datalen(buf), 10);
   test_eq(eof, 0);
   test_eq(i, 0);
 
   /* Now test when buffer is filled exactly. */
-  buflen = 16;
-  i = read_to_buf(s, 6, &buf, &buflen, &buf_datalen, &eof);
-  test_eq(buflen, 16);
-  test_eq(buf_datalen, 16);
+  buf2 = buf_new_with_capacity(6);
+  i = read_to_buf(s, 6, buf2, &eof);
+  test_eq(buf_capacity(buf2), 6);
+  test_eq(buf_datalen(buf2), 6);
   test_eq(eof, 0);
   test_eq(i, 6);
-  test_memeq(str, buf, 16);
+  test_memeq(str+10, (char*)_buf_peek_raw_buffer(buf2), 6);
+  buf_free(buf2);
   
   /* Now test when buffer is filled with more data to read. */
-  buflen = 32;
-  i = read_to_buf(s, 128, &buf, &buflen, &buf_datalen, &eof);
-  test_eq(buflen, 32);
-  test_eq(buf_datalen, 32);
+  buf2 = buf_new_with_capacity(32);
+  i = read_to_buf(s, 128, buf2, &eof);
+  test_eq(buf_capacity(buf2), 32);
+  test_eq(buf_datalen(buf2), 32);
   test_eq(eof, 0);
-  test_eq(i, 16);
-  test_memeq(str, buf, 32);
+  test_eq(i, 32);
+  buf_free(buf2);
 
   /* Now read to eof. */
-  buflen = MAX_BUF_SIZE;
-  test_assert(buflen > 256);
-  i = read_to_buf(s, 1024, &buf, &buflen, &buf_datalen, &eof);
-  test_eq(i, (256-32));
-  test_eq(buflen, MAX_BUF_SIZE);
-  test_eq(buf_datalen, 256);
-  test_memeq(str, buf, 256);
+  test_assert(buf_capacity(buf) > 256);
+  i = read_to_buf(s, 1024, buf, &eof);
+  test_eq(i, (256-32-10-6));
+  test_eq(buf_capacity(buf), MAX_BUF_SIZE);
+  test_eq(buf_datalen(buf), 256-6-32);
+  test_memeq(str, (char*)_buf_peek_raw_buffer(buf), 10); /* XXX Check rest. */
   test_eq(eof, 0);
 
-  i = read_to_buf(s, 1024, &buf, &buflen, &buf_datalen, &eof);
+  i = read_to_buf(s, 1024, buf, &eof);
   test_eq(i, 0);
-  test_eq(buflen, MAX_BUF_SIZE);
-  test_eq(buf_datalen, 256);
+  test_eq(buf_capacity(buf), MAX_BUF_SIZE);
+  test_eq(buf_datalen(buf), 256-6-32);
   test_eq(eof, 1);
 
   close(s);
@@ -128,50 +128,59 @@
   /**** 
    * find_on_inbuf
    ****/
+  buf_free(buf);
+  buf = buf_new();
+  s = open("/tmp/tor_test/data", O_RDONLY, 0);
+  eof = 0;
+  i = read_to_buf(s, 1024, buf, &eof); 
+  test_eq(256, i);
+  close(s);
 
-  test_eq(((int)'d') + 1, find_on_inbuf("abcd", 4, buf, buf_datalen));
-  test_eq(-1, find_on_inbuf("xyzzy", 5, buf, buf_datalen));
+  test_eq(((int)'d') + 1, find_on_inbuf("abcd", 4, buf));
+  test_eq(-1, find_on_inbuf("xyzzy", 5, buf));
   /* Make sure we don't look off the end of the buffef */
-  buf[256] = 'A';
-  buf[257] = 'X';
-  test_eq(-1, find_on_inbuf("\xff" "A", 2, buf, buf_datalen));
-  test_eq(-1, find_on_inbuf("AX", 2, buf, buf_datalen));
+  ((char*)_buf_peek_raw_buffer(buf))[256] = 'A';
+  ((char*)_buf_peek_raw_buffer(buf))[257] = 'X';
+  test_eq(-1, find_on_inbuf("\xff" "A", 2, buf));
+  test_eq(-1, find_on_inbuf("AX", 2, buf));
   /* Make sure we use the string length */
-  test_eq(((int)'d')+1, find_on_inbuf("abcdX", 4, buf, buf_datalen));
+  test_eq(((int)'d')+1, find_on_inbuf("abcdX", 4, buf));
 
   /****
    * fetch_from_buf
    ****/
   memset(str2, 255, 256);
-  test_eq(246, fetch_from_buf(str2, 10, &buf, &buflen, &buf_datalen));
+  test_eq(246, fetch_from_buf(str2, 10, buf));
   test_memeq(str2, str, 10);
-  test_memeq(str+10,buf,246);
-  test_eq(buf_datalen,246);
+  test_memeq(str+10,(char*)_buf_peek_raw_buffer(buf),246);
+  test_eq(buf_datalen(buf),246);
 
-  test_eq(0, fetch_from_buf(str2, 246, &buf, &buflen, &buf_datalen));
+  test_eq(0, fetch_from_buf(str2, 246, buf));
   test_memeq(str2, str+10, 246);
-  test_eq(buflen,MAX_BUF_SIZE);
-  test_eq(buf_datalen,0);
+  test_eq(buf_capacity(buf),MAX_BUF_SIZE);
+  test_eq(buf_datalen(buf),0);
 
   /****
    * write_to_buf
    ****/
-  memset(buf, (int)'-', 256);
-  i = write_to_buf("Hello world", 11, &buf, &buflen, &buf_datalen);
+  memset((char *)_buf_peek_raw_buffer(buf), (int)'-', 256);
+  i = write_to_buf("Hello world", 11, buf);
   test_eq(i, 11);
-  test_eq(buf_datalen, 11);
-  test_memeq(buf, "Hello world", 11);
-  i = write_to_buf("XYZZY", 5, &buf, &buflen, &buf_datalen);
+  test_eq(buf_datalen(buf), 11);
+  test_memeq((char*)_buf_peek_raw_buffer(buf), "Hello world", 11);
+  i = write_to_buf("XYZZY", 5, buf);
   test_eq(i, 16);
-  test_eq(buf_datalen, 16);
-  test_memeq(buf, "Hello worldXYZZY", 16);
+  test_eq(buf_datalen(buf), 16);
+  test_memeq((char*)_buf_peek_raw_buffer(buf), "Hello worldXYZZY", 16);
   /* Test when buffer is overfull. */
+#if 0
   buflen = 18;
   test_eq(-1, write_to_buf("This string will not fit.", 25, 
                            &buf, &buflen, &buf_datalen));
   test_eq(buf_datalen, 16);
   test_memeq(buf, "Hello worldXYZZY--", 18);
   buflen = MAX_BUF_SIZE;
+#endif
 
   /****
    * flush_buf
@@ -482,7 +491,8 @@
 }
 
 /* from main.c */
-int dump_router_to_string(char *s, int maxlen, routerinfo_t *router);
+int dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
+                          crypto_pk_env_t *ident_key);
 void dump_directory_to_string(char *s, int maxlen);
 
 /* from routers.c */
@@ -491,28 +501,30 @@
 void
 test_dir_format()
 {
-  
-  char buf[2048], buf2[2048];
-  char *pk1_str = NULL, *pk2_str = NULL, *cp;
-  int pk1_str_len, pk2_str_len;
+  char buf[8192], buf2[8192];
+  char *pk1_str = NULL, *pk2_str = NULL, *pk3_str = NULL, *cp;
+  int pk1_str_len, pk2_str_len, pk3_str_len;
   routerinfo_t r1, r2;
-  crypto_pk_env_t *pk1 = NULL, *pk2 = NULL;
-  routerinfo_t *rp1, *rp2;
+  crypto_pk_env_t *pk1 = NULL, *pk2 = NULL, *pk3 = NULL;
+  routerinfo_t *rp1 = NULL, *rp2 = NULL;
   struct exit_policy_t ex1, ex2;
   directory_t *dir1 = NULL, *dir2 = NULL;
 
   test_assert( (pk1 = crypto_new_pk_env(CRYPTO_PK_RSA)) );
   test_assert( (pk2 = crypto_new_pk_env(CRYPTO_PK_RSA)) );
+  test_assert( (pk3 = crypto_new_pk_env(CRYPTO_PK_RSA)) );
   test_assert(! crypto_pk_generate_key(pk1));
   test_assert(! crypto_pk_generate_key(pk2));
+  test_assert(! crypto_pk_generate_key(pk3));
   
   r1.address = "testaddr1.foo.bar";
   r1.addr = 0xc0a80001u; /* 192.168.0.1 */
   r1.or_port = 9000;
   r1.ap_port = 9002;
   r1.dir_port = 9003;
-  r1.pkey = pk1;
-  r1.signing_pkey = NULL;
+  r1.onion_pkey = pk1;
+  r1.identity_pkey = pk2;
+  r1.link_pkey = pk3;
   r1.bandwidth = 1000;
   r1.exit_policy = NULL;
 
@@ -530,8 +542,9 @@
   r2.or_port = 9005;
   r2.ap_port = 0;
   r2.dir_port = 0;
-  r2.pkey = pk2;
-  r2.signing_pkey = pk1;
+  r2.onion_pkey = pk2;
+  r2.identity_pkey = pk1;
+  r2.link_pkey = pk2;
   r2.bandwidth = 3000;
   r2.exit_policy = &ex1;
 
@@ -539,14 +552,23 @@
                                                     &pk1_str_len));
   test_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str, 
                                                     &pk2_str_len));
-  strcpy(buf2, "router testaddr1.foo.bar 9000 9002 9003 1000\n");
+  test_assert(!crypto_pk_write_public_key_to_string(pk3 , &pk3_str, 
+                                                    &pk3_str_len));
+  
+  strcpy(buf2, "router testaddr1.foo.bar 9000 9002 9003 1000\nonion-key\n");
   strcat(buf2, pk1_str);
-  strcat(buf2, "\n");
+  strcat(buf2, "link-key\n");
+  strcat(buf2, pk3_str);
+  strcat(buf2, "signing-key\n");
+  strcat(buf2, pk2_str);
+  strcat(buf2, "router-signature\n");
   
   memset(buf, 0, 2048);
-  test_assert(dump_router_to_string(buf, 2048, &r1)>0);
+  test_assert(dump_router_to_string(buf, 2048, &r1, pk1)>0);
+  buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same 2ce*/
   test_streq(buf, buf2);
-
+  
+  test_assert(dump_router_to_string(buf, 2048, &r1, pk1)>0);
   cp = buf;
   rp1 = router_get_entry_from_string(&cp);
   test_assert(rp1);
@@ -555,16 +577,18 @@
   test_eq(rp1->ap_port, r1.ap_port);
   test_eq(rp1->dir_port, r1.dir_port);
   test_eq(rp1->bandwidth, r1.bandwidth);
-  test_assert(crypto_pk_cmp_keys(rp1->pkey, pk1) == 0);
-  test_assert(rp1->signing_pkey == NULL);
+  test_assert(crypto_pk_cmp_keys(rp1->onion_pkey, pk1) == 0);
+  test_assert(crypto_pk_cmp_keys(rp1->link_pkey, pk3) == 0);
+  test_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0);
   test_assert(rp1->exit_policy == NULL);
 
+#if 0
   strcpy(buf2, "router tor.tor.tor 9005 0 0 3000\n");
   strcat(buf2, pk2_str);
   strcat(buf2, "signing-key\n");
   strcat(buf2, pk1_str);
   strcat(buf2, "accept *:80\nreject 18.*:24\n\n");
-  test_assert(dump_router_to_string(buf, 2048, &r2)>0);
+  test_assert(dump_router_to_string(buf, 2048, &r2, pk2)>0);
   test_streq(buf, buf2);
 
   cp = buf;
@@ -575,8 +599,8 @@
   test_eq(rp2->ap_port, r2.ap_port);
   test_eq(rp2->dir_port, r2.dir_port);
   test_eq(rp2->bandwidth, r2.bandwidth);
-  test_assert(crypto_pk_cmp_keys(rp2->pkey, pk2) == 0);
-  test_assert(crypto_pk_cmp_keys(rp2->signing_pkey, pk1) == 0);
+  test_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0);
+  test_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0);
   test_eq(rp2->exit_policy->policy_type, EXIT_POLICY_ACCEPT);
   test_streq(rp2->exit_policy->string, "accept *:80");
   test_streq(rp2->exit_policy->address, "*");
@@ -586,6 +610,7 @@
   test_streq(rp2->exit_policy->next->address, "18.*");
   test_streq(rp2->exit_policy->next->port, "24");
   test_assert(rp2->exit_policy->next->next == NULL);
+#endif
 
   /* Okay, now for the directories. */
   dir1 = (directory_t*) tor_malloc(sizeof(directory_t));
@@ -593,7 +618,7 @@
   dir1->routers = (routerinfo_t**) tor_malloc(sizeof(routerinfo_t*)*2);
   dir1->routers[0] = &r1;
   dir1->routers[1] = &r2;
-  test_assert(! dump_signed_directory_to_string_impl(buf, 2048, dir1, pk1));
+  test_assert(! dump_signed_directory_to_string_impl(buf, 4096, dir1, pk1));
   /* puts(buf); */
   
   test_assert(! router_get_dir_from_string_impl(buf, &dir2, pk1));



More information about the tor-commits mailing list