]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix that reuse_tcp_close_oldest sets item_on_lru_list to 0.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 21 Oct 2020 07:49:55 +0000 (09:49 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 21 Oct 2020 07:49:55 +0000 (09:49 +0200)
- Fix to add assertions to reuse_tcp_select_id and unit test.
- Fix that if no tcp buffers then pending tcp query stops.

services/outside_network.c
services/outside_network.h
testcode/unitmain.c

index 5f60b847c623b06d8604d4dfe18f9cd03bf53512..355f48ecb81acc378aeab85985cfbec09ae2a79d 100644 (file)
@@ -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) {
index 26705c56de4f207b426b2237f51b2cd0710d0904..5ca0741831804082005b939a563cd29a86ee27ca 100644 (file)
@@ -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);
index a42be424e9e9a35b623368b4b4f9f951fb01556e..c61026f26808294394f99c566f795a96915b5161 100644 (file)
@@ -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; i<addnum; i++) {
+               uint16_t id = reuse_tcp_select_id(reuse, outnet);
+               unit_assert(!reuse_tcp_by_id_find(reuse, id));
+               w = calloc(1, sizeof(*w));
+               unit_assert(w);
+               w->id = 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; t<numtest; t++) {
+               rbtree_init(&reuse->tree_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 */