Commit 9a20a64b authored by Nick Mathewson's avatar Nick Mathewson 🐘
Browse files

r16438@catbus: nickm | 2007-11-05 16:45:45 -0500

 Initial code for variable-length cells. CERT and VERSIONS  need to use them.


svn:r12390
parent 42f7ae3e
Loading
Loading
Loading
Loading
+2 −2
Changes for doc/TODO: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -30,8 +30,8 @@ Things we'd like to do in 0.2.0.x:
        act-on-netinfo logic separate so it can get called _after_
        negotiation.
      - Variable-length cells
        - Add structure
        - Add parse logic
        o Add structure
        o Add parse logic
        - Make CERT and VERSIONS variable.
      - CERT cells
        - functions to parse x509 certs
+36 −0
Changes for src/or/buffers.c: 36 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -993,6 +993,42 @@ fetch_from_buf(char *string, size_t string_len, buf_t *buf)
  return buf->datalen;
}

/** DOCDOC Returns 0 on "not a var-length cell."; 1 whether it's all here
 * yet or not. */
int
fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out)
{
  char hdr[VAR_CELL_HEADER_SIZE];
  var_cell_t *result;
  uint8_t command;
  uint16_t length;
  check();
  *out = NULL;
  if (buf->datalen < VAR_CELL_HEADER_SIZE)
    return 0;
  peek_from_buf(hdr, sizeof(hdr), buf);

  command = *(uint8_t*)(hdr+2);
  if (!(CELL_COMMAND_IS_VAR_LENGTH(command)))
    return 0;

  length = ntohs(get_uint16(hdr+3));
  if (buf->datalen < (size_t)(VAR_CELL_HEADER_SIZE+length))
    return 1;
  result = tor_malloc(sizeof(var_cell_t)+length-1);
  result->command = command;
  result->payload_len = length;
  result->circ_id = ntohs(*(uint16_t*)hdr);

  buf_remove_from_front(buf, VAR_CELL_HEADER_SIZE);
  peek_from_buf(result->payload, length, buf);
  buf_remove_from_front(buf, length);
  check();

  *out = result;
  return 1;
}

/** Move up to *<b>buf_flushlen</b> bytes from <b>buf_in</b> to
 * <b>buf_out</b>, and modify *<b>buf_flushlen</b> appropriately.
 * Return the number of bytes actually copied.
+56 −8
Changes for src/or/command.c: 56 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -35,9 +35,10 @@ static void command_process_create_cell(cell_t *cell, or_connection_t *conn);
static void command_process_created_cell(cell_t *cell, or_connection_t *conn);
static void command_process_relay_cell(cell_t *cell, or_connection_t *conn);
static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn);
static void command_process_versions_cell(cell_t *cell, or_connection_t *conn);
static void command_process_versions_cell(var_cell_t *cell,
                                          or_connection_t *conn);
static void command_process_netinfo_cell(cell_t *cell, or_connection_t *conn);
static void command_process_cert_cell(cell_t *cell, or_connection_t *conn);
static void command_process_cert_cell(var_cell_t *cell, or_connection_t *conn);
static void command_process_link_auth_cell(cell_t *cell,or_connection_t *conn);

#ifdef KEEP_TIMING_STATS
@@ -143,16 +144,14 @@ command_process_cell(cell_t *cell, or_connection_t *conn)
      PROCESS_CELL(destroy, cell, conn);
      break;
    case CELL_VERSIONS:
      ++stats_n_versions_cells_processed;
      PROCESS_CELL(versions, cell, conn);
      tor_fragile_assert();
      break;
    case CELL_NETINFO:
      ++stats_n_netinfo_cells_processed;
      PROCESS_CELL(netinfo, cell, conn);
      break;
    case CELL_CERT:
      ++stats_n_cert_cells_processed;
      PROCESS_CELL(cert, cell, conn);
      tor_fragile_assert();
      break;
    case CELL_LINK_AUTH:
      ++stats_n_link_auth_cells_processed;
@@ -165,6 +164,55 @@ command_process_cell(cell_t *cell, or_connection_t *conn)
  }
}

/** Process a <b>cell</b> that was just received on <b>conn</b>. Keep internal
 * statistics about how many of each cell we've processed so far
 * this second, and the total number of microseconds it took to
 * process each type of cell.
 */
void
command_process_var_cell(var_cell_t *cell, or_connection_t *conn)
{
#ifdef KEEP_TIMING_STATS
  /* how many of each cell have we seen so far this second? needs better
   * name. */
  static int num_versions=0, num_cert=0;

  time_t now = time(NULL);

  if (now > current_second) { /* the second has rolled over */
    /* print stats */
    log_info(LD_OR,
             "At end of second: %d versions (%d ms), %d cert (%d ms)",
             num_versions, versions_time/1000,
             cert, cert_time/1000);

    num_versions = num_cert = 0;
    versions_time = cert_time = 0;

    /* remember which second it is, for next time */
    current_second = now;
  }
#endif

  /*XXXX020 reject all when not handshaking. */
  switch (cell->command) {
    case CELL_VERSIONS:
      ++stats_n_versions_cells_processed;
      PROCESS_CELL(versions, cell, conn);
      break;
    case CELL_CERT:
      ++stats_n_cert_cells_processed;
      PROCESS_CELL(cert, cell, conn);
      break;
    default:
      log_warn(LD_BUG,
               "Variable-length cell of unknown type (%d) received.",
               cell->command);
      tor_fragile_assert();
      break;
  }
}

/** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a
 * new circuit with the p_circ_id specified in cell. Put the circuit in state
 * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
@@ -404,7 +452,7 @@ command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
/** Process a 'versions' cell.  The current link protocol version must be 0
 * to indicate that no version has yet been negotiated. DOCDOC say more. */
static void
command_process_versions_cell(cell_t *cell, or_connection_t *conn)
command_process_versions_cell(var_cell_t *cell, or_connection_t *conn)
{
  uint16_t versionslen;
  int highest_supported_version = 0;
@@ -560,7 +608,7 @@ connection_or_act_on_netinfo(or_connection_t *conn)
}

static void
command_process_cert_cell(cell_t *cell, or_connection_t *conn)
command_process_cert_cell(var_cell_t *cell, or_connection_t *conn)
{
  (void) cell;
  (void) conn;
+35 −5
Changes for src/or/connection_or.c: 35 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -147,6 +147,22 @@ cell_unpack(cell_t *dest, const char *src)
  memcpy(dest->payload, src+3, CELL_PAYLOAD_SIZE);
}

/** DOCDOC */
void
var_cell_pack_header(var_cell_t *cell, char *hdr_out)
{
  *(uint16_t*)(hdr_out) = htons(cell->circ_id);
  *(uint8_t*)(hdr_out+2) = cell->command;
  set_uint16(hdr_out+3, htons(cell->payload_len));
}

/** DOCDOC */
void
var_cell_free(var_cell_t *cell)
{
  tor_free(cell);
}

int
connection_or_reached_eof(or_connection_t *conn)
{
@@ -825,6 +841,13 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn)
  connection_write_to_buf(networkcell.body, CELL_NETWORK_SIZE, TO_CONN(conn));
}

/** DOCDOC */
static int
connection_fetch_var_cell_from_buf(or_connection_t *conn, var_cell_t **out)
{
  return fetch_var_cell_from_buf(conn->_base.inbuf, out);
}

/** Process cells from <b>conn</b>'s inbuf.
 *
 * Loop: while inbuf contains a cell, pull it off the inbuf, unpack it,
@@ -835,14 +858,21 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn)
static int
connection_or_process_cells_from_inbuf(or_connection_t *conn)
{
  char buf[CELL_NETWORK_SIZE];
  cell_t cell;
  var_cell_t *var_cell;

 loop:
  while (1) {
    log_debug(LD_OR,
              "%d: starting, inbuf_datalen %d (%d pending in tls object).",
              conn->_base.s,(int)buf_datalen(conn->_base.inbuf),
              tor_tls_get_pending_bytes(conn->tls));
    if (connection_fetch_var_cell_from_buf(conn, &var_cell)) {
      if (!var_cell)
        return 0; /* not yet. */
      command_process_var_cell(var_cell, conn);
      var_cell_free(var_cell);
    } else {
      char buf[CELL_NETWORK_SIZE];
      cell_t cell;
      if (buf_datalen(conn->_base.inbuf) < CELL_NETWORK_SIZE) /* whole response
                                                                 available? */
        return 0; /* not yet */
@@ -854,8 +884,8 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn)
      cell_unpack(&cell, buf);

      command_process_cell(&cell, conn);

  goto loop; /* process the remainder of the buffer */
    }
  }
}

/** Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>
+23 −8
Changes for src/or/or.h: 23 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -660,6 +660,9 @@ typedef enum {
#define CELL_CERT 9
#define CELL_LINK_AUTH 10

#define CELL_COMMAND_IS_VAR_LENGTH(x) \
  ((x) == CELL_CERT || (x) == CELL_VERSIONS)

/** How long to test reachability before complaining to the user. */
#define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60)

@@ -701,28 +704,36 @@ typedef enum {
/** Number of bytes in a cell transmitted over the network. */
#define CELL_NETWORK_SIZE 512

#define VAR_CELL_HEADER_SIZE 5

/** Number of bytes in a relay cell's header (not including general cell
 * header). */
#define RELAY_HEADER_SIZE (1+2+2+4+2)
/** Largest number of bytes that can fit in a relay cell payload. */
#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE)

typedef struct cell_t cell_t;
/** Parsed onion routing cell.  All communication between nodes
 * is via cells. */
struct cell_t {
typedef struct cell_t {
  uint16_t circ_id; /**< Circuit which received the cell. */
  uint8_t command; /**< Type of the cell: one of PADDING, CREATE, RELAY,
                    * or DESTROY. */
  uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE,
                    * CELL_DESTROY, etc */
  char payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */
};
} cell_t;

/** Parsed variable-length onion routing cell. */
typedef struct var_cell_t {
  uint8_t command;
  uint16_t circ_id;
  uint16_t payload_len;
  char payload[1];
} var_cell_t;

typedef struct packed_cell_t packed_cell_t;
/** A cell as packed for writing to the network. */
struct packed_cell_t {
typedef struct packed_cell_t {
  struct packed_cell_t *next; /**< Next cell queued on this circuit. */
  char body[CELL_NETWORK_SIZE]; /**< Cell as packed for network. */
};
} packed_cell_t;

/** A queue of cells on a circuit, waiting to be added to the
 * or_connection_t's outbuf. */
@@ -2387,6 +2398,7 @@ int write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state,
                      const char *data, size_t data_len, int done);
int move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
int fetch_from_buf(char *string, size_t string_len, buf_t *buf);
int fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out);
int fetch_from_buf_http(buf_t *buf,
                        char **headers_out, size_t max_headerlen,
                        char **body_out, size_t *body_used, size_t max_bodylen,
@@ -2546,6 +2558,7 @@ int connection_ap_handshake_attach_circuit(edge_connection_t *conn);
/********************************* command.c ***************************/

void command_process_cell(cell_t *cell, or_connection_t *conn);
void command_process_var_cell(var_cell_t *cell, or_connection_t *conn);
void connection_or_act_on_netinfo(or_connection_t *conn);

extern uint64_t stats_n_padding_cells_processed;
@@ -2786,6 +2799,8 @@ int connection_or_compute_link_auth_hmac(or_connection_t *conn,
                                         char *hmac_out);

void cell_pack(packed_cell_t *dest, const cell_t *src);
void var_cell_pack_header(var_cell_t *cell, char *hdr_out);
void var_cell_free(var_cell_t *cell);

/********************************* control.c ***************************/