From: Yuri Schaeffer Date: Fri, 11 Oct 2013 14:08:05 +0000 (+0000) Subject: references to parent nodes so deleting will be easier later on X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=25815012ee59860308681e000c1e290703ea527c;p=thirdparty%2Funbound.git references to parent nodes so deleting will be easier later on git-svn-id: file:///svn/unbound/branches/edns-subnet@2976 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/edns-subnet/addrtree.c b/edns-subnet/addrtree.c index fb98d785c..d19d7baf0 100644 --- a/edns-subnet/addrtree.c +++ b/edns-subnet/addrtree.c @@ -20,8 +20,9 @@ * @param addrlen: length of relevant part of key for this node * @return new addredge or NULL on failure */ -static struct addredge* -edge_create(struct addrnode* node, const addrkey_t* addr, addrlen_t addrlen) +static struct addredge * +edge_create(struct addrnode *node, const addrkey_t *addr, + addrlen_t addrlen, struct addrnode *parent_node, int parent_index) { size_t n; struct addredge* edge = (struct addredge*)malloc( sizeof (*edge) ); @@ -29,6 +30,8 @@ edge_create(struct addrnode* node, const addrkey_t* addr, addrlen_t addrlen) return NULL; edge->node = node; edge->len = addrlen; + edge->parent_index = parent_index; + edge->parent_node = parent_node; n = (size_t)((addrlen / KEYWIDTH) + ((addrlen % KEYWIDTH != 0)?1:0)); /*ceil()*/ edge->str = (addrkey_t*)calloc(n, sizeof (addrkey_t)); if (!edge->str) { @@ -36,6 +39,9 @@ edge_create(struct addrnode* node, const addrkey_t* addr, addrlen_t addrlen) return NULL; } memcpy(edge->str, addr, n * sizeof (addrkey_t)); + /* Only manipulate other objects after successful alloc */ + node->parent_edge = edge; + parent_node->edge[parent_index] = edge; return edge; } @@ -60,6 +66,7 @@ node_create(struct addrtree *tree, void* elem, addrlen_t scope, node->ttl = ttl; node->edge[0] = NULL; node->edge[1] = NULL; + node->parent_edge = NULL; return node; } @@ -132,26 +139,27 @@ clean_node(struct addrtree* tree, struct addrnode* node) * free'd. * @param tree: Tree the node lives in. * @param node: Node to be freed - * @param parentnode: parent of node, may be NULL if node is rootnode. - * @param parentedge: edge between parentnode and node. May be NULL iff - * parentnode is NULL */ static void -purge_node(struct addrtree* tree, struct addrnode* node, - struct addrnode* parentnode, struct addredge* parentedge) +purge_node(struct addrtree *tree, struct addrnode *node) { - struct addredge *child_edge = NULL; - int childcount = (node->edge[0] != NULL) + (node->edge[1] != NULL); + struct addredge *parent_edge, *child_edge = NULL; + int index; + int keep = node->edge[0] && node->edge[1]; + clean_node(tree, node); - if (childcount == 2 || !parentnode) - return; - log_assert(parentedge); /* parent node implies parent edge */ - if (childcount == 1) { /* Fix reference */ - child_edge = node->edge[!node->edge[0]]; + parent_edge = node->parent_edge; + if (keep || !parent_edge) return; + index = parent_edge->parent_index; + child_edge = node->edge[!node->edge[0]]; + if (child_edge) { + child_edge->parent_node = parent_edge->parent_node; + child_edge->parent_index = index; } - parentnode->edge[parentedge != parentnode->edge[0]] = child_edge; - free(parentedge->str); - free(parentedge); + parent_edge->parent_node->edge[index] = child_edge; + free(parent_edge->str); + free(parent_edge); + free(node); } /** @@ -289,15 +297,18 @@ addrtree_insert(struct addrtree* tree, const addrkey_t* addr, /* Purge all expired nodes on path */ if (!edge->node->elem || edge->node->ttl >= now) break; - purge_node(tree, edge->node, node, edge); + purge_node(tree, edge->node); edge = node->edge[index]; } /* Case 2: New leafnode */ if (!edge) { newnode = node_create(tree, elem, scope, ttl); - node->edge[index] = edge_create(newnode, addr, sourcemask); - if (!node->edge[index]) + if (!newnode) return; + if (!edge_create(newnode, addr, sourcemask, node, index)) { + clean_node(tree, newnode); free(newnode); + return; + } return; } /* Case 3: Traverse edge */ @@ -314,14 +325,16 @@ addrtree_insert(struct addrtree* tree, const addrkey_t* addr, /* Case 4: split. */ if (!(newnode = node_create(tree, NULL, 0, 0))) return; - if (!(newedge = edge_create(newnode, addr, common))) { + if (!edge_create(newnode, addr, common, node, index)) { clean_node(tree, newnode); free(newnode); return; - } - node->edge[index] = newedge; + } + /** connect existing child to our new node */ index = (uint8_t)getbit(edge->str, edge->len, common); newnode->edge[index] = edge; + edge->parent_node = newnode; + edge->parent_index = index; if (common == sourcemask) { /* Data is stored in the node */ @@ -332,7 +345,11 @@ addrtree_insert(struct addrtree* tree, const addrkey_t* addr, /* Data is stored in other leafnode */ node = newnode; newnode = node_create(tree, elem, scope, ttl); - node->edge[index^1] = edge_create(newnode, addr, sourcemask); + if (!edge_create(newnode, addr, sourcemask, node, index^1)) { + clean_node(tree, newnode); + free(newnode); + return; + } } return; } diff --git a/edns-subnet/addrtree.h b/edns-subnet/addrtree.h index 94db90388..b909f156f 100644 --- a/edns-subnet/addrtree.h +++ b/edns-subnet/addrtree.h @@ -57,6 +57,8 @@ struct addrnode { addrlen_t scope; /** A node can have 0-2 edges, set to NULL for unused */ struct addredge* edge[2]; + /** edge between this node and parent */ + struct addredge* parent_edge; }; struct addredge { @@ -66,6 +68,9 @@ struct addredge { addrlen_t len; /** child node this edge is connected to */ struct addrnode* node; + /** Ptr in parent node to self */ + struct addrnode* parent_node; + int parent_index; }; /** diff --git a/testdata/subnet_val_positive_client.crpl b/testdata/subnet_val_positive_client.crpl index 6d69233c1..ea0f6fa9d 100644 --- a/testdata/subnet_val_positive_client.crpl +++ b/testdata/subnet_val_positive_client.crpl @@ -37,7 +37,7 @@ RANGE_BEGIN 0 100 ENTRY_END ENTRY_BEGIN - MATCH opcode qtype qname ednsdata + MATCH opcode qtype qname ADJUST copy_id REPLY QR NOERROR SECTION QUESTION @@ -45,14 +45,6 @@ RANGE_BEGIN 0 100 SECTION AUTHORITY com. IN NS a.gtld-servers.net. SECTION ADDITIONAL - HEX_EDNSDATA_BEGIN - ; client is 127.0.0.1 - 50 fa ; OPC - 00 07 ; option length - 00 01 ; Family - 11 00 ; source mask, scopemask - 7f 00 00 ; address - HEX_EDNSDATA_END a.gtld-servers.net. IN A 192.5.6.30 ENTRY_END RANGE_END @@ -76,7 +68,7 @@ RANGE_BEGIN 0 100 ENTRY_END ENTRY_BEGIN - MATCH opcode qtype qname ednsdata + MATCH opcode qtype qname ADJUST copy_id REPLY QR NOERROR SECTION QUESTION @@ -84,14 +76,6 @@ RANGE_BEGIN 0 100 SECTION AUTHORITY example.com. IN NS ns.example.com. SECTION ADDITIONAL - HEX_EDNSDATA_BEGIN - ; client is 127.0.0.1 - 50 fa ; OPC - 00 07 ; option length - 00 01 ; Family - 11 00 ; source mask, scopemask - 7f 00 00 ; address - HEX_EDNSDATA_END ns.example.com. IN A 1.2.3.4 ENTRY_END RANGE_END @@ -167,10 +151,16 @@ RANGE_END STEP 1 QUERY ENTRY_BEGIN HEX_ANSWER_BEGIN; - 00 00 01 00 00 01 00 00 00 00 00 01 03 77 77 77 - 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 - 01 00 00 29 10 00 00 00 80 00 00 0b 50 fa 00 07 - 00 01 11 00 7f 00 00 + 00 00 01 00 00 01 00 00 ;ID 0 + 00 00 00 01 03 77 77 77 ; www.example.com A? (DO) + 07 65 78 61 6d 70 6c 65 + 03 63 6f 6d 00 00 01 00 + 01 00 00 29 10 00 00 00 + 80 00 00 0b + + 50 fa 00 07 ; OPC, optlen + 00 01 11 00 ; ip4, scope 17, source 0 + 7f 00 00 ;127.0.0.0/17 HEX_ANSWER_END ENTRY_END