From: W.C.A. Wijngaards Date: Wed, 21 Oct 2020 07:49:55 +0000 (+0200) Subject: - Fix that reuse_tcp_close_oldest sets item_on_lru_list to 0. X-Git-Tag: release-1.13.0rc1~5^2~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2eb39abbaf28d491893743c0a473e86378fdc4f8;p=thirdparty%2Funbound.git - Fix that reuse_tcp_close_oldest sets item_on_lru_list to 0. - Fix to add assertions to reuse_tcp_select_id and unit test. - Fix that if no tcp buffers then pending tcp query stops. --- diff --git a/services/outside_network.c b/services/outside_network.c index 5f60b847c..355f48ecb 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -403,7 +403,7 @@ static void reuse_write_wait_push_back(struct reuse_tcp* reuse, } /** insert element in tree by id */ -static void +void reuse_tree_by_id_insert(struct reuse_tcp* reuse, struct waiting_tcp* w) { log_assert(w->id_node.key == NULL); @@ -412,7 +412,7 @@ reuse_tree_by_id_insert(struct reuse_tcp* reuse, struct waiting_tcp* w) } /** find element in tree by id */ -static struct waiting_tcp* +struct waiting_tcp* reuse_tcp_by_id_find(struct reuse_tcp* reuse, uint16_t id) { struct waiting_tcp key_w; @@ -885,7 +885,7 @@ static void reuse_del_readwait_elem(rbnode_type* node, void* ATTR_UNUSED(arg)) } /** delete readwait waiting_tcp elements, deletes the elements in the list */ -static void reuse_del_readwait(rbtree_type* tree_by_id) +void reuse_del_readwait(rbtree_type* tree_by_id) { if(tree_by_id->root == NULL || tree_by_id->root == RBTREE_NULL) @@ -1946,6 +1946,7 @@ reuse_tcp_close_oldest(struct outside_network* outnet) outnet->tcp_reuse_last = NULL; outnet->tcp_reuse_first = NULL; } + pend->reuse.item_on_lru_list = 0; /* free up */ reuse_cb_and_decommission(outnet, pend, NETEVENT_CLOSED); @@ -1953,7 +1954,7 @@ reuse_tcp_close_oldest(struct outside_network* outnet) /** find spare ID value for reuse tcp stream. That is random and also does * not collide with an existing query ID that is in use or waiting */ -static uint16_t +uint16_t reuse_tcp_select_id(struct reuse_tcp* reuse, struct outside_network* outnet) { uint16_t id = 0, curid, nextid; @@ -1996,9 +1997,11 @@ reuse_tcp_select_id(struct reuse_tcp* reuse, struct outside_network* outnet) if(next && next != RBTREE_NULL) { curid = tree_by_id_get_id(node); nextid = tree_by_id_get_id(next); + log_assert(curid < nextid); if(curid != 0xffff && curid + 1 < nextid) { /* space between nodes */ space = nextid - curid - 1; + log_assert(select >= count); if(select < count + space) { /* here it is */ return curid + 1 + (select - count); @@ -2015,6 +2018,7 @@ reuse_tcp_select_id(struct reuse_tcp* reuse, struct outside_network* outnet) node = rbtree_last(&reuse->tree_by_id); log_assert(node && node != RBTREE_NULL); /* tree not empty */ curid = tree_by_id_get_id(node); + log_assert(count + (0xffff-curid) + reuse->tree_by_id.count == 0xffff); return curid + 1 + (select - count); } @@ -2277,7 +2281,9 @@ reuse_tcp_remove_serviced_keep(struct waiting_tcp* w, * the stream itself. also keep it as an entry in the tree_by_id, * in case the answer returns (that we no longer want), but we cannot * pick the same ID number meanwhile */ - pend_tcp->query->cb = NULL; + if(pend_tcp->query) { + pend_tcp->query->cb = NULL; + } /* see if can be entered in reuse tree * for that the FD has to be non-1 */ if(pend_tcp->c->fd == -1) { diff --git a/services/outside_network.h b/services/outside_network.h index 26705c56d..5ca074183 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -636,6 +636,19 @@ size_t outnet_get_mem(struct outside_network* outnet); */ size_t serviced_get_mem(struct serviced_query* sq); +/** Pick random ID value for a tcp stream, avoids existing IDs. */ +uint16_t reuse_tcp_select_id(struct reuse_tcp* reuse, + struct outside_network* outnet); + +/** find element in tree by id */ +struct waiting_tcp* reuse_tcp_by_id_find(struct reuse_tcp* reuse, uint16_t id); + +/** insert element in tree by id */ +void reuse_tree_by_id_insert(struct reuse_tcp* reuse, struct waiting_tcp* w); + +/** delete readwait waiting_tcp elements, deletes the elements in the list */ +void reuse_del_readwait(rbtree_type* tree_by_id); + /** get TCP file descriptor for address, returns -1 on failure, * tcp_mss is 0 or maxseg size to set for TCP packets. */ int outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss, int dscp); diff --git a/testcode/unitmain.c b/testcode/unitmain.c index a42be424e..c61026f26 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -839,6 +839,52 @@ static void respip_test(void) respip_conf_actions_test(); } +#include "services/outside_network.h" +/** add number of new IDs to the reuse tree, randomly chosen */ +static void tcpid_addmore(struct reuse_tcp* reuse, + struct outside_network* outnet, unsigned int addnum) +{ + unsigned int i; + struct waiting_tcp* w; + for(i=0; iid = id; + w->outnet = outnet; + w->next_waiting = (void*)reuse->pending; + reuse_tree_by_id_insert(reuse, w); + } +} + +/** fill up the reuse ID tree and test assertions */ +static void tcpid_fillup(struct reuse_tcp* reuse, + struct outside_network* outnet) +{ + int t, numtest=3; + for(t=0; ttree_by_id, reuse_id_cmp); + tcpid_addmore(reuse, outnet, 65535); + reuse_del_readwait(&reuse->tree_by_id); + } +} + +/** test TCP ID selection */ +static void tcpid_test(void) +{ + struct pending_tcp pend; + struct outside_network outnet; + unit_show_func("services/outside_network.c", "reuse_tcp_select_id"); + memset(&pend, 0, sizeof(pend)); + pend.reuse.pending = &pend; + memset(&outnet, 0, sizeof(outnet)); + outnet.rnd = ub_initstate(NULL); + rbtree_init(&pend.reuse.tree_by_id, reuse_id_cmp); + tcpid_fillup(&pend.reuse, &outnet); + ub_randfree(outnet.rnd); +} + void unit_show_func(const char* file, const char* func) { printf("test %s:%s\n", file, func); @@ -907,6 +953,7 @@ main(int argc, char* argv[]) infra_test(); ldns_test(); msgparse_test(); + tcpid_test(); #ifdef CLIENT_SUBNET ecs_test(); #endif /* CLIENT_SUBNET */