summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2007-11-05 21:46:35 +0000
committerNick Mathewson <nickm@torproject.org>2007-11-05 21:46:35 +0000
commit9a20a64b62b149b102a487b6dc099fa310553f3c (patch)
tree4bf53c0aa275547f296b70fecdd72cca40c752a6
parent42f7ae3eaeb3d0f1067234f3acf9c0f0f4e6cf1a (diff)
downloadtor-9a20a64b62b149b102a487b6dc099fa310553f3c.tar.gz
tor-9a20a64b62b149b102a487b6dc099fa310553f3c.zip
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
-rw-r--r--doc/TODO4
-rw-r--r--src/or/buffers.c36
-rw-r--r--src/or/command.c64
-rw-r--r--src/or/connection_or.c66
-rw-r--r--src/or/or.h31
5 files changed, 165 insertions, 36 deletions
diff --git a/doc/TODO b/doc/TODO
index 893e3dee09..eec7dc7a49 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -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
diff --git a/src/or/buffers.c b/src/or/buffers.c
index d982330593..e4ee8dc5c7 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -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.
diff --git a/src/or/command.c b/src/or/command.c
index a1724dc709..d46012ade5 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -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;
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 93f4d5d7b1..0645e3eb4e 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -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;
-
- 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 */
-
- connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
+ var_cell_t *var_cell;
+
+ 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 */
- /* retrieve cell info from buf (create the host-order struct from the
- * network-order string) */
- cell_unpack(&cell, buf);
+ connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
- command_process_cell(&cell, conn);
+ /* retrieve cell info from buf (create the host-order struct from the
+ * network-order string) */
+ cell_unpack(&cell, buf);
- 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>
diff --git a/src/or/or.h b/src/or/or.h
index a054e24df6..abc3916581 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -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 ***************************/