1 | /***************************************
2 | $Revision: 1.17 $
3 |
4 | Radix tree (rx). rx_tree.c - functions to operate on trees
5 | (creation/deletion/finding).
6 |
7 | Status: NOT REVUED, TESTED, INCOMPLETE
8 |
9 | Design and implementation by: Marek Bukowy
10 |
11 | ******************/ /******************
12 | Copyright (c) 1999 RIPE NCC
13 |
14 | All Rights Reserved
15 |
16 | Permission to use, copy, modify, and distribute this software and its
17 | documentation for any purpose and without fee is hereby granted,
18 | provided that the above copyright notice appear in all copies and that
19 | both that copyright notice and this permission notice appear in
20 | supporting documentation, and that the name of the author not be
21 | used in advertising or publicity pertaining to distribution of the
22 | software without specific, written prior permission.
23 |
24 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
25 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
26 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
27 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
28 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 | ***************************************/
31 |
32 | #include <erroutines.h>
33 | #include <iproutines.h>
34 | #include <memwrap.h>
35 | #include <stubs.h>
36 |
37 | /***************************************************************************/
38 |
39 | #define RX_IMPL
40 |
41 | #include <rxroutines.h>
42 | /***************************************************************************/
43 |
44 |
45 | /*+++++++++
46 | go down the tree calling func on every node.
47 | (func takes the node pointer and the current level)
48 |
49 | the function is called recursively with level increased
50 | it stops recursing when no child nodes are found or maxlevel is reached.
51 |
52 | therefore the initial call must set level to 0.
53 |
54 | the nodecounter increments at every node, and is the return value
55 | of the function. So start with 0 to get the number of nodes traversed.
56 |
57 | ERROR HANDLING IS DIFFERENT HERE!
58 | Unlike other functions it is not the return value:
59 | The error code from the func function IF DEFINED (== not NULL ) goes
60 | to the variable pointed to by the last parameter.
61 | ++++++++++++*/
62 | int
63 | rx_walk_tree(rx_node_t *node,
64 | er_ret_t (*func)(rx_node_t *node, int level, int nodecounter,
65 | void *userptr),
66 | rx_walk_mt walk_mode,
67 | /* controls if glue nodes are counted*/
68 | /* and if levels or prefix lenghts are checked*/
69 | int maxlevel,
70 | int level,
71 | int nodecounter,
72 | void *userptr,
73 | er_ret_t *err)
74 | {
75 | int i, link, skpglue=0;
76 |
77 | if( node == NULL ) die; /* program error. we expect a valid, checked, node.*/
78 |
79 | /* count the node appropriately:*/
80 | /* if (not glue) or (it doesn't matter)*/
81 |
82 | if( node->glue == 0 || (walk_mode & RX_WALK_SKPGLU) == 0 ) {
83 | level++;
84 | } else { /* nodeglue = 1 && walkmode&skpglue = 1 */
85 | skpglue = 1;
86 | }
87 |
88 | /* check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN, */
89 | /* level otherwise */
90 |
91 | if(walk_mode & RX_WALK_PRFLEN) {
92 | if(node->prefix.bits > maxlevel) {
93 | return nodecounter;
94 | }
95 | }
96 | else if( level > maxlevel ) {
97 | return nodecounter;
98 | }
99 |
100 | /* didn't quit ?? OK, count it too...*/
101 | if( skpglue == 0 ) {
102 | nodecounter++;
103 | }
104 |
105 | if( func != NULL && skpglue == 0 ) {
106 | *err = func(node, level, nodecounter, userptr);
107 |
108 | /* abort the walk on error*/
109 | if( *err != RX_OK ) {
110 | ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK,
111 | "walk_tree: func returned error %d, aborting", *err);
112 | return nodecounter;
113 | }
114 | }
115 |
116 |
117 | for(i=0; i<=1; i++) {
118 |
119 | /* reverse the sense of the walk*/
120 | link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i;
121 |
122 | if( node->child_ptr[link] != NULL ) {
123 | nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode,
124 | maxlevel, level, 0, userptr, err);
125 | /* abort the walk on error*/
126 | if( func != NULL && *err != RX_OK ) {
127 | break;
128 | }
129 | }
130 | }
131 |
132 | return nodecounter;
133 | }
134 |
135 |
136 |
137 | /***************************************************************************/
138 | /*++++++
139 | creates a (top) tree for the space, fills out sql table of trees
140 | generates a tablename for a tree (if NONE)
141 | updates LL of trees
142 |
143 | MT-note: locks/unlocks the forest (still to be done)
144 |
145 | ++++++++*/
146 | er_ret_t
147 | RX_tree_cre (
148 | char *prefixstr, /*+ prefix the tree will cover (string) +*/
149 | rx_fam_t fam_id,
150 | rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/
151 | rx_subtree_mt subtrees, /*+ one of NONE, AUTO, HAND +*/
152 | rx_tree_t **treestore /* store the tree pointer here */
153 | )
154 |
155 | {
156 | er_ret_t err;
157 | rx_tree_t *newtree;
158 | ip_prefix_t newpref;
159 | ip_space_t spc_id;
160 |
161 | if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) {
162 | die;
163 | }
164 |
165 | spc_id = IP_pref_b2_space( &newpref );
166 |
167 | if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) {
168 | return err; /* die*/
169 | }
170 |
171 | ER_dbg_va(FAC_RX, ASP_RX_TREE_GEN, "creating a tree at %08x", newtree);
172 |
173 | /* copy tree settings */
174 | newtree -> space = spc_id;
175 | newtree -> family = fam_id;
176 |
177 | newtree -> subtrees = subtrees;
178 | newtree -> mem_mode = mem_mode;
179 |
180 | /* set other tree values */
181 |
182 | /* parent set to NULL because it's not a subtree */
183 | newtree -> parent_tree = NULL;
184 | /* PR_zeroprefix(& newtree -> prefix);*/
185 | newtree -> maxbits = IP_sizebits(spc_id);
186 |
187 | strcpy(newtree->data_table.val,"");
188 | strcpy(newtree->radix_table.val,"");
189 | strcpy(newtree->leaves_table.val,"");
190 |
191 | newtree->num_nodes = 0;
192 |
193 | newtree->top_ptr = NULL;
194 | newtree->top_key = SQ_NOKEY;
195 |
196 | newtree->prefix = newpref;
197 |
198 | TH_init_read_write_lock( &(newtree->rwlock));
199 |
200 | *treestore = newtree;
201 |
202 | return RX_OK;
203 | }
204 |
205 |
206 | /* ************************************
207 | special walk function for use in consistency checks - it checks the parent
208 | pointer too.
209 | ************************************/
210 | int rx_check_walk_tree( rx_node_t *node,
211 | rx_node_t *parent_node,
212 | int nodecounter,
213 | rx_treecheck_t *checkstruct )
214 | {
215 | int i;
216 |
217 | /* checks*/
218 | if( node == NULL ) {
219 | checkstruct->code |= 1;
220 | }
221 | if( node->parent_ptr != parent_node ) {
222 | checkstruct->code |= 2;
223 | }
224 | if( node->glue && node->leaves_ptr ) {
225 | checkstruct->code |= 4;
226 | }
227 | if( node->glue && (node->child_ptr[0] == NULL || node->child_ptr[1] == NULL ) ) {
228 | checkstruct->code |= 8;
229 | }
230 |
231 |
232 | if( node->leaves_ptr && checkstruct->datatoo ) {
233 | switch( checkstruct->tree->family ) {
234 | case RX_FAM_IP:
235 | /* the simplest (?) case: only one leaf attached to any node
236 | (except for glues) */
237 | if( g_list_length(node->leaves_ptr) != 1 ) {
238 | checkstruct->code |= 16;
239 | }
240 | break;
241 | case RX_FAM_RT:
242 | /* many dataleaves attached to nodes. */
243 | break;
244 | case RX_FAM_IN:
245 | /* many dataleaves attached to nodes.
246 | Some leaves pointed to from many nodes => from as many as the number
247 | of composing prefixes
248 | */
249 | break;
250 | default:
251 | /* ignore */
252 | break;
253 | }
254 | }
255 |
256 |
257 | if( checkstruct->code != 0 ) {
258 | checkstruct->node = node;
259 |
260 | return nodecounter; /* abort the walk on error*/
261 | }
262 |
263 |
264 | nodecounter++;
265 |
266 | for(i=0; i<=1; i++) {
267 | if( node->child_ptr[i] != NULL ) {
268 | nodecounter += rx_check_walk_tree( node->child_ptr[i],
269 | node,
270 | 0, checkstruct );
271 | /* abort the walk on error*/
272 | if ( checkstruct->code != 0 ) {
273 | die; break;
274 | }
275 | }
276 | }
277 | return nodecounter;
278 | }
279 |
280 | /* **************************************************************************
281 | tree consistency check.
282 |
283 | if datatoo = 0, then only parent/child links are checked.
284 |
285 | if datatoo = 1, then a check on the contents of the nodes is done too.
286 |
287 | **************************************************************************/
288 |
289 | er_ret_t
290 | RX_treecheck( rx_tree_t *tree, int datatoo, rx_treecheck_t *errorfound)
291 | {
292 | er_ret_t err = RX_OK;
293 | int nodnum;
294 |
295 | errorfound->tree = tree;
296 | errorfound->datatoo = datatoo;
297 |
298 | /* errorfound.node will be set by hook if it finds an error*/
299 | errorfound->code = 0;
300 |
301 | nodnum = rx_check_walk_tree( tree->top_ptr,
302 | NULL,
303 | 0,
304 | errorfound );
305 |
306 | if( nodnum != tree->num_nodes ) {
307 | errorfound->code |= 1024;
308 | }
309 | if( tree->num_nodes == 0 && tree->top_ptr != NULL ) {
310 | errorfound->code |= 2048;
311 | }
312 | if( tree->num_nodes != 0 && tree->top_ptr == NULL ) {
313 | errorfound->code |= 4096;
314 | }
315 |
316 | if( errorfound->code != 0) {
317 | err = RX_DATNOF;
318 | }
319 | return err;
320 | }