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