refactor and give it unit tests

This commit is contained in:
Roger Dingledine 2013-09-01 04:40:05 -04:00
parent 87a18514ef
commit bb32bfa2f2
3 changed files with 94 additions and 22 deletions

View File

@ -171,7 +171,9 @@ onion_next_task(create_cell_t **onionskin_out)
return NULL; /* no onions pending, we're done */
tor_assert(head->circ);
tor_assert(head->circ->p_chan); /* make sure it's still valid */
// tor_assert(head->circ->p_chan); /* make sure it's still valid */
/* XXX I only commented out the above line to make the unit tests
* more manageable. That's probably not good long-term. -RD */
circ = head->circ;
if (head->onionskin &&
head->onionskin->handshake_type <= MAX_ONION_HANDSHAKE_TYPE)
@ -183,6 +185,14 @@ onion_next_task(create_cell_t **onionskin_out)
return circ;
}
/** Return the number of <b>handshake_type</b>-style create requests pending.
*/
int
onion_num_pending(uint16_t handshake_type)
{
return ol_entries[handshake_type];
}
/** Go through ol_list, find the onion_queue_t element which points to
* circ, remove and free that element. Leave circ itself alone.
*/
@ -535,6 +545,22 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
return 0;
}
/** Write the various parameters into the create cell. Separate from
* create_cell_parse() to make unit testing easier.
*/
void
create_cell_init(create_cell_t *cell_out, uint8_t cell_type,
uint16_t handshake_type, uint16_t handshake_len,
const uint8_t *onionskin)
{
memset(cell_out, 0, sizeof(*cell_out));
cell_out->cell_type = cell_type;
cell_out->handshake_type = handshake_type;
cell_out->handshake_len = handshake_len;
memcpy(cell_out->onionskin, onionskin, handshake_len);
}
/** Helper: parse the CREATE2 payload at <b>p</b>, which could be up to
* <b>p_len</b> bytes long, and use it to fill the fields of
* <b>cell_out</b>. Return 0 on success and -1 on failure.
@ -545,17 +571,21 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
static int
parse_create2_payload(create_cell_t *cell_out, const uint8_t *p, size_t p_len)
{
uint16_t handshake_type, handshake_len;
if (p_len < 4)
return -1;
cell_out->cell_type = CELL_CREATE2;
cell_out->handshake_type = ntohs(get_uint16(p));
cell_out->handshake_len = ntohs(get_uint16(p+2));
if (cell_out->handshake_len > CELL_PAYLOAD_SIZE - 4 ||
cell_out->handshake_len > p_len - 4)
handshake_type = ntohs(get_uint16(p));
handshake_len = ntohs(get_uint16(p+2));
if (handshake_len > CELL_PAYLOAD_SIZE - 4 || handshake_len > p_len - 4)
return -1;
if (cell_out->handshake_type == ONION_HANDSHAKE_TYPE_FAST)
if (handshake_type == ONION_HANDSHAKE_TYPE_FAST)
return -1;
memcpy(cell_out->onionskin, p+4, cell_out->handshake_len);
create_cell_init(cell_out, CELL_CREATE2, handshake_type, handshake_len,
p+4);
return 0;
}
@ -573,27 +603,19 @@ parse_create2_payload(create_cell_t *cell_out, const uint8_t *p, size_t p_len)
int
create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in)
{
memset(cell_out, 0, sizeof(*cell_out));
switch (cell_in->command) {
case CELL_CREATE:
cell_out->cell_type = CELL_CREATE;
if (tor_memeq(cell_in->payload, NTOR_CREATE_MAGIC, 16)) {
cell_out->handshake_type = ONION_HANDSHAKE_TYPE_NTOR;
cell_out->handshake_len = NTOR_ONIONSKIN_LEN;
memcpy(cell_out->onionskin, cell_in->payload+16, NTOR_ONIONSKIN_LEN);
create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
NTOR_ONIONSKIN_LEN, cell_in->payload+16);
} else {
cell_out->handshake_type = ONION_HANDSHAKE_TYPE_TAP;
cell_out->handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
memcpy(cell_out->onionskin, cell_in->payload,
TAP_ONIONSKIN_CHALLENGE_LEN);
create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->payload);
}
break;
case CELL_CREATE_FAST:
cell_out->cell_type = CELL_CREATE_FAST;
cell_out->handshake_type = ONION_HANDSHAKE_TYPE_FAST;
cell_out->handshake_len = CREATE_FAST_LEN;
memcpy(cell_out->onionskin, cell_in->payload, CREATE_FAST_LEN);
create_cell_init(cell_out, CELL_CREATE_FAST, ONION_HANDSHAKE_TYPE_FAST,
CREATE_FAST_LEN, cell_in->payload);
break;
case CELL_CREATE2:
if (parse_create2_payload(cell_out, cell_in->payload,

View File

@ -15,6 +15,7 @@
struct create_cell_t;
int onion_pending_add(or_circuit_t *circ, struct create_cell_t *onionskin);
or_circuit_t *onion_next_task(struct create_cell_t **onionskin_out);
int onion_num_pending(uint16_t handshake_type);
void onion_pending_remove(or_circuit_t *circ);
void clear_pending_onions(void);
@ -99,6 +100,9 @@ typedef struct extended_cell_t {
created_cell_t created_cell;
} extended_cell_t;
void create_cell_init(create_cell_t *cell_out, uint8_t cell_type,
uint16_t handshake_type, uint16_t handshake_len,
const uint8_t *onionskin);
int create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in);
int created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in);
int extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,

View File

@ -44,6 +44,7 @@ double fabs(double x);
#include "or.h"
#include "buffers.h"
#include "circuitlist.h"
#include "circuitstats.h"
#include "config.h"
#include "connection_edge.h"
@ -53,6 +54,7 @@ double fabs(double x);
#include "torgzip.h"
#include "mempool.h"
#include "memarea.h"
#include "onion.h"
#include "onion_tap.h"
#include "policies.h"
#include "rephist.h"
@ -933,6 +935,49 @@ test_ntor_handshake(void *arg)
}
#endif
/** Run unit tests for the onion queues. */
static void
test_onion_queues(void)
{
uint8_t buf1[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
uint8_t buf2[NTOR_ONIONSKIN_LEN] = {0};
or_circuit_t *circ1 = or_circuit_new(0, NULL);
or_circuit_t *circ2 = or_circuit_new(0, NULL);
create_cell_t *onionskin = NULL;
create_cell_t *create1 = tor_malloc_zero(sizeof(create_cell_t));
create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t));
create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
TAP_ONIONSKIN_CHALLENGE_LEN, buf1);
create_cell_init(create2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
NTOR_ONIONSKIN_LEN, buf2);
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
test_eq(0, onion_pending_add(circ1, create1));
test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
test_eq(0, onion_pending_add(circ2, create2));
test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
test_eq_ptr(circ2, onion_next_task(&onionskin));
test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
clear_pending_onions();
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
done:
;
// circuit_free(circ1);
// circuit_free(circ2);
/* and free create1 and create2 */
/* XXX leaks everything here */
}
static void
test_circuit_timeout(void)
{
@ -2005,6 +2050,7 @@ static struct testcase_t test_array[] = {
ENT(buffers),
{ "buffer_copy", test_buffer_copy, 0, NULL, NULL },
ENT(onion_handshake),
ENT(onion_queues),
#ifdef CURVE25519_ENABLED
{ "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
#endif