1a6cc1574Ssthen /*
2a6cc1574Ssthen * testcode/unittcpreuse.c - unit test for tcp_reuse.
3a6cc1574Ssthen *
4a6cc1574Ssthen * Copyright (c) 2021, NLnet Labs. All rights reserved.
5a6cc1574Ssthen *
6a6cc1574Ssthen * This software is open source.
7a6cc1574Ssthen *
8a6cc1574Ssthen * Redistribution and use in source and binary forms, with or without
9a6cc1574Ssthen * modification, are permitted provided that the following conditions
10a6cc1574Ssthen * are met:
11a6cc1574Ssthen *
12a6cc1574Ssthen * Redistributions of source code must retain the above copyright notice,
13a6cc1574Ssthen * this list of conditions and the following disclaimer.
14a6cc1574Ssthen *
15a6cc1574Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16a6cc1574Ssthen * this list of conditions and the following disclaimer in the documentation
17a6cc1574Ssthen * and/or other materials provided with the distribution.
18a6cc1574Ssthen *
19a6cc1574Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20a6cc1574Ssthen * be used to endorse or promote products derived from this software without
21a6cc1574Ssthen * specific prior written permission.
22a6cc1574Ssthen *
23a6cc1574Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24a6cc1574Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25a6cc1574Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26a6cc1574Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27a6cc1574Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28a6cc1574Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29a6cc1574Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30a6cc1574Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31a6cc1574Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32a6cc1574Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33a6cc1574Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34a6cc1574Ssthen *
35a6cc1574Ssthen */
36a6cc1574Ssthen /**
37a6cc1574Ssthen * \file
38a6cc1574Ssthen * Tests the tcp_reuse functionality.
39a6cc1574Ssthen */
40a6cc1574Ssthen
41a6cc1574Ssthen #include "config.h"
42a6cc1574Ssthen #include "testcode/unitmain.h"
43a6cc1574Ssthen #include "util/log.h"
44a6cc1574Ssthen #include "util/random.h"
45a6cc1574Ssthen #include "services/outside_network.h"
46a6cc1574Ssthen
47*0e9b6f9fSsthen #define MAX_TCP_WAITING_NODES 5
48*0e9b6f9fSsthen
49a6cc1574Ssthen /** add number of new IDs to the reuse tree, randomly chosen */
tcpid_addmore(struct reuse_tcp * reuse,struct outside_network * outnet,unsigned int addnum)50a6cc1574Ssthen static void tcpid_addmore(struct reuse_tcp* reuse,
51a6cc1574Ssthen struct outside_network* outnet, unsigned int addnum)
52a6cc1574Ssthen {
53a6cc1574Ssthen unsigned int i;
54a6cc1574Ssthen struct waiting_tcp* w;
55a6cc1574Ssthen for(i=0; i<addnum; i++) {
56a6cc1574Ssthen uint16_t id = reuse_tcp_select_id(reuse, outnet);
57a6cc1574Ssthen unit_assert(!reuse_tcp_by_id_find(reuse, id));
58a6cc1574Ssthen w = calloc(1, sizeof(*w));
59a6cc1574Ssthen unit_assert(w);
60a6cc1574Ssthen w->id = id;
61a6cc1574Ssthen w->outnet = outnet;
62a6cc1574Ssthen w->next_waiting = (void*)reuse->pending;
63a6cc1574Ssthen reuse_tree_by_id_insert(reuse, w);
64a6cc1574Ssthen }
65a6cc1574Ssthen }
66a6cc1574Ssthen
67a6cc1574Ssthen /** fill up the reuse ID tree and test assertions */
tcpid_fillup(struct reuse_tcp * reuse,struct outside_network * outnet)68a6cc1574Ssthen static void tcpid_fillup(struct reuse_tcp* reuse,
69a6cc1574Ssthen struct outside_network* outnet)
70a6cc1574Ssthen {
71a6cc1574Ssthen int t, numtest=3;
72a6cc1574Ssthen for(t=0; t<numtest; t++) {
73a6cc1574Ssthen rbtree_init(&reuse->tree_by_id, reuse_id_cmp);
74a6cc1574Ssthen tcpid_addmore(reuse, outnet, 65535);
75a6cc1574Ssthen reuse_del_readwait(&reuse->tree_by_id);
76a6cc1574Ssthen }
77a6cc1574Ssthen }
78a6cc1574Ssthen
79a6cc1574Ssthen /** test TCP ID selection */
tcpid_test(void)80a6cc1574Ssthen static void tcpid_test(void)
81a6cc1574Ssthen {
82a6cc1574Ssthen struct pending_tcp pend;
83a6cc1574Ssthen struct outside_network outnet;
84a6cc1574Ssthen unit_show_func("services/outside_network.c", "reuse_tcp_select_id");
85a6cc1574Ssthen memset(&pend, 0, sizeof(pend));
86a6cc1574Ssthen pend.reuse.pending = &pend;
87a6cc1574Ssthen memset(&outnet, 0, sizeof(outnet));
88a6cc1574Ssthen outnet.rnd = ub_initstate(NULL);
89a6cc1574Ssthen rbtree_init(&pend.reuse.tree_by_id, reuse_id_cmp);
90a6cc1574Ssthen tcpid_fillup(&pend.reuse, &outnet);
91a6cc1574Ssthen ub_randfree(outnet.rnd);
92a6cc1574Ssthen }
93a6cc1574Ssthen
94a6cc1574Ssthen /** check that the tree has present number of nodes and the LRU is linked
95a6cc1574Ssthen * properly. */
check_tree_and_list(struct outside_network * outnet,int present)96a6cc1574Ssthen static void check_tree_and_list(struct outside_network* outnet, int present)
97a6cc1574Ssthen {
98a6cc1574Ssthen int i;
99a6cc1574Ssthen struct reuse_tcp *reuse, *next_reuse;
100a6cc1574Ssthen unit_assert(present == (int)outnet->tcp_reuse.count);
101a6cc1574Ssthen if(present < 1) {
102a6cc1574Ssthen unit_assert(outnet->tcp_reuse_first == NULL);
103a6cc1574Ssthen unit_assert(outnet->tcp_reuse_last == NULL);
104a6cc1574Ssthen return;
105a6cc1574Ssthen }
106a6cc1574Ssthen unit_assert(outnet->tcp_reuse_first->item_on_lru_list);
107a6cc1574Ssthen unit_assert(!outnet->tcp_reuse_first->lru_prev);
108a6cc1574Ssthen reuse = outnet->tcp_reuse_first;
109a6cc1574Ssthen for(i=0; i<present-1; i++) {
110a6cc1574Ssthen unit_assert(reuse->item_on_lru_list);
111a6cc1574Ssthen unit_assert(reuse->lru_next);
112a6cc1574Ssthen unit_assert(reuse->lru_next != reuse);
113a6cc1574Ssthen next_reuse = reuse->lru_next;
114a6cc1574Ssthen unit_assert(next_reuse->lru_prev == reuse);
115a6cc1574Ssthen reuse = next_reuse;
116a6cc1574Ssthen }
117a6cc1574Ssthen unit_assert(!reuse->lru_next);
118a6cc1574Ssthen unit_assert(outnet->tcp_reuse_last->item_on_lru_list);
119a6cc1574Ssthen unit_assert(outnet->tcp_reuse_last == reuse);
120a6cc1574Ssthen }
121a6cc1574Ssthen
122a6cc1574Ssthen /** creates pending_tcp. Copy of outside_network.c:create_pending_tcp without
123a6cc1574Ssthen * the comm_point creation */
create_pending_tcp(struct outside_network * outnet)124a6cc1574Ssthen static int create_pending_tcp(struct outside_network* outnet)
125a6cc1574Ssthen {
126a6cc1574Ssthen size_t i;
127a6cc1574Ssthen if(outnet->num_tcp == 0)
128a6cc1574Ssthen return 1; /* no tcp needed, nothing to do */
129a6cc1574Ssthen if(!(outnet->tcp_conns = (struct pending_tcp **)calloc(
130a6cc1574Ssthen outnet->num_tcp, sizeof(struct pending_tcp*))))
131a6cc1574Ssthen return 0;
132a6cc1574Ssthen for(i=0; i<outnet->num_tcp; i++) {
133a6cc1574Ssthen if(!(outnet->tcp_conns[i] = (struct pending_tcp*)calloc(1,
134a6cc1574Ssthen sizeof(struct pending_tcp))))
135a6cc1574Ssthen return 0;
136a6cc1574Ssthen outnet->tcp_conns[i]->next_free = outnet->tcp_free;
137a6cc1574Ssthen outnet->tcp_free = outnet->tcp_conns[i];
138a6cc1574Ssthen }
139a6cc1574Ssthen return 1;
140a6cc1574Ssthen }
141a6cc1574Ssthen
142a6cc1574Ssthen /** empty the tcp_reuse tree and LRU list */
empty_tree(struct outside_network * outnet)143a6cc1574Ssthen static void empty_tree(struct outside_network* outnet)
144a6cc1574Ssthen {
145a6cc1574Ssthen size_t i;
146a6cc1574Ssthen struct reuse_tcp* reuse;
147a6cc1574Ssthen reuse = outnet->tcp_reuse_first;
148a6cc1574Ssthen i = outnet->tcp_reuse.count;
149a6cc1574Ssthen while(reuse) {
150a6cc1574Ssthen reuse_tcp_remove_tree_list(outnet, reuse);
151a6cc1574Ssthen check_tree_and_list(outnet, --i);
152a6cc1574Ssthen reuse = outnet->tcp_reuse_first;
153a6cc1574Ssthen }
154a6cc1574Ssthen }
155a6cc1574Ssthen
156a6cc1574Ssthen /** check removal of the LRU element on the given position of total elements */
check_removal(struct outside_network * outnet,int position,int total)157a6cc1574Ssthen static void check_removal(struct outside_network* outnet, int position, int total)
158a6cc1574Ssthen {
159a6cc1574Ssthen int i;
160a6cc1574Ssthen struct reuse_tcp* reuse;
161a6cc1574Ssthen empty_tree(outnet);
162a6cc1574Ssthen for(i=0; i<total; i++) {
163a6cc1574Ssthen reuse_tcp_insert(outnet, outnet->tcp_conns[i]);
164a6cc1574Ssthen }
165a6cc1574Ssthen check_tree_and_list(outnet, total);
166a6cc1574Ssthen reuse = outnet->tcp_reuse_first;
167a6cc1574Ssthen for(i=0; i<position; i++) reuse = reuse->lru_next;
168a6cc1574Ssthen reuse_tcp_remove_tree_list(outnet, reuse);
169a6cc1574Ssthen check_tree_and_list(outnet, total-1);
170a6cc1574Ssthen }
171a6cc1574Ssthen
172a6cc1574Ssthen /** check snipping off the last element of the LRU with total elements */
check_snip(struct outside_network * outnet,int total)173a6cc1574Ssthen static void check_snip(struct outside_network* outnet, int total)
174a6cc1574Ssthen {
175a6cc1574Ssthen int i;
176a6cc1574Ssthen struct reuse_tcp* reuse;
177a6cc1574Ssthen empty_tree(outnet);
178a6cc1574Ssthen for(i=0; i<total; i++) {
179a6cc1574Ssthen reuse_tcp_insert(outnet, outnet->tcp_conns[i]);
180a6cc1574Ssthen }
181a6cc1574Ssthen check_tree_and_list(outnet, total);
182a6cc1574Ssthen reuse = reuse_tcp_lru_snip(outnet);
183a6cc1574Ssthen while(reuse) {
184a6cc1574Ssthen reuse_tcp_remove_tree_list(outnet, reuse);
185a6cc1574Ssthen check_tree_and_list(outnet, --total);
186a6cc1574Ssthen reuse = reuse_tcp_lru_snip(outnet);
187a6cc1574Ssthen }
188a6cc1574Ssthen unit_assert(outnet->tcp_reuse_first == NULL);
189a6cc1574Ssthen unit_assert(outnet->tcp_reuse_last == NULL);
190a6cc1574Ssthen unit_assert(outnet->tcp_reuse.count == 0);
191a6cc1574Ssthen }
192a6cc1574Ssthen
193a6cc1574Ssthen /** test tcp_reuse tree and LRU list functions */
tcp_reuse_tree_list_test(void)194a6cc1574Ssthen static void tcp_reuse_tree_list_test(void)
195a6cc1574Ssthen {
196a6cc1574Ssthen size_t i;
197a6cc1574Ssthen struct outside_network outnet;
198a6cc1574Ssthen struct reuse_tcp* reuse;
199a6cc1574Ssthen memset(&outnet, 0, sizeof(outnet));
200a6cc1574Ssthen rbtree_init(&outnet.tcp_reuse, reuse_cmp);
201a6cc1574Ssthen outnet.num_tcp = 5;
202a6cc1574Ssthen outnet.tcp_reuse_max = outnet.num_tcp;
203a6cc1574Ssthen if(!create_pending_tcp(&outnet)) fatal_exit("out of memory");
204a6cc1574Ssthen /* add all to the tree */
205a6cc1574Ssthen unit_show_func("services/outside_network.c", "reuse_tcp_insert");
206a6cc1574Ssthen for(i=0; i<outnet.num_tcp; i++) {
207a6cc1574Ssthen reuse_tcp_insert(&outnet, outnet.tcp_conns[i]);
208a6cc1574Ssthen check_tree_and_list(&outnet, i+1);
209a6cc1574Ssthen }
210a6cc1574Ssthen /* check touching */
211a6cc1574Ssthen unit_show_func("services/outside_network.c", "reuse_tcp_lru_touch");
212a6cc1574Ssthen for(i=0; i<outnet.tcp_reuse.count; i++) {
213a6cc1574Ssthen for(reuse = outnet.tcp_reuse_first; reuse->lru_next; reuse = reuse->lru_next);
214a6cc1574Ssthen reuse_tcp_lru_touch(&outnet, reuse);
215a6cc1574Ssthen check_tree_and_list(&outnet, outnet.num_tcp);
216a6cc1574Ssthen }
217a6cc1574Ssthen /* check removal */
218a6cc1574Ssthen unit_show_func("services/outside_network.c", "reuse_tcp_remove_tree_list");
219a6cc1574Ssthen check_removal(&outnet, 2, 5);
220a6cc1574Ssthen check_removal(&outnet, 1, 3);
221a6cc1574Ssthen check_removal(&outnet, 1, 2);
222a6cc1574Ssthen /* check snip */
223a6cc1574Ssthen unit_show_func("services/outside_network.c", "reuse_tcp_lru_snip");
224a6cc1574Ssthen check_snip(&outnet, 4);
225a6cc1574Ssthen
226a6cc1574Ssthen for(i=0; i<outnet.num_tcp; i++)
227a6cc1574Ssthen if(outnet.tcp_conns[i]) {
228a6cc1574Ssthen free(outnet.tcp_conns[i]);
229a6cc1574Ssthen }
230a6cc1574Ssthen free(outnet.tcp_conns);
231a6cc1574Ssthen }
232a6cc1574Ssthen
check_waiting_tcp_list(struct outside_network * outnet,struct waiting_tcp * first,struct waiting_tcp * last,size_t total)233*0e9b6f9fSsthen static void check_waiting_tcp_list(struct outside_network* outnet,
234*0e9b6f9fSsthen struct waiting_tcp* first, struct waiting_tcp* last, size_t total)
235*0e9b6f9fSsthen {
236*0e9b6f9fSsthen size_t i, j;
237*0e9b6f9fSsthen struct waiting_tcp* w = outnet->tcp_wait_first;
238*0e9b6f9fSsthen struct waiting_tcp* n = NULL;
239*0e9b6f9fSsthen if(first) unit_assert(outnet->tcp_wait_first == first);
240*0e9b6f9fSsthen if(last) unit_assert(outnet->tcp_wait_last == last && !last->next_waiting);
241*0e9b6f9fSsthen for(i=0; w; i++) {
242*0e9b6f9fSsthen unit_assert(i<total); /* otherwise we are looping */
243*0e9b6f9fSsthen unit_assert(w->on_tcp_waiting_list);
244*0e9b6f9fSsthen n = w->next_waiting;
245*0e9b6f9fSsthen for(j=0; n; j++) {
246*0e9b6f9fSsthen unit_assert(j<total-i-1); /* otherwise we are looping */
247*0e9b6f9fSsthen unit_assert(n != w);
248*0e9b6f9fSsthen n = n->next_waiting;
249*0e9b6f9fSsthen }
250*0e9b6f9fSsthen w = w->next_waiting;
251*0e9b6f9fSsthen }
252*0e9b6f9fSsthen }
253*0e9b6f9fSsthen
254*0e9b6f9fSsthen /** clear the tcp waiting list */
waiting_tcp_list_clear(struct outside_network * outnet)255*0e9b6f9fSsthen static void waiting_tcp_list_clear(struct outside_network* outnet)
256*0e9b6f9fSsthen {
257*0e9b6f9fSsthen struct waiting_tcp* w = outnet->tcp_wait_first, *n = NULL;
258*0e9b6f9fSsthen if(!w) return;
259*0e9b6f9fSsthen unit_assert(outnet->tcp_wait_first);
260*0e9b6f9fSsthen unit_assert(outnet->tcp_wait_last);
261*0e9b6f9fSsthen while(w) {
262*0e9b6f9fSsthen n = w->next_waiting;
263*0e9b6f9fSsthen w->on_tcp_waiting_list = 0;
264*0e9b6f9fSsthen w->next_waiting = (struct waiting_tcp*)1; /* In purpose faux value */
265*0e9b6f9fSsthen w = n;
266*0e9b6f9fSsthen }
267*0e9b6f9fSsthen outnet->tcp_wait_first = NULL;
268*0e9b6f9fSsthen outnet->tcp_wait_last = NULL;
269*0e9b6f9fSsthen }
270*0e9b6f9fSsthen
271*0e9b6f9fSsthen /** check removal of the waiting_tcp element on the given position of total
272*0e9b6f9fSsthen * elements */
check_waiting_tcp_removal(int is_pop,struct outside_network * outnet,struct waiting_tcp * store,size_t position,size_t total)273*0e9b6f9fSsthen static void check_waiting_tcp_removal(int is_pop,
274*0e9b6f9fSsthen struct outside_network* outnet, struct waiting_tcp* store,
275*0e9b6f9fSsthen size_t position, size_t total)
276*0e9b6f9fSsthen {
277*0e9b6f9fSsthen size_t i;
278*0e9b6f9fSsthen struct waiting_tcp* w;
279*0e9b6f9fSsthen waiting_tcp_list_clear(outnet);
280*0e9b6f9fSsthen for(i=0; i<total; i++) {
281*0e9b6f9fSsthen outnet_waiting_tcp_list_add(outnet, &store[i], 0);
282*0e9b6f9fSsthen }
283*0e9b6f9fSsthen check_waiting_tcp_list(outnet, &store[0], &store[total-1], total);
284*0e9b6f9fSsthen
285*0e9b6f9fSsthen if(is_pop) {
286*0e9b6f9fSsthen w = outnet_waiting_tcp_list_pop(outnet);
287*0e9b6f9fSsthen unit_assert(w); /* please clang-analyser */
288*0e9b6f9fSsthen } else {
289*0e9b6f9fSsthen w = outnet->tcp_wait_first;
290*0e9b6f9fSsthen for(i=0; i<position; i++) {
291*0e9b6f9fSsthen unit_assert(w); /* please clang-analyser */
292*0e9b6f9fSsthen w = w->next_waiting;
293*0e9b6f9fSsthen }
294*0e9b6f9fSsthen unit_assert(w); /* please clang-analyser */
295*0e9b6f9fSsthen outnet_waiting_tcp_list_remove(outnet, w);
296*0e9b6f9fSsthen }
297*0e9b6f9fSsthen unit_assert(!(w->on_tcp_waiting_list || w->next_waiting));
298*0e9b6f9fSsthen
299*0e9b6f9fSsthen if(position == 0 && total == 1) {
300*0e9b6f9fSsthen /* the list should be empty */
301*0e9b6f9fSsthen check_waiting_tcp_list(outnet, NULL, NULL, total-1);
302*0e9b6f9fSsthen } else if(position == 0) {
303*0e9b6f9fSsthen /* first element should be gone */
304*0e9b6f9fSsthen check_waiting_tcp_list(outnet, &store[1], &store[total-1], total-1);
305*0e9b6f9fSsthen } else if(position == total - 1) {
306*0e9b6f9fSsthen /* last element should be gone */
307*0e9b6f9fSsthen check_waiting_tcp_list(outnet, &store[0], &store[total-2], total-1);
308*0e9b6f9fSsthen } else {
309*0e9b6f9fSsthen /* an element should be gone */
310*0e9b6f9fSsthen check_waiting_tcp_list(outnet, &store[0], &store[total-1], total-1);
311*0e9b6f9fSsthen }
312*0e9b6f9fSsthen }
313*0e9b6f9fSsthen
waiting_tcp_list_test(void)314*0e9b6f9fSsthen static void waiting_tcp_list_test(void)
315*0e9b6f9fSsthen {
316*0e9b6f9fSsthen size_t i = 0;
317*0e9b6f9fSsthen struct outside_network outnet;
318*0e9b6f9fSsthen struct waiting_tcp* w, *t = NULL;
319*0e9b6f9fSsthen struct waiting_tcp store[MAX_TCP_WAITING_NODES];
320*0e9b6f9fSsthen memset(&outnet, 0, sizeof(outnet));
321*0e9b6f9fSsthen memset(&store, 0, sizeof(store));
322*0e9b6f9fSsthen
323*0e9b6f9fSsthen /* Check add first on empty list */
324*0e9b6f9fSsthen unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_add_first");
325*0e9b6f9fSsthen t = &store[i];
326*0e9b6f9fSsthen outnet_waiting_tcp_list_add_first(&outnet, t, 0);
327*0e9b6f9fSsthen check_waiting_tcp_list(&outnet, t, t, 1);
328*0e9b6f9fSsthen
329*0e9b6f9fSsthen /* Check add */
330*0e9b6f9fSsthen unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_add");
331*0e9b6f9fSsthen for(i=1; i<MAX_TCP_WAITING_NODES-1; i++) {
332*0e9b6f9fSsthen w = &store[i];
333*0e9b6f9fSsthen outnet_waiting_tcp_list_add(&outnet, w, 0);
334*0e9b6f9fSsthen }
335*0e9b6f9fSsthen check_waiting_tcp_list(&outnet, t, w, MAX_TCP_WAITING_NODES-1);
336*0e9b6f9fSsthen
337*0e9b6f9fSsthen /* Check add first on populated list */
338*0e9b6f9fSsthen unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_add_first");
339*0e9b6f9fSsthen w = &store[i];
340*0e9b6f9fSsthen t = outnet.tcp_wait_last;
341*0e9b6f9fSsthen outnet_waiting_tcp_list_add_first(&outnet, w, 0);
342*0e9b6f9fSsthen check_waiting_tcp_list(&outnet, w, t, MAX_TCP_WAITING_NODES);
343*0e9b6f9fSsthen
344*0e9b6f9fSsthen /* Check removal */
345*0e9b6f9fSsthen unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_remove");
346*0e9b6f9fSsthen check_waiting_tcp_removal(0, &outnet, store, 2, 5);
347*0e9b6f9fSsthen check_waiting_tcp_removal(0, &outnet, store, 1, 3);
348*0e9b6f9fSsthen check_waiting_tcp_removal(0, &outnet, store, 0, 2);
349*0e9b6f9fSsthen check_waiting_tcp_removal(0, &outnet, store, 1, 2);
350*0e9b6f9fSsthen check_waiting_tcp_removal(0, &outnet, store, 0, 1);
351*0e9b6f9fSsthen
352*0e9b6f9fSsthen /* Check pop */
353*0e9b6f9fSsthen unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_pop");
354*0e9b6f9fSsthen check_waiting_tcp_removal(1, &outnet, store, 0, 3);
355*0e9b6f9fSsthen check_waiting_tcp_removal(1, &outnet, store, 0, 2);
356*0e9b6f9fSsthen check_waiting_tcp_removal(1, &outnet, store, 0, 1);
357*0e9b6f9fSsthen }
358*0e9b6f9fSsthen
check_reuse_write_wait(struct reuse_tcp * reuse,struct waiting_tcp * first,struct waiting_tcp * last,size_t total)359*0e9b6f9fSsthen static void check_reuse_write_wait(struct reuse_tcp* reuse,
360*0e9b6f9fSsthen struct waiting_tcp* first, struct waiting_tcp* last, size_t total)
361*0e9b6f9fSsthen {
362*0e9b6f9fSsthen size_t i, j;
363*0e9b6f9fSsthen struct waiting_tcp* w = reuse->write_wait_first;
364*0e9b6f9fSsthen struct waiting_tcp* n = NULL;
365*0e9b6f9fSsthen if(first) unit_assert(reuse->write_wait_first == first && !first->write_wait_prev);
366*0e9b6f9fSsthen if(last) unit_assert(reuse->write_wait_last == last && !last->write_wait_next);
367*0e9b6f9fSsthen /* check one way */
368*0e9b6f9fSsthen for(i=0; w; i++) {
369*0e9b6f9fSsthen unit_assert(i<total); /* otherwise we are looping */
370*0e9b6f9fSsthen unit_assert(w->write_wait_queued);
371*0e9b6f9fSsthen n = w->write_wait_next;
372*0e9b6f9fSsthen for(j=0; n; j++) {
373*0e9b6f9fSsthen unit_assert(j<total-i-1); /* otherwise we are looping */
374*0e9b6f9fSsthen unit_assert(n != w);
375*0e9b6f9fSsthen n = n->write_wait_next;
376*0e9b6f9fSsthen }
377*0e9b6f9fSsthen w = w->write_wait_next;
378*0e9b6f9fSsthen }
379*0e9b6f9fSsthen /* check the other way */
380*0e9b6f9fSsthen w = reuse->write_wait_last;
381*0e9b6f9fSsthen for(i=0; w; i++) {
382*0e9b6f9fSsthen unit_assert(i<total); /* otherwise we are looping */
383*0e9b6f9fSsthen unit_assert(w->write_wait_queued);
384*0e9b6f9fSsthen n = w->write_wait_prev;
385*0e9b6f9fSsthen for(j=0; n; j++) {
386*0e9b6f9fSsthen unit_assert(j<total-i-1); /* otherwise we are looping */
387*0e9b6f9fSsthen unit_assert(n != w);
388*0e9b6f9fSsthen n = n->write_wait_prev;
389*0e9b6f9fSsthen }
390*0e9b6f9fSsthen w = w->write_wait_prev;
391*0e9b6f9fSsthen }
392*0e9b6f9fSsthen }
393*0e9b6f9fSsthen
394*0e9b6f9fSsthen /** clear the tcp waiting list */
reuse_write_wait_clear(struct reuse_tcp * reuse)395*0e9b6f9fSsthen static void reuse_write_wait_clear(struct reuse_tcp* reuse)
396*0e9b6f9fSsthen {
397*0e9b6f9fSsthen struct waiting_tcp* w = reuse->write_wait_first, *n = NULL;
398*0e9b6f9fSsthen if(!w) return;
399*0e9b6f9fSsthen unit_assert(reuse->write_wait_first);
400*0e9b6f9fSsthen unit_assert(reuse->write_wait_last);
401*0e9b6f9fSsthen while(w) {
402*0e9b6f9fSsthen n = w->write_wait_next;
403*0e9b6f9fSsthen w->write_wait_queued = 0;
404*0e9b6f9fSsthen w->write_wait_next = (struct waiting_tcp*)1; /* In purpose faux value */
405*0e9b6f9fSsthen w->write_wait_prev = (struct waiting_tcp*)1; /* In purpose faux value */
406*0e9b6f9fSsthen w = n;
407*0e9b6f9fSsthen }
408*0e9b6f9fSsthen reuse->write_wait_first = NULL;
409*0e9b6f9fSsthen reuse->write_wait_last = NULL;
410*0e9b6f9fSsthen }
411*0e9b6f9fSsthen
412*0e9b6f9fSsthen /** check removal of the reuse_write_wait element on the given position of total
413*0e9b6f9fSsthen * elements */
check_reuse_write_wait_removal(int is_pop,struct reuse_tcp * reuse,struct waiting_tcp * store,size_t position,size_t total)414*0e9b6f9fSsthen static void check_reuse_write_wait_removal(int is_pop,
415*0e9b6f9fSsthen struct reuse_tcp* reuse, struct waiting_tcp* store,
416*0e9b6f9fSsthen size_t position, size_t total)
417*0e9b6f9fSsthen {
418*0e9b6f9fSsthen size_t i;
419*0e9b6f9fSsthen struct waiting_tcp* w;
420*0e9b6f9fSsthen reuse_write_wait_clear(reuse);
421*0e9b6f9fSsthen for(i=0; i<total; i++) {
422*0e9b6f9fSsthen reuse_write_wait_push_back(reuse, &store[i]);
423*0e9b6f9fSsthen }
424*0e9b6f9fSsthen check_reuse_write_wait(reuse, &store[0], &store[total-1], total);
425*0e9b6f9fSsthen
426*0e9b6f9fSsthen if(is_pop) {
427*0e9b6f9fSsthen w = reuse_write_wait_pop(reuse);
428*0e9b6f9fSsthen } else {
429*0e9b6f9fSsthen w = reuse->write_wait_first;
430*0e9b6f9fSsthen for(i=0; i<position; i++) w = w->write_wait_next;
431*0e9b6f9fSsthen reuse_write_wait_remove(reuse, w);
432*0e9b6f9fSsthen }
433*0e9b6f9fSsthen unit_assert(!(w->write_wait_queued || w->write_wait_next || w->write_wait_prev));
434*0e9b6f9fSsthen
435*0e9b6f9fSsthen if(position == 0 && total == 1) {
436*0e9b6f9fSsthen /* the list should be empty */
437*0e9b6f9fSsthen check_reuse_write_wait(reuse, NULL, NULL, total-1);
438*0e9b6f9fSsthen } else if(position == 0) {
439*0e9b6f9fSsthen /* first element should be gone */
440*0e9b6f9fSsthen check_reuse_write_wait(reuse, &store[1], &store[total-1], total-1);
441*0e9b6f9fSsthen } else if(position == total - 1) {
442*0e9b6f9fSsthen /* last element should be gone */
443*0e9b6f9fSsthen check_reuse_write_wait(reuse, &store[0], &store[total-2], total-1);
444*0e9b6f9fSsthen } else {
445*0e9b6f9fSsthen /* an element should be gone */
446*0e9b6f9fSsthen check_reuse_write_wait(reuse, &store[0], &store[total-1], total-1);
447*0e9b6f9fSsthen }
448*0e9b6f9fSsthen }
449*0e9b6f9fSsthen
reuse_write_wait_test(void)450*0e9b6f9fSsthen static void reuse_write_wait_test(void)
451*0e9b6f9fSsthen {
452*0e9b6f9fSsthen size_t i;
453*0e9b6f9fSsthen struct reuse_tcp reuse;
454*0e9b6f9fSsthen struct waiting_tcp store[MAX_TCP_WAITING_NODES];
455*0e9b6f9fSsthen struct waiting_tcp* w;
456*0e9b6f9fSsthen memset(&reuse, 0, sizeof(reuse));
457*0e9b6f9fSsthen memset(&store, 0, sizeof(store));
458*0e9b6f9fSsthen
459*0e9b6f9fSsthen /* Check adding */
460*0e9b6f9fSsthen unit_show_func("services/outside_network.c", "reuse_write_wait_push_back");
461*0e9b6f9fSsthen for(i=0; i<MAX_TCP_WAITING_NODES; i++) {
462*0e9b6f9fSsthen w = &store[i];
463*0e9b6f9fSsthen reuse_write_wait_push_back(&reuse, w);
464*0e9b6f9fSsthen }
465*0e9b6f9fSsthen check_reuse_write_wait(&reuse, &store[0], w, MAX_TCP_WAITING_NODES);
466*0e9b6f9fSsthen
467*0e9b6f9fSsthen /* Check removal */
468*0e9b6f9fSsthen unit_show_func("services/outside_network.c", "reuse_write_wait_remove");
469*0e9b6f9fSsthen check_reuse_write_wait_removal(0, &reuse, store, 2, 5);
470*0e9b6f9fSsthen check_reuse_write_wait_removal(0, &reuse, store, 1, 3);
471*0e9b6f9fSsthen check_reuse_write_wait_removal(0, &reuse, store, 0, 2);
472*0e9b6f9fSsthen check_reuse_write_wait_removal(0, &reuse, store, 1, 2);
473*0e9b6f9fSsthen check_reuse_write_wait_removal(0, &reuse, store, 0, 1);
474*0e9b6f9fSsthen
475*0e9b6f9fSsthen /* Check pop */
476*0e9b6f9fSsthen unit_show_func("services/outside_network.c", "reuse_write_wait_pop");
477*0e9b6f9fSsthen check_reuse_write_wait_removal(1, &reuse, store, 0, 3);
478*0e9b6f9fSsthen check_reuse_write_wait_removal(1, &reuse, store, 0, 2);
479*0e9b6f9fSsthen check_reuse_write_wait_removal(1, &reuse, store, 0, 1);
480*0e9b6f9fSsthen }
481*0e9b6f9fSsthen
tcpreuse_test(void)482a6cc1574Ssthen void tcpreuse_test(void)
483a6cc1574Ssthen {
484a6cc1574Ssthen unit_show_feature("tcp_reuse");
485a6cc1574Ssthen tcpid_test();
486a6cc1574Ssthen tcp_reuse_tree_list_test();
487*0e9b6f9fSsthen waiting_tcp_list_test();
488*0e9b6f9fSsthen reuse_write_wait_test();
489a6cc1574Ssthen }
490