/** Perform supported SOCKS 4 commands */ static void test_socks_4_supported_commands(void *ptr) { SOCKS_TEST_INIT(); tt_int_op(0,OP_EQ, buf_datalen(buf)); /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4370 */ ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x03\x00"); tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); tt_int_op(4,OP_EQ, socks->socks_version); tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */ tt_int_op(SOCKS_COMMAND_CONNECT,OP_EQ, socks->command); tt_str_op("2.2.2.3",OP_EQ, socks->address); tt_int_op(4370,OP_EQ, socks->port); tt_assert(socks->got_auth == 0); tt_assert(! socks->username); tt_int_op(0,OP_EQ, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4369 with userid*/ ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x04me\x00"); tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); tt_int_op(4,OP_EQ, socks->socks_version); tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */ tt_int_op(SOCKS_COMMAND_CONNECT,OP_EQ, socks->command); tt_str_op("2.2.2.4",OP_EQ, socks->address); tt_int_op(4370,OP_EQ, socks->port); tt_assert(socks->got_auth == 1); tt_assert(socks->username); tt_int_op(2,OP_EQ, socks->usernamelen); tt_mem_op("me",OP_EQ, socks->username, 2); tt_int_op(0,OP_EQ, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 4a Send RESOLVE [F0] request for torproject.org */ ADD_DATA(buf, "\x04\xF0\x01\x01\x00\x00\x00\x02me\x00torproject.org\x00"); tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); tt_int_op(4,OP_EQ, socks->socks_version); tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */ tt_str_op("torproject.org",OP_EQ, socks->address); tt_int_op(0,OP_EQ, buf_datalen(buf)); done: ; }
static void test_buffers_zlib_fin_at_chunk_end(void *arg) { char *msg = NULL; char *contents = NULL; char *expanded = NULL; buf_t *buf = NULL; tor_zlib_state_t *zlib_state = NULL; size_t out_len, in_len; size_t sz, headerjunk; (void) arg; buf = buf_new_with_capacity(128); /* will round up */ sz = buf_get_default_chunk_size(buf); msg = tor_malloc_zero(sz); write_to_buf(msg, 1, buf); tt_assert(buf->head); /* Fill up the chunk so the zlib stuff won't fit in one chunk. */ tt_uint_op(buf->head->memlen, OP_LT, sz); headerjunk = buf->head->memlen - 7; write_to_buf(msg, headerjunk-1, buf); tt_uint_op(buf->head->datalen, OP_EQ, headerjunk); tt_uint_op(buf_datalen(buf), OP_EQ, headerjunk); /* Write an empty string, with finalization on. */ zlib_state = tor_zlib_new(1, ZLIB_METHOD, HIGH_COMPRESSION); tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), OP_EQ, 0); in_len = buf_datalen(buf); contents = tor_malloc(in_len); tt_int_op(fetch_from_buf(contents, in_len, buf), OP_EQ, 0); tt_uint_op(in_len, OP_GT, headerjunk); tt_int_op(0, OP_EQ, tor_gzip_uncompress(&expanded, &out_len, contents + headerjunk, in_len - headerjunk, ZLIB_METHOD, 1, LOG_WARN)); tt_int_op(out_len, OP_EQ, 0); tt_assert(expanded); done: buf_free(buf); tor_zlib_free(zlib_state); tor_free(contents); tor_free(expanded); tor_free(msg); }
static int process_read_stdout_replacement(process_t *process, buf_t *buffer) { (void)process; static int times_called = 0; /* Generate some dummy CMETHOD lines the first 5 times. The 6th time, send 'CMETHODS DONE' to finish configuring the proxy. */ times_called++; if (times_called <= 5) { buf_add_printf(buffer, "SMETHOD mock%d 127.0.0.1:555%d\n", times_called, times_called); } else if (times_called <= 6) { buf_add_string(buffer, "SMETHODS DONE\n"); } else if (times_called <= 7) { buf_add_string(buffer, "LOG SEVERITY=error MESSAGE=\"Oh noes, something " "bad happened. What do we do!?\"\n"); buf_add_string(buffer, "LOG SEVERITY=warning MESSAGE=\"warning msg\"\n"); buf_add_string(buffer, "LOG SEVERITY=notice MESSAGE=\"notice msg\"\n"); buf_add_string(buffer, "LOG SEVERITY=info MESSAGE=\"info msg\"\n"); buf_add_string(buffer, "LOG SEVERITY=debug MESSAGE=\"debug msg\"\n"); } else if (times_called <= 8) { buf_add_string(buffer, "STATUS TRANSPORT=a K_1=a K_2=b K_3=\"foo bar\"\n"); buf_add_string(buffer, "STATUS TRANSPORT=b K_1=a K_2=b K_3=\"foo bar\"\n"); buf_add_string(buffer, "STATUS TRANSPORT=c K_1=a K_2=b K_3=\"foo bar\"\n"); } return (int)buf_datalen(buffer); }
/** Write the given <b>buffer</b> as input to the given <b>process</b>'s * standard input. Returns the number of bytes written. */ int process_unix_write(process_t *process, buf_t *buffer) { tor_assert(process); tor_assert(buffer); process_unix_t *unix_process = process_get_unix_process(process); size_t buffer_flush_len = buf_datalen(buffer); const size_t max_to_write = MIN(PROCESS_MAX_WRITE, buffer_flush_len); /* If we have data to write (when buffer_flush_len > 0) and we are not * currently getting file descriptor events from the kernel, we tell the * kernel to start notifying us about when we can write to our file * descriptor and return. */ if (buffer_flush_len > 0 && ! unix_process->stdin_handle.is_writing) { process_unix_start_writing(&unix_process->stdin_handle); return 0; } /* We don't have any data to write, but the kernel is currently notifying us * about whether we are able to write or not. Tell the kernel to stop * notifying us until we have data to write. */ if (buffer_flush_len == 0 && unix_process->stdin_handle.is_writing) { process_unix_stop_writing(&unix_process->stdin_handle); return 0; } /* We have data to write and the kernel have told us to write it. */ return buf_flush_to_pipe(buffer, process_get_unix_process(process)->stdin_handle.fd, max_to_write, &buffer_flush_len); }
/** Perform SOCKS 5 authentication */ static void test_socks_5_no_authenticate(void *ptr) { SOCKS_TEST_INIT(); /*SOCKS 5 No Authentication */ ADD_DATA(buf,"\x05\x01\x00"); tt_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(5,OP_EQ, socks->reply[0]); tt_int_op(SOCKS_NO_AUTH,OP_EQ, socks->reply[1]); tt_int_op(0,OP_EQ, buf_datalen(buf)); /*SOCKS 5 Send username/password anyway - pretend to be broken */ ADD_DATA(buf,"\x01\x02\x01\x01\x02\x01\x01"); tt_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(1,OP_EQ, socks->reply[0]); tt_int_op(0,OP_EQ, socks->reply[1]); tt_int_op(2,OP_EQ, socks->usernamelen); tt_int_op(2,OP_EQ, socks->passwordlen); tt_mem_op("\x01\x01",OP_EQ, socks->username, 2); tt_mem_op("\x01\x01",OP_EQ, socks->password, 2); done: ; }
static void test_proto_line(void *arg) { (void)arg; char tmp[60]; buf_t *buf = buf_new(); #define S(str) str, sizeof(str)-1 const struct { const char *input; size_t input_len; size_t line_len; const char *output; int returnval; } cases[] = { { S("Hello world"), 0, NULL, 0 }, { S("Hello world\n"), 12, "Hello world\n", 1 }, { S("Hello world\nMore"), 12, "Hello world\n", 1 }, { S("\n oh hello world\nMore"), 1, "\n", 1 }, { S("Hello worpd\n\nMore"), 12, "Hello worpd\n", 1 }, { S("------------------------------------------------------------\n"), 0, NULL, -1 }, }; unsigned i; for (i = 0; i < ARRAY_LENGTH(cases); ++i) { buf_add(buf, cases[i].input, cases[i].input_len); memset(tmp, 0xfe, sizeof(tmp)); size_t sz = sizeof(tmp); int rv = buf_get_line(buf, tmp, &sz); tt_int_op(rv, OP_EQ, cases[i].returnval); if (rv == 1) { tt_int_op(sz, OP_LT, sizeof(tmp)); tt_mem_op(cases[i].output, OP_EQ, tmp, sz+1); tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len - strlen(tmp)); tt_int_op(sz, OP_EQ, cases[i].line_len); } else { tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len); // tt_int_op(sz, OP_EQ, sizeof(tmp)); } buf_clear(buf); } done: buf_free(buf); }
/** Read <b>buf</b>, which should contain an Extended ORPort message * from a transport proxy. If well-formed, create and populate * <b>out</b> with the Extended ORport message. Return 0 if the * buffer was incomplete, 1 if it was well-formed and -1 if we * encountered an error while parsing it. */ int fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out) { char hdr[EXT_OR_CMD_HEADER_SIZE]; uint16_t len; if (buf_datalen(buf) < EXT_OR_CMD_HEADER_SIZE) return 0; buf_peek(buf, hdr, sizeof(hdr)); len = ntohs(get_uint16(hdr+2)); if (buf_datalen(buf) < (unsigned)len + EXT_OR_CMD_HEADER_SIZE) return 0; *out = ext_or_cmd_new(len); (*out)->cmd = ntohs(get_uint16(hdr)); (*out)->len = len; buf_drain(buf, EXT_OR_CMD_HEADER_SIZE); buf_get_bytes(buf, (*out)->body, len); return 1; }
/* Write sz bytes from cp into a newly allocated buffer buf. * Returns NULL when passed a NULL cp or zero sz. * Asserts on failure: only for use in unit tests. * buf must be freed using buf_free(). */ buf_t * buf_new_with_data(const char *cp, size_t sz) { /* Validate arguments */ if (!cp || sz <= 0) { return NULL; } tor_assert(sz < SSIZE_T_CEILING); /* Allocate a buffer */ buf_t *buf = buf_new_with_capacity(sz); tor_assert(buf); buf_assert_ok(buf); tor_assert(!buf->head); /* Allocate a chunk that is sz bytes long */ buf->head = chunk_new_with_alloc_size(CHUNK_ALLOC_SIZE(sz)); buf->tail = buf->head; tor_assert(buf->head); buf_assert_ok(buf); tor_assert(buf_allocation(buf) >= sz); /* Copy the data and size the buffers */ tor_assert(sz <= buf_slack(buf)); tor_assert(sz <= CHUNK_REMAINING_CAPACITY(buf->head)); memcpy(&buf->head->mem[0], cp, sz); buf->datalen = sz; buf->head->datalen = sz; buf->head->data = &buf->head->mem[0]; buf_assert_ok(buf); /* Make sure everything is large enough */ tor_assert(buf_allocation(buf) >= sz); tor_assert(buf_allocation(buf) >= buf_datalen(buf) + buf_slack(buf)); /* Does the buffer implementation allocate more than the requested size? * (for example, by rounding up). If so, these checks will fail. */ tor_assert(buf_datalen(buf) == sz); tor_assert(buf_slack(buf) == 0); return buf; }
/** Check <b>buf</b> for a variable-length cell according to the rules of link * protocol version <b>linkproto</b>. If one is found, pull it off the buffer * and assign a newly allocated var_cell_t to *<b>out</b>, and return 1. * Return 0 if whatever is on the start of buf_t is not a variable-length * cell. Return 1 and set *<b>out</b> to NULL if there seems to be the start * of a variable-length cell on <b>buf</b>, but the whole thing isn't there * yet. */ int fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto) { char hdr[VAR_CELL_MAX_HEADER_SIZE]; var_cell_t *result; uint8_t command; uint16_t length; const int wide_circ_ids = linkproto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS; const int circ_id_len = get_circ_id_size(wide_circ_ids); const unsigned header_len = get_var_cell_header_size(wide_circ_ids); *out = NULL; if (buf_datalen(buf) < header_len) return 0; buf_peek(buf, hdr, header_len); command = get_uint8(hdr + circ_id_len); if (!(cell_command_is_var_length(command, linkproto))) return 0; length = ntohs(get_uint16(hdr + circ_id_len + 1)); if (buf_datalen(buf) < (size_t)(header_len+length)) return 1; result = var_cell_new(length); result->command = command; if (wide_circ_ids) result->circ_id = ntohl(get_uint32(hdr)); else result->circ_id = ntohs(get_uint16(hdr)); buf_drain(buf, header_len); buf_peek(buf, (char*) result->payload, length); buf_drain(buf, length); *out = result; return 1; }
/** Perform unsupported SOCKS 5 commands */ static void test_socks_5_unsupported_commands(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 5 Send unsupported BIND [02] command */ ADD_DATA(buf, "\x05\x02\x00\x01"); tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks),OP_EQ, 0); tt_int_op(0,OP_EQ, buf_datalen(buf)); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(5,OP_EQ, socks->reply[0]); tt_int_op(0,OP_EQ, socks->reply[1]); ADD_DATA(buf, "\x05\x02\x00\x01\x02\x02\x02\x01\x01\x01"); tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks),OP_EQ, -1); tt_int_op(5,OP_EQ,socks->socks_version); tt_int_op(10,OP_EQ,socks->replylen); tt_int_op(5,OP_EQ,socks->reply[0]); tt_int_op(SOCKS5_COMMAND_NOT_SUPPORTED,OP_EQ,socks->reply[1]); tt_int_op(1,OP_EQ,socks->reply[3]); buf_clear(buf); socks_request_clear(socks); /* SOCKS 5 Send unsupported UDP_ASSOCIATE [03] command */ ADD_DATA(buf, "\x05\x02\x00\x01"); tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks),OP_EQ, 0); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(5,OP_EQ, socks->reply[0]); tt_int_op(0,OP_EQ, socks->reply[1]); ADD_DATA(buf, "\x05\x03\x00\x01\x02\x02\x02\x01\x01\x01"); tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks),OP_EQ, -1); tt_int_op(5,OP_EQ,socks->socks_version); tt_int_op(10,OP_EQ,socks->replylen); tt_int_op(5,OP_EQ,socks->reply[0]); tt_int_op(SOCKS5_COMMAND_NOT_SUPPORTED,OP_EQ,socks->reply[1]); tt_int_op(1,OP_EQ,socks->reply[3]); done: ; }
static void test_buffers_zlib_impl(int finalize_with_nil) { char *msg = NULL; char *contents = NULL; char *expanded = NULL; buf_t *buf = NULL; tor_zlib_state_t *zlib_state = NULL; size_t out_len, in_len; int done; buf = buf_new_with_capacity(128); /* will round up */ zlib_state = tor_zlib_new(1, ZLIB_METHOD, HIGH_COMPRESSION); msg = tor_malloc(512); crypto_rand(msg, 512); tt_int_op(write_to_buf_zlib(buf, zlib_state, msg, 128, 0), OP_EQ, 0); tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+128, 128, 0), OP_EQ, 0); tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+256, 256, 0), OP_EQ, 0); done = !finalize_with_nil; tt_int_op(write_to_buf_zlib(buf, zlib_state, "all done", 9, done), OP_EQ, 0); if (finalize_with_nil) { tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), OP_EQ, 0); } in_len = buf_datalen(buf); contents = tor_malloc(in_len); tt_int_op(fetch_from_buf(contents, in_len, buf), OP_EQ, 0); tt_int_op(0, OP_EQ, tor_gzip_uncompress(&expanded, &out_len, contents, in_len, ZLIB_METHOD, 1, LOG_WARN)); tt_int_op(out_len, OP_GE, 128); tt_mem_op(msg, OP_EQ, expanded, 128); tt_int_op(out_len, OP_GE, 512); tt_mem_op(msg, OP_EQ, expanded, 512); tt_int_op(out_len, OP_EQ, 512+9); tt_mem_op("all done", OP_EQ, expanded+512, 9); done: buf_free(buf); tor_zlib_free(zlib_state); tor_free(contents); tor_free(expanded); tor_free(msg); }
static char * buf_get_contents(buf_t *buf, size_t *sz_out) { char *out; *sz_out = buf_datalen(buf); if (*sz_out >= ULONG_MAX) return NULL; /* C'mon, really? */ out = tor_malloc(*sz_out + 1); if (fetch_from_buf(out, (unsigned long)*sz_out, buf) != 0) { tor_free(out); return NULL; } out[*sz_out] = '\0'; /* Hopefully gratuitous. */ return out; }
/** Perform SOCKS 5 authentication and send data all in one go */ static void test_socks_5_authenticate_with_data(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 5 Negotiate username/password authentication */ ADD_DATA(buf, "\x05\x01\x02"); tt_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(5,OP_EQ, socks->reply[0]); tt_int_op(SOCKS_USER_PASS,OP_EQ, socks->reply[1]); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(0,OP_EQ, buf_datalen(buf)); /* SOCKS 5 Send username/password */ /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */ ADD_DATA(buf, "\x01\x02me\x03you\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11"); tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(1,OP_EQ, socks->reply[0]); tt_int_op(0,OP_EQ, socks->reply[1]); tt_str_op("2.2.2.2",OP_EQ, socks->address); tt_int_op(4369,OP_EQ, socks->port); tt_int_op(2,OP_EQ, socks->usernamelen); tt_int_op(3,OP_EQ, socks->passwordlen); tt_mem_op("me",OP_EQ, socks->username, 2); tt_mem_op("you",OP_EQ, socks->password, 3); done: ; }
/** Perform SOCKS 5 authentication */ static void test_socks_5_authenticate(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 5 Negotiate username/password authentication */ ADD_DATA(buf, "\x05\x01\x02"); tt_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(5,OP_EQ, socks->reply[0]); tt_int_op(SOCKS_USER_PASS,OP_EQ, socks->reply[1]); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(0,OP_EQ, buf_datalen(buf)); /* SOCKS 5 Send username/password */ ADD_DATA(buf, "\x01\x02me\x08mypasswd"); tt_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(1,OP_EQ, socks->reply[0]); tt_int_op(0,OP_EQ, socks->reply[1]); tt_int_op(2,OP_EQ, socks->usernamelen); tt_int_op(8,OP_EQ, socks->passwordlen); tt_mem_op("me",OP_EQ, socks->username, 2); tt_mem_op("mypasswd",OP_EQ, socks->password, 8); done: ; }
/** Called when we get data from a cpuworker. If the answer is not complete, * wait for a complete answer. If the answer is complete, * process it as appropriate. */ int connection_cpu_process_inbuf(connection_t *conn) { char success; char buf[LEN_ONION_RESPONSE]; uint64_t conn_id; circid_t circ_id; connection_t *tmp_conn; or_connection_t *p_conn = NULL; circuit_t *circ; tor_assert(conn); tor_assert(conn->type == CONN_TYPE_CPUWORKER); if (!buf_datalen(conn->inbuf)) return 0; if (conn->state == CPUWORKER_STATE_BUSY_ONION) { if (buf_datalen(conn->inbuf) < LEN_ONION_RESPONSE) /* answer available? */ return 0; /* not yet */ tor_assert(buf_datalen(conn->inbuf) == LEN_ONION_RESPONSE); connection_fetch_from_buf(&success,1,conn); connection_fetch_from_buf(buf,LEN_ONION_RESPONSE-1,conn); /* parse out the circ it was talking about */ tag_unpack(buf, &conn_id, &circ_id); circ = NULL; tmp_conn = connection_get_by_global_id(conn_id); if (tmp_conn && !tmp_conn->marked_for_close && tmp_conn->type == CONN_TYPE_OR) p_conn = TO_OR_CONN(tmp_conn); if (p_conn) circ = circuit_get_by_circid_orconn(circ_id, p_conn); if (success == 0) { log_debug(LD_OR, "decoding onionskin failed. " "(Old key or bad software.) Closing."); if (circ) circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); goto done_processing; } if (!circ) { /* This happens because somebody sends us a destroy cell and the * circuit goes away, while the cpuworker is working. This is also * why our tag doesn't include a pointer to the circ, because we'd * never know if it's still valid. */ log_debug(LD_OR,"processed onion for a circ that's gone. Dropping."); goto done_processing; } tor_assert(! CIRCUIT_IS_ORIGIN(circ)); if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN, buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) { log_warn(LD_OR,"onionskin_answer failed. Closing."); circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); goto done_processing; } log_debug(LD_OR,"onionskin_answer succeeded. Yay."); } else { tor_assert(0); /* don't ask me to do handshakes yet */ } done_processing: conn->state = CPUWORKER_STATE_IDLE; num_cpuworkers_busy--; if (conn->timestamp_created < last_rotation_time) { connection_mark_for_close(conn); num_cpuworkers--; spawn_enough_cpuworkers(); } else { process_pending_task(conn); } return 0; }
static void test_buffer_time_tracking(void *arg) { buf_t *buf=NULL, *buf2=NULL; struct timeval tv0; const time_t START = 1389288246; const uint32_t START_MSEC = (uint32_t) ((uint64_t)START * 1000); int i; char tmp[4096]; (void)arg; crypto_rand(tmp, sizeof(tmp)); tv0.tv_sec = START; tv0.tv_usec = 0; buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ tt_assert(buf); /* Empty buffer means the timestamp is 0. */ tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC)); tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000)); tor_gettimeofday_cache_set(&tv0); write_to_buf("ABCDEFG", 7, buf); tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000)); buf2 = buf_copy(buf); tt_assert(buf2); tt_int_op(1234, OP_EQ, buf_get_oldest_chunk_timestamp(buf2, START_MSEC+1234)); /* Now add more bytes; enough to overflow the first chunk. */ tv0.tv_usec += 123 * 1000; tor_gettimeofday_cache_set(&tv0); for (i = 0; i < 600; ++i) write_to_buf("ABCDEFG", 7, buf); tt_int_op(4207, OP_EQ, buf_datalen(buf)); /* The oldest bytes are still in the front. */ tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000)); /* Once those bytes are dropped, the chunk is still on the first * timestamp. */ fetch_from_buf(tmp, 100, buf); tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000)); /* But once we discard the whole first chunk, we get the data in the second * chunk. */ fetch_from_buf(tmp, 4000, buf); tt_int_op(107, OP_EQ, buf_datalen(buf)); tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123)); /* This time we'll be grabbing a chunk from the freelist, and making sure its time gets updated */ tv0.tv_sec += 5; tv0.tv_usec = 617*1000; tor_gettimeofday_cache_set(&tv0); for (i = 0; i < 600; ++i) write_to_buf("ABCDEFG", 7, buf); tt_int_op(4307, OP_EQ, buf_datalen(buf)); tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123)); fetch_from_buf(tmp, 4000, buf); fetch_from_buf(tmp, 306, buf); tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+5617)); tt_int_op(383, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+6000)); done: buf_free(buf); buf_free(buf2); }
static void test_buffer_pullup(void *arg) { buf_t *buf; char *stuff, *tmp; const char *cp; size_t sz; (void)arg; stuff = tor_malloc(16384); tmp = tor_malloc(16384); buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ tt_assert(buf); tt_int_op(buf_get_default_chunk_size(buf), OP_EQ, 4096); tt_int_op(buf_get_total_allocation(), OP_EQ, 0); /* There are a bunch of cases for pullup. One is the trivial case. Let's mess around with an empty buffer. */ buf_pullup(buf, 16); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_EQ, NULL); tt_uint_op(sz, OP_EQ, 0); /* Let's make sure nothing got allocated */ tt_int_op(buf_get_total_allocation(), OP_EQ, 0); /* Case 1: everything puts into the first chunk with some moving. */ /* Let's add some data. */ crypto_rand(stuff, 16384); write_to_buf(stuff, 3000, buf); write_to_buf(stuff+3000, 3000, buf); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_NE, NULL); tt_int_op(sz, OP_LE, 4096); /* Make room for 3000 bytes in the first chunk, so that the pullup-move code * can get tested. */ tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 3000); tt_mem_op(tmp,OP_EQ, stuff, 3000); buf_pullup(buf, 2048); assert_buf_ok(buf); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_NE, NULL); tt_int_op(sz, OP_GE, 2048); tt_mem_op(cp,OP_EQ, stuff+3000, 2048); tt_int_op(3000, OP_EQ, buf_datalen(buf)); tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 0); tt_mem_op(tmp,OP_EQ, stuff+3000, 2048); buf_free(buf); /* Now try the large-chunk case. */ buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ write_to_buf(stuff, 4000, buf); write_to_buf(stuff+4000, 4000, buf); write_to_buf(stuff+8000, 4000, buf); write_to_buf(stuff+12000, 4000, buf); tt_int_op(buf_datalen(buf), OP_EQ, 16000); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_NE, NULL); tt_int_op(sz, OP_LE, 4096); buf_pullup(buf, 12500); assert_buf_ok(buf); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_NE, NULL); tt_int_op(sz, OP_GE, 12500); tt_mem_op(cp,OP_EQ, stuff, 12500); tt_int_op(buf_datalen(buf), OP_EQ, 16000); fetch_from_buf(tmp, 12400, buf); tt_mem_op(tmp,OP_EQ, stuff, 12400); tt_int_op(buf_datalen(buf), OP_EQ, 3600); fetch_from_buf(tmp, 3500, buf); tt_mem_op(tmp,OP_EQ, stuff+12400, 3500); fetch_from_buf(tmp, 100, buf); tt_mem_op(tmp,OP_EQ, stuff+15900, 10); buf_free(buf); /* Make sure that the pull-up-whole-buffer case works */ buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ write_to_buf(stuff, 4000, buf); write_to_buf(stuff+4000, 4000, buf); fetch_from_buf(tmp, 100, buf); /* dump 100 bytes from first chunk */ buf_pullup(buf, 16000); /* Way too much. */ assert_buf_ok(buf); buf_get_first_chunk_data(buf, &cp, &sz); tt_ptr_op(cp, OP_NE, NULL); tt_int_op(sz, OP_EQ, 7900); tt_mem_op(cp,OP_EQ, stuff+100, 7900); buf_free(buf); buf = NULL; tt_int_op(buf_get_total_allocation(), OP_EQ, 0); done: buf_free(buf); tor_free(stuff); tor_free(tmp); }
/** Run unit tests for buffers.c */ static void test_buffers_basic(void *arg) { char str[256]; char str2[256]; buf_t *buf = NULL, *buf2 = NULL; const char *cp; int j; size_t r; (void) arg; /**** * buf_new ****/ if (!(buf = buf_new())) TT_DIE(("Assertion failed.")); //test_eq(buf_capacity(buf), 4096); tt_int_op(buf_datalen(buf),OP_EQ, 0); /**** * General pointer frobbing */ for (j=0;j<256;++j) { str[j] = (char)j; } write_to_buf(str, 256, buf); write_to_buf(str, 256, buf); tt_int_op(buf_datalen(buf),OP_EQ, 512); fetch_from_buf(str2, 200, buf); tt_mem_op(str,OP_EQ, str2, 200); tt_int_op(buf_datalen(buf),OP_EQ, 312); memset(str2, 0, sizeof(str2)); fetch_from_buf(str2, 256, buf); tt_mem_op(str+200,OP_EQ, str2, 56); tt_mem_op(str,OP_EQ, str2+56, 200); tt_int_op(buf_datalen(buf),OP_EQ, 56); memset(str2, 0, sizeof(str2)); /* Okay, now we should be 512 bytes into the 4096-byte buffer. If we add * another 3584 bytes, we hit the end. */ for (j=0;j<15;++j) { write_to_buf(str, 256, buf); } assert_buf_ok(buf); tt_int_op(buf_datalen(buf),OP_EQ, 3896); fetch_from_buf(str2, 56, buf); tt_int_op(buf_datalen(buf),OP_EQ, 3840); tt_mem_op(str+200,OP_EQ, str2, 56); for (j=0;j<15;++j) { memset(str2, 0, sizeof(str2)); fetch_from_buf(str2, 256, buf); tt_mem_op(str,OP_EQ, str2, 256); } tt_int_op(buf_datalen(buf),OP_EQ, 0); buf_free(buf); buf = NULL; /* Okay, now make sure growing can work. */ buf = buf_new_with_capacity(16); //test_eq(buf_capacity(buf), 16); write_to_buf(str+1, 255, buf); //test_eq(buf_capacity(buf), 256); fetch_from_buf(str2, 254, buf); tt_mem_op(str+1,OP_EQ, str2, 254); //test_eq(buf_capacity(buf), 256); assert_buf_ok(buf); write_to_buf(str, 32, buf); //test_eq(buf_capacity(buf), 256); assert_buf_ok(buf); write_to_buf(str, 256, buf); assert_buf_ok(buf); //test_eq(buf_capacity(buf), 512); tt_int_op(buf_datalen(buf),OP_EQ, 33+256); fetch_from_buf(str2, 33, buf); tt_int_op(*str2,OP_EQ, str[255]); tt_mem_op(str2+1,OP_EQ, str, 32); //test_eq(buf_capacity(buf), 512); tt_int_op(buf_datalen(buf),OP_EQ, 256); fetch_from_buf(str2, 256, buf); tt_mem_op(str,OP_EQ, str2, 256); /* now try shrinking: case 1. */ buf_free(buf); buf = buf_new_with_capacity(33668); for (j=0;j<67;++j) { write_to_buf(str,255, buf); } //test_eq(buf_capacity(buf), 33668); tt_int_op(buf_datalen(buf),OP_EQ, 17085); for (j=0; j < 40; ++j) { fetch_from_buf(str2, 255,buf); tt_mem_op(str2,OP_EQ, str, 255); } /* now try shrinking: case 2. */ buf_free(buf); buf = buf_new_with_capacity(33668); for (j=0;j<67;++j) { write_to_buf(str,255, buf); } for (j=0; j < 20; ++j) { fetch_from_buf(str2, 255,buf); tt_mem_op(str2,OP_EQ, str, 255); } for (j=0;j<80;++j) { write_to_buf(str,255, buf); } //test_eq(buf_capacity(buf),33668); for (j=0; j < 120; ++j) { fetch_from_buf(str2, 255,buf); tt_mem_op(str2,OP_EQ, str, 255); } /* Move from buf to buf. */ buf_free(buf); buf = buf_new_with_capacity(4096); buf2 = buf_new_with_capacity(4096); for (j=0;j<100;++j) write_to_buf(str, 255, buf); tt_int_op(buf_datalen(buf),OP_EQ, 25500); for (j=0;j<100;++j) { r = 10; move_buf_to_buf(buf2, buf, &r); tt_int_op(r,OP_EQ, 0); } tt_int_op(buf_datalen(buf),OP_EQ, 24500); tt_int_op(buf_datalen(buf2),OP_EQ, 1000); for (j=0;j<3;++j) { fetch_from_buf(str2, 255, buf2); tt_mem_op(str2,OP_EQ, str, 255); } r = 8192; /*big move*/ move_buf_to_buf(buf2, buf, &r); tt_int_op(r,OP_EQ, 0); r = 30000; /* incomplete move */ move_buf_to_buf(buf2, buf, &r); tt_int_op(r,OP_EQ, 13692); for (j=0;j<97;++j) { fetch_from_buf(str2, 255, buf2); tt_mem_op(str2,OP_EQ, str, 255); } buf_free(buf); buf_free(buf2); buf = buf2 = NULL; buf = buf_new_with_capacity(5); cp = "Testing. This is a moderately long Testing string."; for (j = 0; cp[j]; j++) write_to_buf(cp+j, 1, buf); tt_int_op(0,OP_EQ, buf_find_string_offset(buf, "Testing", 7)); tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "esting", 6)); tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "est", 3)); tt_int_op(39,OP_EQ, buf_find_string_offset(buf, "ing str", 7)); tt_int_op(35,OP_EQ, buf_find_string_offset(buf, "Testing str", 11)); tt_int_op(32,OP_EQ, buf_find_string_offset(buf, "ng ", 3)); tt_int_op(43,OP_EQ, buf_find_string_offset(buf, "string.", 7)); tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "shrdlu", 6)); tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "Testing thing", 13)); tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "ngx", 3)); buf_free(buf); buf = NULL; /* Try adding a string too long for any freelist. */ { char *cp = tor_malloc_zero(65536); buf = buf_new(); write_to_buf(cp, 65536, buf); tor_free(cp); tt_int_op(buf_datalen(buf), OP_EQ, 65536); buf_free(buf); buf = NULL; } done: if (buf) buf_free(buf); if (buf2) buf_free(buf2); }
static void test_proto_var_cell(void *arg) { (void)arg; char *mem_op_hex_tmp = NULL; char tmp[1024]; buf_t *buf = NULL; var_cell_t *cell = NULL; buf = buf_new(); memset(tmp, 0xf0, sizeof(tmp)); /* Short little commands will make us say "no cell yet." */ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4)); tt_ptr_op(cell, OP_EQ, NULL); buf_add(buf, "\x01\x02\x02\0x2", 4); tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4)); /* An incomplete fixed-length cell makes us say "no cell yet". */ buf_add(buf, "\x03", 1); tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4)); /* A complete fixed length-cell makes us say "not a variable-length cell" */ buf_add(buf, tmp, 509); tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4)); buf_clear(buf); /* An incomplete versions cell is a variable-length cell that isn't ready * yet. */ buf_add(buf, "\x01\x02\x03\x04" /* circid */ "\x07" /* VERSIONS */ "\x00\x04" /* 4 bytes long */ "\x00" /* incomplete */, 8); tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4)); tt_ptr_op(cell, OP_EQ, NULL); /* Complete it, and it's a variable-length cell. Leave a byte on the end for * fun. */ buf_add(buf, "\x09\x00\x25\ff", 4); tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4)); tt_ptr_op(cell, OP_NE, NULL); tt_int_op(cell->command, OP_EQ, CELL_VERSIONS); tt_uint_op(cell->circ_id, OP_EQ, 0x01020304); tt_int_op(cell->payload_len, OP_EQ, 4); test_mem_op_hex(cell->payload, OP_EQ, "00090025"); var_cell_free(cell); cell = NULL; tt_int_op(buf_datalen(buf), OP_EQ, 1); buf_clear(buf); /* In link protocol 3 and earlier, circid fields were two bytes long. Let's * ensure that gets handled correctly. */ buf_add(buf, "\x23\x45\x81\x00\x06" /* command 81; 6 bytes long */ "coraje", 11); tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 3)); tt_ptr_op(cell, OP_NE, NULL); tt_int_op(cell->command, OP_EQ, 129); tt_uint_op(cell->circ_id, OP_EQ, 0x2345); tt_int_op(cell->payload_len, OP_EQ, 6); tt_mem_op(cell->payload, OP_EQ, "coraje", 6); var_cell_free(cell); cell = NULL; tt_int_op(buf_datalen(buf), OP_EQ, 0); /* In link protocol 2, only VERSIONS cells counted as variable-length */ buf_add(buf, "\x23\x45\x81\x00\x06" "coraje", 11); /* As above */ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2)); buf_clear(buf); buf_add(buf, "\x23\x45\x07\x00\x06" "futuro", 11); tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2)); tt_ptr_op(cell, OP_NE, NULL); tt_int_op(cell->command, OP_EQ, 7); tt_uint_op(cell->circ_id, OP_EQ, 0x2345); tt_int_op(cell->payload_len, OP_EQ, 6); tt_mem_op(cell->payload, OP_EQ, "futuro", 6); var_cell_free(cell); cell = NULL; done: buf_free(buf); var_cell_free(cell); tor_free(mem_op_hex_tmp); }
static void test_buffer_copy(void *arg) { buf_t *buf=NULL, *buf2=NULL; const char *s; size_t len; char b[256]; int i; (void)arg; buf = buf_new(); tt_assert(buf); /* Copy an empty buffer. */ tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf)); tt_assert(buf2); tt_int_op(0, OP_EQ, buf_datalen(buf2)); /* Now try with a short buffer. */ s = "And now comes an act of enormous enormance!"; len = strlen(s); write_to_buf(s, len, buf); tt_int_op(len, OP_EQ, buf_datalen(buf)); /* Add junk to buf2 so we can test replacing.*/ write_to_buf("BLARG", 5, buf2); tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf)); tt_int_op(len, OP_EQ, buf_datalen(buf2)); fetch_from_buf(b, len, buf2); tt_mem_op(b, OP_EQ, s, len); /* Now free buf2 and retry so we can test allocating */ buf_free(buf2); buf2 = NULL; tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf)); tt_int_op(len, OP_EQ, buf_datalen(buf2)); fetch_from_buf(b, len, buf2); tt_mem_op(b, OP_EQ, s, len); /* Clear buf for next test */ fetch_from_buf(b, len, buf); tt_int_op(buf_datalen(buf),OP_EQ,0); /* Okay, now let's try a bigger buffer. */ s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit " "esse quam nihil molestiae consequatur, vel illum qui dolorem eum " "fugiat quo voluptas nulla pariatur?"; len = strlen(s); for (i = 0; i < 256; ++i) { b[0]=i; write_to_buf(b, 1, buf); write_to_buf(s, len, buf); } tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf)); tt_int_op(buf_datalen(buf2), OP_EQ, buf_datalen(buf)); for (i = 0; i < 256; ++i) { fetch_from_buf(b, len+1, buf2); tt_int_op((unsigned char)b[0],OP_EQ,i); tt_mem_op(b+1, OP_EQ, s, len); } done: if (buf) buf_free(buf); if (buf2) buf_free(buf2); }
/** Perform supported SOCKS 5 commands */ static void test_socks_5_supported_commands(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */ ADD_DATA(buf, "\x05\x01\x00"); tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks),OP_EQ, 0); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(5,OP_EQ, socks->reply[0]); tt_int_op(0,OP_EQ, socks->reply[1]); ADD_DATA(buf, "\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11"); tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks),OP_EQ, 1); tt_str_op("2.2.2.2",OP_EQ, socks->address); tt_int_op(4369,OP_EQ, socks->port); tt_int_op(0,OP_EQ, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 5 Send CONNECT [01] to FQDN torproject.org:4369 */ ADD_DATA(buf, "\x05\x01\x00"); ADD_DATA(buf, "\x05\x01\x00\x03\x0Etorproject.org\x11\x11"); tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks),OP_EQ, 1); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(5,OP_EQ, socks->reply[0]); tt_int_op(0,OP_EQ, socks->reply[1]); tt_str_op("torproject.org",OP_EQ, socks->address); tt_int_op(4369,OP_EQ, socks->port); tt_int_op(0,OP_EQ, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 5 Send RESOLVE [F0] request for torproject.org:4369 */ ADD_DATA(buf, "\x05\x01\x00"); ADD_DATA(buf, "\x05\xF0\x00\x03\x0Etorproject.org\x01\x02"); tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(5,OP_EQ, socks->reply[0]); tt_int_op(0,OP_EQ, socks->reply[1]); tt_str_op("torproject.org",OP_EQ, socks->address); tt_int_op(0,OP_EQ, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 5 Should reject RESOLVE [F0] request for IPv4 address * string if SafeSocks is enabled. */ ADD_DATA(buf, "\x05\x01\x00"); ADD_DATA(buf, "\x05\xF0\x00\x03\x07"); ADD_DATA(buf, "8.8.8.8"); ADD_DATA(buf, "\x01\x02"); tt_assert(fetch_from_buf_socks(buf,socks,get_options()->TestSocks,1) == -1); tt_int_op(5,OP_EQ,socks->socks_version); tt_int_op(10,OP_EQ,socks->replylen); tt_int_op(5,OP_EQ,socks->reply[0]); tt_int_op(SOCKS5_NOT_ALLOWED,OP_EQ,socks->reply[1]); tt_int_op(1,OP_EQ,socks->reply[3]); socks_request_clear(socks); /* SOCKS 5 should reject RESOLVE [F0] reject for IPv6 address * string if SafeSocks is enabled. */ ADD_DATA(buf, "\x05\x01\x00"); ADD_DATA(buf, "\x05\xF0\x00\x03\x27"); ADD_DATA(buf, "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); ADD_DATA(buf, "\x01\x02"); tt_assert(fetch_from_buf_socks(buf,socks,get_options()->TestSocks,1) == -1); tt_int_op(5,OP_EQ,socks->socks_version); tt_int_op(10,OP_EQ,socks->replylen); tt_int_op(5,OP_EQ,socks->reply[0]); tt_int_op(SOCKS5_NOT_ALLOWED,OP_EQ,socks->reply[1]); tt_int_op(1,OP_EQ,socks->reply[3]); socks_request_clear(socks); /* SOCKS 5 Send RESOLVE_PTR [F1] for IP address 2.2.2.5 */ ADD_DATA(buf, "\x05\x01\x00"); ADD_DATA(buf, "\x05\xF1\x00\x01\x02\x02\x02\x05\x01\x03"); tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); tt_int_op(5,OP_EQ, socks->socks_version); tt_int_op(2,OP_EQ, socks->replylen); tt_int_op(5,OP_EQ, socks->reply[0]); tt_int_op(0,OP_EQ, socks->reply[1]); tt_str_op("2.2.2.5",OP_EQ, socks->address); tt_int_op(0,OP_EQ, buf_datalen(buf)); done: ; }
static void test_buffer_ext_or_cmd(void *arg) { ext_or_cmd_t *cmd = NULL; buf_t *buf = buf_new(); char *tmp = NULL; (void) arg; /* Empty -- should give "not there. */ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd)); tt_ptr_op(NULL, OP_EQ, cmd); /* Three bytes: shouldn't work. */ write_to_buf("\x00\x20\x00", 3, buf); tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd)); tt_ptr_op(NULL, OP_EQ, cmd); tt_int_op(3, OP_EQ, buf_datalen(buf)); /* 0020 0000: That's a nil command. It should work. */ write_to_buf("\x00", 1, buf); tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd)); tt_ptr_op(NULL, OP_NE, cmd); tt_int_op(0x20, OP_EQ, cmd->cmd); tt_int_op(0, OP_EQ, cmd->len); tt_int_op(0, OP_EQ, buf_datalen(buf)); ext_or_cmd_free(cmd); cmd = NULL; /* Now try a length-6 command with one byte missing. */ write_to_buf("\x10\x21\x00\x06""abcde", 9, buf); tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd)); tt_ptr_op(NULL, OP_EQ, cmd); write_to_buf("f", 1, buf); tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd)); tt_ptr_op(NULL, OP_NE, cmd); tt_int_op(0x1021, OP_EQ, cmd->cmd); tt_int_op(6, OP_EQ, cmd->len); tt_mem_op("abcdef", OP_EQ, cmd->body, 6); tt_int_op(0, OP_EQ, buf_datalen(buf)); ext_or_cmd_free(cmd); cmd = NULL; /* Now try a length-10 command with 4 extra bytes. */ write_to_buf("\xff\xff\x00\x0aloremipsum\x10\x00\xff\xff", 18, buf); tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd)); tt_ptr_op(NULL, OP_NE, cmd); tt_int_op(0xffff, OP_EQ, cmd->cmd); tt_int_op(10, OP_EQ, cmd->len); tt_mem_op("loremipsum", OP_EQ, cmd->body, 10); tt_int_op(4, OP_EQ, buf_datalen(buf)); ext_or_cmd_free(cmd); cmd = NULL; /* Finally, let's try a maximum-length command. We already have the header * waiting. */ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd)); tmp = tor_malloc_zero(65535); write_to_buf(tmp, 65535, buf); tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd)); tt_ptr_op(NULL, OP_NE, cmd); tt_int_op(0x1000, OP_EQ, cmd->cmd); tt_int_op(0xffff, OP_EQ, cmd->len); tt_mem_op(tmp, OP_EQ, cmd->body, 65535); tt_int_op(0, OP_EQ, buf_datalen(buf)); ext_or_cmd_free(cmd); cmd = NULL; done: ext_or_cmd_free(cmd); buf_free(buf); tor_free(tmp); }