Commit 7a34cdf5 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

general cleanup and reabstraction, to prepare for tls


svn:r426
parent 99d1e493
Loading
Loading
Loading
Loading
+79 −87
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ connection_t *connection_new(int type) {
  conn->timestamp_lastread = now.tv_sec;
  conn->timestamp_lastwritten = now.tv_sec;

#ifndef TOR_TLS
  if (connection_speaks_cells(conn)) {
    conn->f_crypto = crypto_new_cipher_env(CONNECTION_CIPHER);
    if (!conn->f_crypto) {
@@ -105,6 +106,7 @@ connection_t *connection_new(int type) {
      return NULL;
    }
  }
#endif
  conn->done_sending = conn->done_receiving = 0;
  return conn;
}
@@ -120,10 +122,16 @@ void connection_free(connection_t *conn) {
    free(conn->dest_addr);

  if(connection_speaks_cells(conn)) {
    directory_set_dirty();
#ifdef TOR_TLS
    if (conn->SSL)
      crypt_SSL_free(conn->SSL);
#else
    if (conn->f_crypto)
      crypto_free_cipher_env(conn->f_crypto);
    if (conn->b_crypto)
      crypto_free_cipher_env(conn->b_crypto);
#endif
  }

  if (conn->pkey)
@@ -133,9 +141,6 @@ void connection_free(connection_t *conn) {
    log_fn(LOG_INFO,"closing fd %d.",conn->s);
    close(conn->s);
  }
  if(conn->type == CONN_TYPE_OR) {
    directory_set_dirty();
  }
  free(conn);
}

@@ -279,22 +284,52 @@ int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16
  return 0;
}

int connection_handle_read(connection_t *conn) {
  struct timeval now;

  my_gettimeofday(&now);
  conn->timestamp_lastread = now.tv_sec;

  switch(conn->type) {
    case CONN_TYPE_OR_LISTENER:
      return connection_or_handle_listener_read(conn);
    case CONN_TYPE_AP_LISTENER:
      return connection_ap_handle_listener_read(conn);
    case CONN_TYPE_DIR_LISTENER:
      return connection_dir_handle_listener_read(conn);
    default:

      if(connection_read_to_buf(conn) < 0) {
        if(conn->type == CONN_TYPE_DIR && conn->state == DIR_CONN_STATE_CONNECTING) {
           /* it's a directory server and connecting failed: forget about this router */
           /* XXX I suspect pollerr may make Windows not get to this point. :( */
           router_forget_router(conn->addr,conn->port); 
             /* FIXME i don't think router_forget_router works. */
         }
         return -1;
      }
      if(connection_process_inbuf(conn) < 0) {
        //log_fn(LOG_DEBUG,"connection_process_inbuf returned %d.",retval);
        return -1;
      }
      if(!connection_state_is_open(conn) && conn->receiver_bucket == 0) {
        log_fn(LOG_DEBUG,"receiver bucket reached 0 before handshake finished. Closing.");
        return -1;
      }
      return 0;
  } /* end switch */
}

int connection_read_to_buf(connection_t *conn) {
  int read_result;
  struct timeval now;
  int at_most = global_read_bucket;

  if(connection_speaks_cells(conn)) {
    assert(conn->receiver_bucket >= 0);
  }
  if(!connection_speaks_cells(conn)) {
  } else {
    assert(conn->receiver_bucket < 0);
  }

  my_gettimeofday(&now);

  conn->timestamp_lastread = now.tv_sec;

  if(conn->receiver_bucket >= 0 && at_most > conn->receiver_bucket)
    at_most = conn->receiver_bucket;

@@ -338,13 +373,44 @@ int connection_outbuf_too_full(connection_t *conn) {
}

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->outbuflen,
                   &conn->outbuf_flushlen, &conn->outbuf_datalen);
}

int connection_write_to_buf(char *string, int len, connection_t *conn) {
int connection_handle_write(connection_t *conn) {
  struct timeval now;
  int retval;

  if(connection_is_listener(conn)) {
    log_fn(LOG_DEBUG,"Got a listener socket. Can't happen!");
    return -1;
  }

  my_gettimeofday(&now);
  conn->timestamp_lastwritten = now.tv_sec;

#ifdef TOR_TLS
  if(connection_speaks_cells(conn)) {
    retval = flush_buf_SSL(conn->SSL, &conn->outbuf, &conn->outbuflen,
                           &conn->outbuf_flushlen, &conn->outbuf_datalen);
    ...

  } else
#endif
  {
    retval = flush_buf(conn->s, &conn->outbuf, &conn->outbuflen,
                       &conn->outbuf_flushlen, &conn->outbuf_datalen);
        /* conns in CONNECTING state will fall through... */

    if(retval == 0) { /* it's done flushing */
      retval = connection_finished_flushing(conn); /* ...and get handled here. */
    }
  }

  return retval;
}

int connection_write_to_buf(char *string, int len, connection_t *conn) {

  if(!len)
    return 0;
@@ -352,12 +418,10 @@ int connection_write_to_buf(char *string, int len, connection_t *conn) {
  if(conn->marked_for_close)
    return 0;

  conn->timestamp_lastwritten = now.tv_sec;

  if( (!connection_speaks_cells(conn)) ||
      (!connection_state_is_open(conn)) ||
      (options.LinkPadding == 0) ) {
    /* connection types other than or and op, or or/op not in 'open' state, should flush immediately */
    /* connection types other than or, or or not in 'open' state, should flush immediately */
    /* also flush immediately if we're not doing LinkPadding, since otherwise it will never flush */
    connection_start_writing(conn);
    conn->outbuf_flushlen += len;
@@ -397,78 +461,6 @@ int connection_state_is_open(connection_t *conn) {
  return 0;
}

void connection_send_cell(connection_t *conn) {
  cell_t cell;
  int bytes_in_full_flushlen;

  assert(0); /* this function has decayed. rewrite before using. */

  /* this function only gets called if options.LinkPadding is 1 */
  assert(options.LinkPadding == 1);

  assert(conn);

  if(!connection_speaks_cells(conn)) {
    /* this conn doesn't speak cells. do nothing. */
    return;
  }

  if(!connection_state_is_open(conn)) {
    /* it's not in 'open' state, all data should already be waiting to be flushed */
    assert(conn->outbuf_datalen == conn->outbuf_flushlen);
    return;
  }

#if 0 /* use to send evenly spaced cells, but not padding */
  if(conn->outbuf_datalen - conn->outbuf_flushlen >= sizeof(cell_t)) {
    conn->outbuf_flushlen += sizeof(cell_t); /* instruct it to send a cell */
    connection_start_writing(conn);
  }
#endif

  connection_increment_send_timeval(conn); /* update when we'll send the next cell */

  bytes_in_full_flushlen = conn->bandwidth / 100; /* 10ms worth */
  if(bytes_in_full_flushlen < 10*sizeof(cell_t))
    bytes_in_full_flushlen = 10*sizeof(cell_t); /* but at least 10 cells worth */

  if(conn->outbuf_flushlen > bytes_in_full_flushlen - sizeof(cell_t)) {
    /* if we would exceed bytes_in_full_flushlen by adding a new cell */
    return;
  }

  if(conn->outbuf_datalen - conn->outbuf_flushlen < sizeof(cell_t)) {
    /* we need to queue a padding cell first */
    memset(&cell,0,sizeof(cell_t));
    cell.command = CELL_PADDING;
    connection_write_cell_to_buf(&cell, conn);
  }

  /* The connection_write_cell_to_buf() call doesn't increase the flushlen
   * (if link padding is on). So if there isn't a whole cell waiting-but-
   * not-yet-flushed, we add a padding cell. Thus in any case the gap between
   * outbuf_datalen and outbuf_flushlen is at least sizeof(cell_t).
   */
  conn->outbuf_flushlen += sizeof(cell_t); /* instruct it to send a cell */
  connection_start_writing(conn);
}

void connection_increment_send_timeval(connection_t *conn) {
  /* add "1000000 * sizeof(cell_t) / conn->bandwidth" microseconds to conn->send_timeval */
  /* FIXME should perhaps use ceil() of this. For now I simply add 1. */

  tv_addms(&conn->send_timeval, 1+1000 * sizeof(cell_t) / conn->bandwidth);
}

void connection_init_timeval(connection_t *conn) {

  assert(conn);

  my_gettimeofday(&conn->send_timeval);

  connection_increment_send_timeval(conn);
}

int connection_send_destroy(aci_t aci, connection_t *conn) {
  cell_t cell;

+7 −4
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

extern or_options_t options; /* command-line and config-file options */

#ifndef TOR_TLS
static int or_handshake_op_send_keys(connection_t *conn);
static int or_handshake_op_finished_sending_keys(connection_t *conn);

@@ -15,8 +16,9 @@ static int or_handshake_client_send_auth(connection_t *conn);
static int or_handshake_server_process_auth(connection_t *conn);
static int or_handshake_server_process_nonce(connection_t *conn);

static void connection_or_set_open(connection_t *conn);
static void conn_or_init_crypto(connection_t *conn);
#endif
static void connection_or_set_open(connection_t *conn);

/*
 *
@@ -29,7 +31,6 @@ int connection_or_process_inbuf(connection_t *conn) {
  assert(conn && conn->type == CONN_TYPE_OR);

  if(conn->inbuf_reached_eof) {
    /* eof reached, kill it. */
    log_fn(LOG_DEBUG,"conn reached eof. Closing.");
    return -1;
  }
@@ -37,12 +38,14 @@ int connection_or_process_inbuf(connection_t *conn) {
//  log(LOG_DEBUG,"connection_or_process_inbuf(): state %d.",conn->state);

  switch(conn->state) {
#ifndef TOR_TLS
    case OR_CONN_STATE_CLIENT_AUTH_WAIT:
      return or_handshake_client_process_auth(conn);
    case OR_CONN_STATE_SERVER_AUTH_WAIT:
      return or_handshake_server_process_auth(conn);
    case OR_CONN_STATE_SERVER_NONCE_WAIT:
      return or_handshake_server_process_nonce(conn);
#endif
    case OR_CONN_STATE_OPEN:
      return connection_process_cell_from_inbuf(conn);
    default:
@@ -583,7 +586,6 @@ or_handshake_server_process_auth(connection_t *conn) {
    crypto_cipher_decrypt_init_cipher(conn->f_crypto);

    conn->state = OR_CONN_STATE_OPEN;
    connection_init_timeval(conn);
    connection_watch_events(conn, POLLIN);

    return connection_process_inbuf(conn); /* in case they sent some cells along with the keys */
@@ -654,10 +656,10 @@ static void
connection_or_set_open(connection_t *conn) {
  conn->state = OR_CONN_STATE_OPEN;
  directory_set_dirty();
  connection_init_timeval(conn);
  connection_watch_events(conn, POLLIN);
}

#ifndef TOR_TLS
static void 
conn_or_init_crypto(connection_t *conn) {
  //int x;
@@ -673,6 +675,7 @@ conn_or_init_crypto(connection_t *conn) {
  crypto_cipher_decrypt_init_cipher(conn->b_crypto);
    /* always encrypt with f, always decrypt with b */
}
#endif



+31 −115
Original line number Diff line number Diff line
@@ -244,83 +244,47 @@ void connection_start_writing(connection_t *conn) {
}

static void conn_read(int i) {
  int retval;
  connection_t *conn;

  if(!(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR)))
    return; /* this conn doesn't want to read */
    /* see http://www.greenend.org.uk/rjk/2001/06/poll.html for
     * discussion of POLLIN vs POLLHUP */

  conn = connection_array[i];
  assert(conn);
  //log_fn(LOG_DEBUG,"socket %d has something to read.",conn->s);

  if(
      /* XXX does POLLHUP also mean it's definitely broken? */
#ifdef MS_WINDOWS
  if (poll_array[i].revents & POLLERR) {
    retval = -1;
    goto error;
  }
#endif

  if (conn->type == CONN_TYPE_OR_LISTENER) {
    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 {
    retval = connection_read_to_buf(conn);
    if (retval < 0 && conn->type == CONN_TYPE_DIR && conn->state == DIR_CONN_STATE_CONNECTING) {
       /* it's a directory server and connecting failed: forget about this router */
       router_forget_router(conn->addr,conn->port); /* FIXME i don't think this function works. */
    }
    if (retval >= 0) { /* all still well */
      retval = connection_process_inbuf(conn);
//    log_fn(LOG_DEBUG,"connection_process_inbuf returned %d.",retval);
      if(retval >= 0 && !connection_state_is_open(conn) && conn->receiver_bucket == 0) {
        log(LOG_DEBUG,"conn_read(): receiver bucket reached 0 before handshake finished. Closing.");
        retval = -1;
      }
    }
  }

#ifdef MS_WINDOWS
 error:
      (poll_array[i].revents & POLLERR) ||
#endif
  if(retval < 0) { /* this connection is broken. remove it */
    connection_handle_read(conn) < 0)
    {
      /* this connection is broken. remove it */
      log_fn(LOG_INFO,"%s connection broken, removing.", conn_type_to_string[conn->type]); 
      connection_remove(conn);
      connection_free(conn);
    if(i<nfds) { /* we just replaced the one at i with a new one.
                    process it too. */
      if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR))
        /* something to read */
      if(i<nfds) { /* we just replaced the one at i with a new one. process it too. */
        conn_read(i);
      }
    }
}

static void conn_write(int i) {
  int retval;
  connection_t *conn;

  if(!(poll_array[i].revents & POLLOUT))
    return; /* this conn doesn't want to write */

  conn = connection_array[i];
  //log_fn(LOG_DEBUG,"socket %d wants to write.",conn->s);

  if(connection_is_listener(conn)) {
    log_fn(LOG_DEBUG,"Got a listener socket. Can't happen!");
    retval = -1;
  } else {
    /* else it's an OP, OR, or exit */
    retval = connection_flush_buf(conn); /* conns in CONNECTING state will fall through... */
    if(retval == 0) { /* it's done flushing */
      retval = connection_finished_flushing(conn); /* ...and get handled here. */
    }
  }

  if(retval < 0) { /* this connection is broken. remove it. */
  if(connection_handle_write(conn) < 0) { /* this connection is broken. remove it. */
    log_fn(LOG_DEBUG,"%s connection broken, removing.", conn_type_to_string[conn->type]);
    connection_remove(conn);
    connection_free(conn);
    if(i<nfds) { /* we just replaced the one at i with a new one.
                    process it too. */
      if(poll_array[i].revents & POLLOUT) /* something to write */
    if(i<nfds) { /* we just replaced the one at i with a new one. process it too. */
        conn_write(i);
    }
  }
@@ -346,7 +310,7 @@ static void check_conn_marked(int i) {
  }
}

static int prepare_for_poll(int *timeout) {
static int prepare_for_poll(void) {
  int i;
//  connection_t *conn = NULL;
  connection_t *tmpconn;
@@ -434,45 +398,9 @@ static int prepare_for_poll(int *timeout) {
    current_second = now.tv_sec; /* remember which second it is, for next time */
  }

  *timeout = 1000 - (now.tv_usec / 1000); /* how many milliseconds til the next second? */

  return 0;
  return (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */
}



/* Link padding stuff left here for fun. Not used now. */
#if 0
  if(options.LinkPadding) {
    /* now check which conn wants to speak soonest */
    for(i=0;i<nfds;i++) {
      tmpconn = connection_array[i];
      if(!connection_speaks_cells(tmpconn))
        continue; /* this conn type doesn't send cells */
      if(!connection_state_is_open(tmpconn))
        continue; /* only conns in state 'open' have a valid send_timeval */ 
      while(tv_cmp(&tmpconn->send_timeval,&now) <= 0) { /* send_timeval has already passed, let it send a cell */
        connection_send_cell(tmpconn);
      }
      if(!conn || tv_cmp(&tmpconn->send_timeval, &soonest) < 0) { /* this is the best choice so far */
        conn = tmpconn;
        soonest.tv_sec = conn->send_timeval.tv_sec;
        soonest.tv_usec = conn->send_timeval.tv_usec;
      }
    }

    if(conn) { /* we might want to set *timeout sooner */
      ms_until_conn = (soonest.tv_sec - now.tv_sec)*1000 +
                    (soonest.tv_usec - now.tv_usec)/1000;
//      log(LOG_DEBUG,"prepare_for_poll(): conn %d times out in %d ms.",conn->s, ms_until_conn);
      if(ms_until_conn < *timeout) { /* use the new one */
//        log(LOG_DEBUG,"prepare_for_poll(): conn %d soonest, in %d ms.",conn->s,ms_until_conn);
        *timeout = ms_until_conn;
      }
    }
  }
#endif

static int do_main_loop(void) {
  int i;
  int timeout;
@@ -516,7 +444,7 @@ static int do_main_loop(void) {

  /* start up the necessary connections based on which ports are
   * non-zero. This is where we try to connect to all the other ORs,
   * and start the listeners
   * and start the listeners.
   */
  retry_all_connections((uint16_t) options.ORPort,
                        (uint16_t) options.APPort,
@@ -543,17 +471,10 @@ static int do_main_loop(void) {
      please_reap_children = 0;
    }
#endif /* signal stuff */
    if(prepare_for_poll(&timeout) < 0) {
      log(LOG_DEBUG,"do_main_loop(): prepare_for_poll failed, exiting.");
      return -1;
    }
    /* now timeout is the value we'll hand to poll. It's either -1, meaning
     * don't timeout, else it indicates the soonest event (either the
     * one-second rollover for refilling receiver buckets, or the soonest
     * conn that needs to send a cell)
     */

    /* poll until we have an event, or it's time to do something */
    timeout = prepare_for_poll();

    /* poll until we have an event, or the second ends */
    poll_result = poll(poll_array, nfds, timeout);

#if 0 /* let catch() handle things like ^c, and otherwise don't worry about it */
@@ -567,15 +488,10 @@ static int do_main_loop(void) {
    if(poll_result > 0) { /* we have at least one connection to deal with */
      /* do all the reads and errors first, so we can detect closed sockets */
      for(i=0;i<nfds;i++)
        if(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR))
          /* something to read, or an error. */
        conn_read(i); /* this also blows away broken connections */
/* see http://www.greenend.org.uk/rjk/2001/06/poll.html for discussion
 * of POLLIN vs POLLHUP */

      /* then do the writes */
      for(i=0;i<nfds;i++)
        if(poll_array[i].revents & POLLOUT) /* something to write */
        conn_write(i);

      /* any of the conns need to be closed now? */
+52 −45
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@
#include "../common/log.h"
#include "../common/util.h"

#define RECOMMENDED_SOFTWARE_VERSIONS "0.0.2pre6,0.0.2pre7"
#define RECOMMENDED_SOFTWARE_VERSIONS "0.0.2pre8"

#define MAXCONNECTIONS 1000 /* upper bound on max connections.
                              can be lowered by config file */
@@ -131,6 +131,7 @@
#define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION
#define CPUWORKER_TASK_HANDSHAKE CPUWORKER_STATE_BUSY_HANDSHAKE

#ifndef TOR_TLS
/* how to read these states:
 * foo_CONN_STATE_bar_baz:
 * "I am acting as a bar, currently in stage baz of talking with a foo."
@@ -145,6 +146,11 @@
#define OR_CONN_STATE_SERVER_SENDING_AUTH 7 /* writing auth and nonce */
#define OR_CONN_STATE_SERVER_NONCE_WAIT 8 /* waiting for confirmation of nonce */
#define OR_CONN_STATE_OPEN 9 /* ready to send/receive cells. */
#else
#define OR_CONN_STATE_CONNECTING 0 /* waiting for connect() to finish */
#define OR_CONN_STATE_HANDSHAKING 1 /* SSL is handshaking, not done yet */
#define OR_CONN_STATE_OPEN 2 /* ready to send/receive cells. */
#endif

#define EXIT_CONN_STATE_RESOLVING 0 /* waiting for response from dns farm */
#define EXIT_CONN_STATE_CONNECTING 1 /* waiting for connect() to finish */
@@ -272,73 +278,72 @@ typedef struct {

struct connection_t { 

/* Used by all types: */

  uint8_t type;
  int state;
  uint8_t wants_to_read;
  uint8_t state;
  uint8_t wants_to_read; /* should we start reading again once
                          * the bandwidth throttler allows it?
                          */
  int s; /* our socket */
  int poll_index;
  int marked_for_close;
  int poll_index; /* index of this conn into the poll_array */
  int marked_for_close; /* should we close this conn on the next
                         * iteration of the main loop?
                         */

  char *inbuf;
  int inbuflen;
  int inbuf_datalen;
  int inbuf_reached_eof;
  long timestamp_lastread;
  int inbuflen; /* how many bytes are alloc'ed for inbuf? */
  int inbuf_datalen; /* how many bytes of data are on 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? */
  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;

  long timestamp_created;
  long timestamp_lastwritten; /* when was the last time poll() said we could write? */

/* used by OR and OP: */
  long timestamp_created; /* when was this connection_t created? */

  uint32_t bandwidth; /* connection bandwidth */
  uint32_t bandwidth; /* connection bandwidth. Set to -1 for non-OR conns. */
  int receiver_bucket; /* when this hits 0, stop receiving. Every second we
                        * add 'bandwidth' to this, capping it at 10*bandwidth.
			* Set to -1 for non-OR conns.
                        */
  struct timeval send_timeval; /* for determining when to send the next cell */

  uint32_t addr; /* these two uniquely identify a router. Both in host order. */
  uint16_t port; /* if non-zero, they identify the guy on the other end
                  * of the connection. */
  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 */

#ifndef TOR_TLS
/* Used only by OR connections: */

  /* link encryption */
  crypto_cipher_env_t *f_crypto;
  crypto_cipher_env_t *b_crypto;

//  struct timeval lastsend; /* time of last transmission to the client */
//  struct timeval interval; /* transmission interval */

  uint32_t addr; /* these two uniquely identify a router. Both in host order. */
  uint16_t port;
  char nonce[8];
#endif

/* used by exit and ap: */
/* Used only by edge connections: */
  char stream_id[STREAM_ID_SIZE];
  struct connection_t *next_stream;
  struct connection_t *next_stream; /* points to the next stream at this edge, if any */
  struct crypt_path_t *cpath_layer; /* a pointer to which node in the circ this conn exits at */
  int package_window;
  int deliver_window;
  int done_sending;
  int done_receiving;
  int package_window; /* how many more relay cells can i send into the circuit? */
  int deliver_window; /* how many more relay cells can end at me? */

/* Used by ap: */
  char socks_version; 
  char read_username;
  int done_sending; /* for half-open connections; not used currently */
  int done_receiving;

/* Used by exit and ap: */
  char *dest_addr;
/* Used only by AP connections: */
  char socks_version; /* what socks version are they speaking at me? */
  char read_username; /* have i read the username yet? */
  char *dest_addr; /* what address and port are this stream's destination? */
  uint16_t dest_port; /* host order */

/* Used by everyone */
  char *address; /* strdup into this, because free_connection frees it */
/* Used for cell connections */
  crypto_pk_env_t *pkey; /* public RSA key for the other side */

/* Used while negotiating OR/OR connections */
  char nonce[8];

/* Used by worker connections */
/* Used only by worker connections: */
  int num_processed; /* statistics kept by dns worker */
  struct circuit_t *circ; /* by cpu worker to know who he's working for */
};
@@ -392,7 +397,7 @@ struct crypt_path_t {
  uint32_t addr;
  uint16_t port;

  char state;
  uint8_t state;
#define CPATH_STATE_CLOSED 0
#define CPATH_STATE_AWAITING_KEYS 1
#define CPATH_STATE_OPEN 2
@@ -429,9 +434,9 @@ struct circuit_t {

  char onionskin[DH_ONIONSKIN_LEN]; /* for storage while onionskin pending */
  long timestamp_created;
  char dirty; /* whether this circuit has been used yet */
  uint8_t dirty; /* whether this circuit has been used yet */

  int state;
  uint8_t state;

//  unsigned char *onion; /* stores the onion when state is CONN_STATE_OPEN_WAIT */
//  uint32_t onionlen; /* total onion length */
@@ -612,6 +617,7 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st
/* start all connections that should be up but aren't */
int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16_t dir_listenport);

int connection_handle_read(connection_t *conn);
int connection_read_to_buf(connection_t *conn);

int connection_fetch_from_buf(char *string, int len, connection_t *conn);
@@ -620,6 +626,7 @@ int connection_outbuf_too_full(connection_t *conn);
int connection_find_on_inbuf(char *string, int len, connection_t *conn);
int connection_wants_to_flush(connection_t *conn);
int connection_flush_buf(connection_t *conn);
int connection_handle_write(connection_t *conn);

int connection_write_to_buf(char *string, int len, connection_t *conn);
void connection_send_cell(connection_t *conn);