prop224: 'is_new_tp' -> 'use_second_hdsir_index' in hs_get_responsible_hsdirs()
[tor.git] / src / test / test_oom.c
blobcf28690a28c78ca9bbda586f7cfbb22e7d707035
1 /* Copyright (c) 2014-2017, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /* Unit tests for OOM handling logic */
6 #define RELAY_PRIVATE
7 #define BUFFERS_PRIVATE
8 #define CIRCUITLIST_PRIVATE
9 #define CONNECTION_PRIVATE
10 #include "or.h"
11 #include "buffers.h"
12 #include "circuitlist.h"
13 #include "compat_libevent.h"
14 #include "connection.h"
15 #include "config.h"
16 #include "relay.h"
17 #include "test.h"
18 #include "test_helpers.h"
20 /* small replacement mock for circuit_mark_for_close_ to avoid doing all
21 * the other bookkeeping that comes with marking circuits. */
22 static void
23 circuit_mark_for_close_dummy_(circuit_t *circ, int reason, int line,
24 const char *file)
26 (void) reason;
27 if (circ->marked_for_close) {
28 TT_FAIL(("Circuit already marked for close at %s:%d, but we are marking "
29 "it again at %s:%d",
30 circ->marked_for_close_file, (int)circ->marked_for_close,
31 file, line));
34 circ->marked_for_close = line;
35 circ->marked_for_close_file = file;
38 static circuit_t *
39 dummy_or_circuit_new(int n_p_cells, int n_n_cells)
41 or_circuit_t *circ = or_circuit_new(0, NULL);
42 int i;
43 cell_t cell;
45 for (i=0; i < n_p_cells; ++i) {
46 crypto_rand((void*)&cell, sizeof(cell));
47 cell_queue_append_packed_copy(TO_CIRCUIT(circ), &circ->p_chan_cells,
48 0, &cell, 1, 0);
51 for (i=0; i < n_n_cells; ++i) {
52 crypto_rand((void*)&cell, sizeof(cell));
53 cell_queue_append_packed_copy(TO_CIRCUIT(circ),
54 &TO_CIRCUIT(circ)->n_chan_cells,
55 1, &cell, 1, 0);
58 TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_OR;
59 return TO_CIRCUIT(circ);
62 static void
63 add_bytes_to_buf(buf_t *buf, size_t n_bytes)
65 char b[3000];
67 while (n_bytes) {
68 size_t this_add = n_bytes > sizeof(b) ? sizeof(b) : n_bytes;
69 crypto_rand(b, this_add);
70 buf_add(buf, b, this_add);
71 n_bytes -= this_add;
75 static edge_connection_t *
76 dummy_edge_conn_new(circuit_t *circ,
77 int type, size_t in_bytes, size_t out_bytes)
79 edge_connection_t *conn;
80 buf_t *inbuf, *outbuf;
82 if (type == CONN_TYPE_EXIT)
83 conn = edge_connection_new(type, AF_INET);
84 else
85 conn = ENTRY_TO_EDGE_CONN(entry_connection_new(type, AF_INET));
87 inbuf = TO_CONN(conn)->inbuf;
88 outbuf = TO_CONN(conn)->outbuf;
90 /* We add these bytes directly to the buffers, to avoid all the
91 * edge connection read/write machinery. */
92 add_bytes_to_buf(inbuf, in_bytes);
93 add_bytes_to_buf(outbuf, out_bytes);
95 conn->on_circuit = circ;
96 if (type == CONN_TYPE_EXIT) {
97 or_circuit_t *oc = TO_OR_CIRCUIT(circ);
98 conn->next_stream = oc->n_streams;
99 oc->n_streams = conn;
100 } else {
101 origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
102 conn->next_stream = oc->p_streams;
103 oc->p_streams = conn;
106 return conn;
109 /** Run unit tests for buffers.c */
110 static void
111 test_oom_circbuf(void *arg)
113 or_options_t *options = get_options_mutable();
114 circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL;
115 uint64_t now_ns = 1389631048 * (uint64_t)1000000000;
116 const uint64_t start_ns = now_ns;
118 (void) arg;
120 monotime_enable_test_mocking();
121 MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_);
123 /* Far too low for real life. */
124 options->MaxMemInQueues = 256*packed_cell_mem_cost();
125 options->CellStatistics = 0;
127 tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We don't start out OOM. */
128 tt_int_op(cell_queues_get_total_allocation(), OP_EQ, 0);
129 tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
131 /* Now we're going to fake up some circuits and get them added to the global
132 circuit list. */
133 monotime_coarse_set_mock_time_nsec(now_ns);
134 c1 = dummy_origin_circuit_new(30);
136 now_ns += 10 * 1000000;
137 monotime_coarse_set_mock_time_nsec(now_ns);
138 c2 = dummy_or_circuit_new(20, 20);
140 tt_int_op(packed_cell_mem_cost(), OP_EQ,
141 sizeof(packed_cell_t));
142 tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
143 packed_cell_mem_cost() * 70);
144 tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We are still not OOM */
146 now_ns += 10 * 1000000;
147 monotime_coarse_set_mock_time_nsec(now_ns);
148 c3 = dummy_or_circuit_new(100, 85);
149 tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We are still not OOM */
150 tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
151 packed_cell_mem_cost() * 255);
153 now_ns += 10 * 1000000;
154 monotime_coarse_set_mock_time_nsec(now_ns);
155 /* Adding this cell will trigger our OOM handler. */
156 c4 = dummy_or_circuit_new(2, 0);
158 tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
159 packed_cell_mem_cost() * 257);
161 tt_int_op(cell_queues_check_size(), OP_EQ, 1); /* We are now OOM */
163 tt_assert(c1->marked_for_close);
164 tt_assert(! c2->marked_for_close);
165 tt_assert(! c3->marked_for_close);
166 tt_assert(! c4->marked_for_close);
168 tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
169 packed_cell_mem_cost() * (257 - 30));
171 circuit_free(c1);
173 monotime_coarse_set_mock_time_nsec(start_ns); /* go back in time */
174 c1 = dummy_or_circuit_new(90, 0);
176 now_ns += 10 * 1000000;
177 monotime_coarse_set_mock_time_nsec(now_ns);
179 tt_int_op(cell_queues_check_size(), OP_EQ, 1); /* We are now OOM */
181 tt_assert(c1->marked_for_close);
182 tt_assert(! c2->marked_for_close);
183 tt_assert(! c3->marked_for_close);
184 tt_assert(! c4->marked_for_close);
186 tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
187 packed_cell_mem_cost() * (257 - 30));
189 done:
190 circuit_free(c1);
191 circuit_free(c2);
192 circuit_free(c3);
193 circuit_free(c4);
195 UNMOCK(circuit_mark_for_close_);
196 monotime_disable_test_mocking();
199 /** Run unit tests for buffers.c */
200 static void
201 test_oom_streambuf(void *arg)
203 or_options_t *options = get_options_mutable();
204 circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL, *c5 = NULL;
205 uint32_t tvms;
206 int i;
207 smartlist_t *edgeconns = smartlist_new();
208 const uint64_t start_ns = 1389641159 * (uint64_t)1000000000;
209 uint64_t now_ns = start_ns;
211 (void) arg;
212 monotime_enable_test_mocking();
214 MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_);
216 /* Far too low for real life. */
217 options->MaxMemInQueues = 81*packed_cell_mem_cost() + 4096 * 34;
218 options->CellStatistics = 0;
220 tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We don't start out OOM. */
221 tt_int_op(cell_queues_get_total_allocation(), OP_EQ, 0);
222 tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
224 monotime_coarse_set_mock_time_nsec(start_ns);
226 /* Start all circuits with a bit of data queued in cells */
228 /* go halfway into the second. */
229 monotime_coarse_set_mock_time_nsec(start_ns + 500 * 1000000);
230 c1 = dummy_or_circuit_new(10,10);
232 monotime_coarse_set_mock_time_nsec(start_ns + 510 * 1000000);
233 c2 = dummy_origin_circuit_new(20);
234 monotime_coarse_set_mock_time_nsec(start_ns + 520 * 1000000);
235 c3 = dummy_or_circuit_new(20,20);
236 monotime_coarse_set_mock_time_nsec(start_ns + 530 * 1000000);
237 c4 = dummy_or_circuit_new(0,0);
238 tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
239 packed_cell_mem_cost() * 80);
241 now_ns = start_ns + 600 * 1000000;
242 monotime_coarse_set_mock_time_nsec(now_ns);
244 /* Add some connections to c1...c4. */
245 for (i = 0; i < 4; ++i) {
246 edge_connection_t *ec;
247 /* link it to a circuit */
248 now_ns += 10 * 1000000;
249 monotime_coarse_set_mock_time_nsec(now_ns);
250 ec = dummy_edge_conn_new(c1, CONN_TYPE_EXIT, 1000, 1000);
251 tt_assert(ec);
252 smartlist_add(edgeconns, ec);
253 now_ns += 10 * 1000000;
254 monotime_coarse_set_mock_time_nsec(now_ns);
255 ec = dummy_edge_conn_new(c2, CONN_TYPE_AP, 1000, 1000);
256 tt_assert(ec);
257 smartlist_add(edgeconns, ec);
258 now_ns += 10 * 1000000;
259 monotime_coarse_set_mock_time_nsec(now_ns);
260 ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); /* Yes, 4 twice*/
261 tt_assert(ec);
262 smartlist_add(edgeconns, ec);
263 now_ns += 10 * 1000000;
264 monotime_coarse_set_mock_time_nsec(now_ns);
265 ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000);
266 smartlist_add(edgeconns, ec);
267 tt_assert(ec);
270 now_ns -= now_ns % 1000000000;
271 now_ns += 1000000000;
272 monotime_coarse_set_mock_time_nsec(now_ns);
273 tvms = (uint32_t) monotime_coarse_absolute_msec();
275 tt_int_op(circuit_max_queued_cell_age(c1, tvms), OP_EQ, 500);
276 tt_int_op(circuit_max_queued_cell_age(c2, tvms), OP_EQ, 490);
277 tt_int_op(circuit_max_queued_cell_age(c3, tvms), OP_EQ, 480);
278 tt_int_op(circuit_max_queued_cell_age(c4, tvms), OP_EQ, 0);
280 tt_int_op(circuit_max_queued_data_age(c1, tvms), OP_EQ, 390);
281 tt_int_op(circuit_max_queued_data_age(c2, tvms), OP_EQ, 380);
282 tt_int_op(circuit_max_queued_data_age(c3, tvms), OP_EQ, 0);
283 tt_int_op(circuit_max_queued_data_age(c4, tvms), OP_EQ, 370);
285 tt_int_op(circuit_max_queued_item_age(c1, tvms), OP_EQ, 500);
286 tt_int_op(circuit_max_queued_item_age(c2, tvms), OP_EQ, 490);
287 tt_int_op(circuit_max_queued_item_age(c3, tvms), OP_EQ, 480);
288 tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 370);
290 tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
291 packed_cell_mem_cost() * 80);
292 tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*16*2);
294 /* Now give c4 a very old buffer of modest size */
296 edge_connection_t *ec;
297 now_ns -= 1000000000;
298 monotime_coarse_set_mock_time_nsec(now_ns);
299 ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000);
300 tt_assert(ec);
301 smartlist_add(edgeconns, ec);
303 tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2);
304 tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 1000);
306 tt_int_op(cell_queues_check_size(), OP_EQ, 0);
308 /* And run over the limit. */
309 now_ns += 800*1000000;
310 monotime_coarse_set_mock_time_nsec(now_ns);
311 c5 = dummy_or_circuit_new(0,5);
313 tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
314 packed_cell_mem_cost() * 85);
315 tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2);
317 tt_int_op(cell_queues_check_size(), OP_EQ, 1); /* We are now OOM */
319 /* C4 should have died. */
320 tt_assert(! c1->marked_for_close);
321 tt_assert(! c2->marked_for_close);
322 tt_assert(! c3->marked_for_close);
323 tt_assert(c4->marked_for_close);
324 tt_assert(! c5->marked_for_close);
326 tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
327 packed_cell_mem_cost() * 85);
328 tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*8*2);
330 done:
331 circuit_free(c1);
332 circuit_free(c2);
333 circuit_free(c3);
334 circuit_free(c4);
335 circuit_free(c5);
337 SMARTLIST_FOREACH(edgeconns, edge_connection_t *, ec,
338 connection_free_(TO_CONN(ec)));
339 smartlist_free(edgeconns);
341 UNMOCK(circuit_mark_for_close_);
342 monotime_disable_test_mocking();
345 struct testcase_t oom_tests[] = {
346 { "circbuf", test_oom_circbuf, TT_FORK, NULL, NULL },
347 { "streambuf", test_oom_streambuf, TT_FORK, NULL, NULL },
348 END_OF_TESTCASES