1    | /***************************************
2    |   $Revision: 1.15 $
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_BOT, "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  | 	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  | }