diff options
author | Nick Mathewson <nickm@torproject.org> | 2007-11-05 21:46:35 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2007-11-05 21:46:35 +0000 |
commit | 9a20a64b62b149b102a487b6dc099fa310553f3c (patch) | |
tree | 4bf53c0aa275547f296b70fecdd72cca40c752a6 /src | |
parent | 42f7ae3eaeb3d0f1067234f3acf9c0f0f4e6cf1a (diff) | |
download | tor-9a20a64b62b149b102a487b6dc099fa310553f3c.tar tor-9a20a64b62b149b102a487b6dc099fa310553f3c.tar.gz |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/or/buffers.c | 36 | ||||
-rw-r--r-- | src/or/command.c | 64 | ||||
-rw-r--r-- | src/or/connection_or.c | 66 | ||||
-rw-r--r-- | src/or/or.h | 31 |
4 files changed, 163 insertions, 34 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c index d98233059..e4ee8dc5c 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 a1724dc70..d46012ade 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 93f4d5d7b..0645e3eb4 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 a054e24df..abc391658 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 ***************************/ |