Loading src/or/circuitlist.c +3 −3 Original line number Diff line number Diff line Loading @@ -1664,7 +1664,7 @@ n_cells_in_circ_queues(const circuit_t *c) * This function will return incorrect results if the oldest cell queued on * the circuit is older than 2**32 msec (about 49 days) old. */ static uint32_t STATIC uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now) { uint32_t age = 0; Loading Loading @@ -1711,7 +1711,7 @@ circuit_get_streams_max_data_age(const edge_connection_t *stream, uint32_t now) /** Return the age in milliseconds of the oldest buffer chunk on any stream * attached to the circuit <b>c</b>, where age is taken in milliseconds before * the time <b>now</b> (in truncated milliseconds since the epoch). */ static uint32_t STATIC uint32_t circuit_max_queued_data_age(const circuit_t *c, uint32_t now) { if (CIRCUIT_IS_ORIGIN(c)) { Loading @@ -1726,7 +1726,7 @@ circuit_max_queued_data_age(const circuit_t *c, uint32_t now) /** Return the age of the oldest cell or stream buffer chunk on the circuit * <b>c</b>, where age is taken in milliseconds before the time <b>now</b> (in * truncated milliseconds since the epoch). */ static uint32_t STATIC uint32_t circuit_max_queued_item_age(const circuit_t *c, uint32_t now) { uint32_t cell_age = circuit_max_queued_cell_age(c, now); Loading src/or/circuitlist.h +3 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,9 @@ void channel_note_destroy_not_pending(channel_t *chan, circid_t id); #ifdef CIRCUITLIST_PRIVATE STATIC void circuit_free(circuit_t *circ); STATIC size_t n_cells_in_circ_queues(const circuit_t *c); STATIC uint32_t circuit_max_queued_data_age(const circuit_t *c, uint32_t now); STATIC uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now); STATIC uint32_t circuit_max_queued_item_age(const circuit_t *c, uint32_t now); #endif #endif Loading src/test/test_oom.c +153 −4 Original line number Diff line number Diff line Loading @@ -76,7 +76,6 @@ dummy_origin_circuit_new(int n_cells) return TO_CIRCUIT(circ); } #if 0 static void add_bytes_to_buf(generic_buffer_t *buf, size_t n_bytes) { Loading @@ -91,18 +90,34 @@ add_bytes_to_buf(generic_buffer_t *buf, size_t n_bytes) } static edge_connection_t * dummy_edge_conn_new(int type, size_t in_bytes, size_t out_bytes) dummy_edge_conn_new(circuit_t *circ, int type, size_t in_bytes, size_t out_bytes) { edge_connection_t *conn = edge_connection_new(type, AF_INET); edge_connection_t *conn; if (type == CONN_TYPE_EXIT) conn = edge_connection_new(type, AF_INET); else conn = ENTRY_TO_EDGE_CONN(entry_connection_new(type, AF_INET)); /* We add these bytes directly to the buffers, to avoid all the * edge connection read/write machinery. */ add_bytes_to_buf(TO_CONN(conn)->inbuf, in_bytes); add_bytes_to_buf(TO_CONN(conn)->outbuf, out_bytes); conn->on_circuit = circ; if (type == CONN_TYPE_EXIT) { or_circuit_t *oc = TO_OR_CIRCUIT(circ); conn->next_stream = oc->n_streams; oc->n_streams = conn; } else { origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ); conn->next_stream = oc->p_streams; oc->p_streams = conn; } return conn; } #endif /** Run unit tests for buffers.c */ static void Loading Loading @@ -192,8 +207,142 @@ test_oom_circbuf(void *arg) UNMOCK(circuit_mark_for_close_); } /** Run unit tests for buffers.c */ static void test_oom_streambuf(void *arg) { or_options_t *options = get_options_mutable(); circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL, *c5 = NULL; struct timeval tv = { 1389641159, 0 }; uint32_t tvms; int i; (void) arg; MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_); init_cell_pool(); /* Far too low for real life. */ options->MaxMemInQueues = 81*packed_cell_mem_cost() + 4096 * 34; options->CellStatistics = 0; tt_int_op(cell_queues_check_size(), ==, 0); /* We don't start out OOM. */ tt_int_op(cell_queues_get_total_allocation(), ==, 0); tt_int_op(buf_get_total_allocation(), ==, 0); /* Start all circuits with a bit of data queued in cells */ tv.tv_usec = 500*1000; /* go halfway into the second. */ tor_gettimeofday_cache_set(&tv); c1 = dummy_or_circuit_new(10,10); tv.tv_usec = 510*1000; tor_gettimeofday_cache_set(&tv); c2 = dummy_origin_circuit_new(20); tv.tv_usec = 520*1000; tor_gettimeofday_cache_set(&tv); c3 = dummy_or_circuit_new(20,20); tv.tv_usec = 530*1000; tor_gettimeofday_cache_set(&tv); c4 = dummy_or_circuit_new(0,0); tt_int_op(cell_queues_get_total_allocation(), ==, packed_cell_mem_cost() * 80); tv.tv_usec = 600*1000; tor_gettimeofday_cache_set(&tv); /* Add some connections to c1...c4. */ for (i = 0; i < 4; ++i) { edge_connection_t *ec; /* link it to a circuit */ tv.tv_usec += 10*1000; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c1, CONN_TYPE_EXIT, 1000, 1000); tt_assert(ec); tv.tv_usec += 10*1000; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c2, CONN_TYPE_AP, 1000, 1000); tt_assert(ec); tv.tv_usec += 10*1000; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); /* Yes, 4 twice*/ tt_assert(ec); tv.tv_usec += 10*1000; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); tt_assert(ec); } tv.tv_sec += 1; tv.tv_usec = 0; tvms = (uint32_t) tv_to_msec(&tv); tt_int_op(circuit_max_queued_cell_age(c1, tvms), ==, 500); tt_int_op(circuit_max_queued_cell_age(c2, tvms), ==, 490); tt_int_op(circuit_max_queued_cell_age(c3, tvms), ==, 480); tt_int_op(circuit_max_queued_cell_age(c4, tvms), ==, 0); tt_int_op(circuit_max_queued_data_age(c1, tvms), ==, 390); tt_int_op(circuit_max_queued_data_age(c2, tvms), ==, 380); tt_int_op(circuit_max_queued_data_age(c3, tvms), ==, 0); tt_int_op(circuit_max_queued_data_age(c4, tvms), ==, 370); tt_int_op(circuit_max_queued_item_age(c1, tvms), ==, 500); tt_int_op(circuit_max_queued_item_age(c2, tvms), ==, 490); tt_int_op(circuit_max_queued_item_age(c3, tvms), ==, 480); tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 370); tt_int_op(cell_queues_get_total_allocation(), ==, packed_cell_mem_cost() * 80); tt_int_op(buf_get_total_allocation(), ==, 4096*16*2); /* Now give c4 a very old buffer of modest size */ { edge_connection_t *ec; tv.tv_sec -= 1; tv.tv_usec = 0; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); tt_assert(ec); } tt_int_op(buf_get_total_allocation(), ==, 4096*17*2); tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 1000); tt_int_op(cell_queues_check_size(), ==, 0); /* And run over the limit. */ tv.tv_usec = 800*1000; tor_gettimeofday_cache_set(&tv); c5 = dummy_or_circuit_new(0,5); tt_int_op(cell_queues_get_total_allocation(), ==, packed_cell_mem_cost() * 85); tt_int_op(buf_get_total_allocation(), ==, 4096*17*2); tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */ /* C4 should have died. */ tt_assert(! c1->marked_for_close); tt_assert(! c2->marked_for_close); tt_assert(! c3->marked_for_close); tt_assert(c4->marked_for_close); tt_assert(! c5->marked_for_close); tt_int_op(cell_queues_get_total_allocation(), ==, packed_cell_mem_cost() * 85); tt_int_op(buf_get_total_allocation(), ==, 4096*8*2); done: circuit_free(c1); circuit_free(c2); circuit_free(c3); circuit_free(c4); circuit_free(c5); UNMOCK(circuit_mark_for_close_); } struct testcase_t oom_tests[] = { { "circbuf", test_oom_circbuf, TT_FORK, NULL, NULL }, { "streambuf", test_oom_streambuf, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; Loading
src/or/circuitlist.c +3 −3 Original line number Diff line number Diff line Loading @@ -1664,7 +1664,7 @@ n_cells_in_circ_queues(const circuit_t *c) * This function will return incorrect results if the oldest cell queued on * the circuit is older than 2**32 msec (about 49 days) old. */ static uint32_t STATIC uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now) { uint32_t age = 0; Loading Loading @@ -1711,7 +1711,7 @@ circuit_get_streams_max_data_age(const edge_connection_t *stream, uint32_t now) /** Return the age in milliseconds of the oldest buffer chunk on any stream * attached to the circuit <b>c</b>, where age is taken in milliseconds before * the time <b>now</b> (in truncated milliseconds since the epoch). */ static uint32_t STATIC uint32_t circuit_max_queued_data_age(const circuit_t *c, uint32_t now) { if (CIRCUIT_IS_ORIGIN(c)) { Loading @@ -1726,7 +1726,7 @@ circuit_max_queued_data_age(const circuit_t *c, uint32_t now) /** Return the age of the oldest cell or stream buffer chunk on the circuit * <b>c</b>, where age is taken in milliseconds before the time <b>now</b> (in * truncated milliseconds since the epoch). */ static uint32_t STATIC uint32_t circuit_max_queued_item_age(const circuit_t *c, uint32_t now) { uint32_t cell_age = circuit_max_queued_cell_age(c, now); Loading
src/or/circuitlist.h +3 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,9 @@ void channel_note_destroy_not_pending(channel_t *chan, circid_t id); #ifdef CIRCUITLIST_PRIVATE STATIC void circuit_free(circuit_t *circ); STATIC size_t n_cells_in_circ_queues(const circuit_t *c); STATIC uint32_t circuit_max_queued_data_age(const circuit_t *c, uint32_t now); STATIC uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now); STATIC uint32_t circuit_max_queued_item_age(const circuit_t *c, uint32_t now); #endif #endif Loading
src/test/test_oom.c +153 −4 Original line number Diff line number Diff line Loading @@ -76,7 +76,6 @@ dummy_origin_circuit_new(int n_cells) return TO_CIRCUIT(circ); } #if 0 static void add_bytes_to_buf(generic_buffer_t *buf, size_t n_bytes) { Loading @@ -91,18 +90,34 @@ add_bytes_to_buf(generic_buffer_t *buf, size_t n_bytes) } static edge_connection_t * dummy_edge_conn_new(int type, size_t in_bytes, size_t out_bytes) dummy_edge_conn_new(circuit_t *circ, int type, size_t in_bytes, size_t out_bytes) { edge_connection_t *conn = edge_connection_new(type, AF_INET); edge_connection_t *conn; if (type == CONN_TYPE_EXIT) conn = edge_connection_new(type, AF_INET); else conn = ENTRY_TO_EDGE_CONN(entry_connection_new(type, AF_INET)); /* We add these bytes directly to the buffers, to avoid all the * edge connection read/write machinery. */ add_bytes_to_buf(TO_CONN(conn)->inbuf, in_bytes); add_bytes_to_buf(TO_CONN(conn)->outbuf, out_bytes); conn->on_circuit = circ; if (type == CONN_TYPE_EXIT) { or_circuit_t *oc = TO_OR_CIRCUIT(circ); conn->next_stream = oc->n_streams; oc->n_streams = conn; } else { origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ); conn->next_stream = oc->p_streams; oc->p_streams = conn; } return conn; } #endif /** Run unit tests for buffers.c */ static void Loading Loading @@ -192,8 +207,142 @@ test_oom_circbuf(void *arg) UNMOCK(circuit_mark_for_close_); } /** Run unit tests for buffers.c */ static void test_oom_streambuf(void *arg) { or_options_t *options = get_options_mutable(); circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL, *c5 = NULL; struct timeval tv = { 1389641159, 0 }; uint32_t tvms; int i; (void) arg; MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_); init_cell_pool(); /* Far too low for real life. */ options->MaxMemInQueues = 81*packed_cell_mem_cost() + 4096 * 34; options->CellStatistics = 0; tt_int_op(cell_queues_check_size(), ==, 0); /* We don't start out OOM. */ tt_int_op(cell_queues_get_total_allocation(), ==, 0); tt_int_op(buf_get_total_allocation(), ==, 0); /* Start all circuits with a bit of data queued in cells */ tv.tv_usec = 500*1000; /* go halfway into the second. */ tor_gettimeofday_cache_set(&tv); c1 = dummy_or_circuit_new(10,10); tv.tv_usec = 510*1000; tor_gettimeofday_cache_set(&tv); c2 = dummy_origin_circuit_new(20); tv.tv_usec = 520*1000; tor_gettimeofday_cache_set(&tv); c3 = dummy_or_circuit_new(20,20); tv.tv_usec = 530*1000; tor_gettimeofday_cache_set(&tv); c4 = dummy_or_circuit_new(0,0); tt_int_op(cell_queues_get_total_allocation(), ==, packed_cell_mem_cost() * 80); tv.tv_usec = 600*1000; tor_gettimeofday_cache_set(&tv); /* Add some connections to c1...c4. */ for (i = 0; i < 4; ++i) { edge_connection_t *ec; /* link it to a circuit */ tv.tv_usec += 10*1000; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c1, CONN_TYPE_EXIT, 1000, 1000); tt_assert(ec); tv.tv_usec += 10*1000; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c2, CONN_TYPE_AP, 1000, 1000); tt_assert(ec); tv.tv_usec += 10*1000; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); /* Yes, 4 twice*/ tt_assert(ec); tv.tv_usec += 10*1000; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); tt_assert(ec); } tv.tv_sec += 1; tv.tv_usec = 0; tvms = (uint32_t) tv_to_msec(&tv); tt_int_op(circuit_max_queued_cell_age(c1, tvms), ==, 500); tt_int_op(circuit_max_queued_cell_age(c2, tvms), ==, 490); tt_int_op(circuit_max_queued_cell_age(c3, tvms), ==, 480); tt_int_op(circuit_max_queued_cell_age(c4, tvms), ==, 0); tt_int_op(circuit_max_queued_data_age(c1, tvms), ==, 390); tt_int_op(circuit_max_queued_data_age(c2, tvms), ==, 380); tt_int_op(circuit_max_queued_data_age(c3, tvms), ==, 0); tt_int_op(circuit_max_queued_data_age(c4, tvms), ==, 370); tt_int_op(circuit_max_queued_item_age(c1, tvms), ==, 500); tt_int_op(circuit_max_queued_item_age(c2, tvms), ==, 490); tt_int_op(circuit_max_queued_item_age(c3, tvms), ==, 480); tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 370); tt_int_op(cell_queues_get_total_allocation(), ==, packed_cell_mem_cost() * 80); tt_int_op(buf_get_total_allocation(), ==, 4096*16*2); /* Now give c4 a very old buffer of modest size */ { edge_connection_t *ec; tv.tv_sec -= 1; tv.tv_usec = 0; tor_gettimeofday_cache_set(&tv); ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); tt_assert(ec); } tt_int_op(buf_get_total_allocation(), ==, 4096*17*2); tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 1000); tt_int_op(cell_queues_check_size(), ==, 0); /* And run over the limit. */ tv.tv_usec = 800*1000; tor_gettimeofday_cache_set(&tv); c5 = dummy_or_circuit_new(0,5); tt_int_op(cell_queues_get_total_allocation(), ==, packed_cell_mem_cost() * 85); tt_int_op(buf_get_total_allocation(), ==, 4096*17*2); tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */ /* C4 should have died. */ tt_assert(! c1->marked_for_close); tt_assert(! c2->marked_for_close); tt_assert(! c3->marked_for_close); tt_assert(c4->marked_for_close); tt_assert(! c5->marked_for_close); tt_int_op(cell_queues_get_total_allocation(), ==, packed_cell_mem_cost() * 85); tt_int_op(buf_get_total_allocation(), ==, 4096*8*2); done: circuit_free(c1); circuit_free(c2); circuit_free(c3); circuit_free(c4); circuit_free(c5); UNMOCK(circuit_mark_for_close_); } struct testcase_t oom_tests[] = { { "circbuf", test_oom_circbuf, TT_FORK, NULL, NULL }, { "streambuf", test_oom_streambuf, TT_FORK, NULL, NULL }, END_OF_TESTCASES };