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
This commit is contained in:
Nick Mathewson
2007-11-05 21:46:35 +00:00
parent 42f7ae3eae
commit 9a20a64b62
5 changed files with 164 additions and 35 deletions
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+47 -17
View File
@@ -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,27 +858,34 @@ 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:
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 (buf_datalen(conn->_base.inbuf) < CELL_NETWORK_SIZE) /* whole response
available? */
return 0; /* not yet */
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 */
connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
/* retrieve cell info from buf (create the host-order struct from the
* network-order string) */
cell_unpack(&cell, buf);
/* retrieve cell info from buf (create the host-order struct from the
* network-order string) */
cell_unpack(&cell, buf);
command_process_cell(&cell, conn);
goto loop; /* process the remainder of the buffer */
command_process_cell(&cell, conn);
}
}
}
/** Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>
+23 -8
View File
@@ -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 ***************************/