1    | /***************************************
2    |   $Revision: 1.25 $
3    | 
4    |   Radix tree (rx).  rx_node.c - functions to operate on nodes of the tree
5    |   (creation/deletion).
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 <rxroutines.h>
34   | #include <memwrap.h>
35   | #include <stubs.h>
36   | #include <glib.h>
37   | 
38   | #include <comparisons.h> 
39   | 
40   | /***************************************************************************/
41   | /*++++++++++++++++
42   |   rx_creat_node = create a new data node 
43   |   (empty{glue} nodes get created automatically).
44   | 
45   |   Takes a pointer to the (already allocated) data leaf to be included 
46   |   in the list of data nodes (presumably empty as the node is only now being
47   |   created).
48   |   
49   |   Requires a stack of nodes created in CREAT mode (with glue nodes, 
50   |   until deep enough and the last node being non-glue).
51   |   
52   |   MT notes: requires the tree to be locked.
53   |   
54   |   Returns: RX_OK or error code.
55   | 
56   |   +++++++++++++++++*/
57   | static
58   | er_ret_t
59   | rx_creat_node (
60   | 	       ip_prefix_t   *newpref,  /*+ prefix of the node to be added +*/
61   | 	       rx_tree_t     *tree,     /*+ tree the new node goes to +*/
62   | 	       rx_dataleaf_t *dataleaf, /*+ dataleaf to attach at this node+*/
63   | 	       rx_nodcpy_t   stack[],   /*+ stack==array of node_copies +*/
64   | 	       int           stackdepth /*+ length of the stack +*/
65   | 	     )
66   | {
67   |   rx_node_t *newnode, *curnode, *memnode, *gluenode;
68   |   int chk_bit, dif_bit, link, curpos;
69   |   char buf[1024];
70   |   er_ret_t err;
71   | 
72   |   /* assume no such node yet. Will die if there is one.*/
73   |    
74   |   /* calloc, because parent/child keys and child ptrs are not always set.*/
75   | 
76   |   if( (err=wr_calloc( (void **) & newnode, 1, sizeof(rx_node_t))) != UT_OK) {
77   |     return err; 
78   |   }
79   |   
80   |   /* increment the number of nodes in the tree*/
81   |   tree -> num_nodes ++;
82   |   
83   |   newnode -> prefix = *newpref;
84   |   
85   |   /* attach the leaf to a (presumably empty?! hence NULL) list...*/
86   |   newnode->leaves_ptr = g_list_prepend(NULL, dataleaf);
87   |   newnode->glue = 0;
88   |   
89   |   /* OK, so take a look at the tree*/
90   | 
91   |   if ( tree -> num_nodes == 1 ) { 
92   |     /* The tree was empty. Create a new top node.*/
93   |     
94   |     tree -> top_ptr = newnode;
95   |     ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "Created as the top node");
96   |     return RX_OK;
97   |   }
98   | 
99   |   /* OK, there is at least one node in the tree. Take a look at the stack.*/
100  | 
101  |   /*    we've got a real node there (not a glue), but we may be too deep.*/
102  |   /*   (it's not a glue, because glues have always two children.*/
103  |   /*    we had to go that deep because from a glue alone one doesn't know */
104  |   /*    what it glues)*/
105  |   /* GO UP.*/
106  |   /* take the first differing bit from comparing */
107  |   /* the new and the found nodes' prefixes. */
108  |   /* (not deeper than the shorter of the two)*/
109  |   
110  |   curpos =   stackdepth-1;
111  |   curnode =  & stack[curpos].cpy;
112  | 
113  |   chk_bit = smaller(curnode->prefix.bits, newpref->bits );
114  |   
115  |   for(dif_bit = 0; dif_bit < chk_bit; dif_bit++) {
116  |     /* break the loop when the first different bit is found*/
117  | 
118  |     if( IP_addr_bit_get( & curnode->prefix.ip, dif_bit) 
119  | 	!=  IP_addr_bit_get( & newpref->ip, dif_bit) ) {
120  |       break;
121  |     }
122  |   }
123  |  
124  |   ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, 
125  | 	    "cur = %d, new = %d, chk_bit = %d, dif_bit = %d", 
126  | 	    curnode->prefix.bits, newpref->bits, chk_bit, dif_bit );
127  |   
128  |   if(dif_bit == IP_sizebits(newpref->ip.space)) die; /* it mustn't happen!!!*/
129  |  
130  |   /* go up to that level (watch the head of the tree!)*/
131  |   
132  |   while( curpos > 0 && stack[curpos-1].cpy.prefix.bits >= dif_bit) {
133  |     curpos--;
134  |     ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, 
135  | 	      "up to level %d", curpos );
136  |   }
137  |   
138  |   /*
139  |     if the bit lenghts of the node, new prefix and the diffbit are equal
140  |     {
141  |     YOU'VE GOT THE NODE where the new one will be attached.
142  |     Either it has data (and will be moved accordingly), 
143  |     or is a glue (and will be turned into a regular node).
144  |     }
145  |   */
146  |   
147  |   curnode =  & stack[curpos].cpy;
148  |   
149  |   /* RAM: set a pointer to the real node in memory*/
150  |   memnode = stack[curpos].srcptr;
151  |         
152  |   if(    dif_bit == newpref->bits 
153  | 	 && dif_bit == curnode->prefix.bits ) {
154  | 
155  |     /* such node already exists, nothing to change in the tree!!!*/
156  |     /* this should be checked before calling this function, so..*/
157  |       
158  |     die;
159  |   }
160  |   /*
161  |     else  ** the branch ends here; we must create a new node... **
162  |     {
163  |     OK, how is the new node's prefix length w.r.t the dif_bit ? 
164  |     longer  -> make it a child of the node found
165  |     shorter -> make it the parent of the node found and take its place
166  |     equal   -> make a glue node the parent of both 
167  |     }
168  |     
169  |     WHEN ATTACHING THE NODE, VALUES FROM THE STACK ARE USED,
170  |     TO PREVENT EXCESSIVE LOOKUPS AGAIN.
171  |     
172  |   */
173  |   else {
174  |     
175  |     /* **** attach it.*/
176  |     if( ER_is_traced(FAC_RX, ASP_RX_NODCRE_DET) ) {
177  |       rx_nod_print(curnode, buf, 1024);
178  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "Looking at node %s", buf);
179  |     }
180  |     
181  |     if( curnode -> prefix.bits == dif_bit ) {
182  |       
183  |       /* attach here as a child of the node found      */
184  |       link = IP_addr_bit_get( &newpref->ip, dif_bit );
185  |       
186  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "attaching as child %d", link);
187  |       
188  |       if( memnode -> child_ptr[link] != NULL ) {
189  | 	die;
190  |       }
191  |       
192  |       memnode -> child_ptr[link] = newnode;
193  |       newnode -> parent_ptr = memnode;
194  |     }
195  |     else if ( newpref->bits == dif_bit ) {
196  |       /* make it the parent of the node found and take its place,*/
197  |       /* moving it down.*/
198  | 
199  |       /* set the link from the NEW node to the OLD one (different than before)*/
200  | 
201  |       link = IP_addr_bit_get( &curnode->prefix.ip, dif_bit );
202  |       
203  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "shifting down as child %d", link);
204  | 
205  |       /* PARENT<->NEW LINKS*/
206  |       /* see if the node was the top_node*/
207  |       if (curnode -> parent_ptr == NULL) {
208  | 	/*  update tree struct */
209  | 	tree -> top_ptr = newnode;
210  |       } else {    
211  | 	/* no - fix the child link at the parent.*/
212  | 	/* at the link where it was attached*/
213  | 	int link = (curnode->parent_ptr->child_ptr[1] == memnode);
214  | 	memnode -> parent_ptr -> child_ptr[link] = newnode;
215  |       }
216  |       memnode -> parent_ptr = newnode;
217  | 
218  |       /* NEW<->CHILD LINKS*/
219  |       newnode -> parent_ptr = curnode->parent_ptr;
220  |       newnode -> child_ptr[link] = memnode;
221  |     }
222  |     else {
223  |       /* create a glue and shift the curnode below the glue,*/
224  |       /* then attach the new node at the glue*/
225  |       
226  |       /* calloc, because parent/child keys are not set.*/
227  | 
228  |       if( (err=wr_calloc( (void **)& gluenode, 1, sizeof(rx_node_t))) != UT_OK) {
229  | 	return err; /* die;*/
230  |       }
231  |       tree -> num_nodes ++;
232  | 
233  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "created glue node at %p", gluenode);
234  | 
235  |       gluenode -> prefix.bits = dif_bit;
236  | 
237  |       /* fill in the address. The glue node should get the prefix*/
238  |       /* shorter by one than the shorter of the two prefixes that are glued*/
239  |       /* (difbit)*/
240  |       /**/
241  |       
242  |       gluenode -> prefix.ip = newpref->ip;
243  |       gluenode -> prefix.bits = dif_bit;
244  |       
245  |       /* the ip in this prefix is probably incorrect. Fix it.*/
246  |       IP_pref_bit_fix(  & gluenode -> prefix );
247  |       
248  |       gluenode -> leaves_ptr = NULL;
249  |       gluenode -> glue = 1;
250  | 
251  |       /* 1. Fix the link to and from the parent to the gluenode.*/
252  | 
253  |       gluenode -> parent_ptr = curnode->parent_ptr;
254  |       if (gluenode->parent_ptr == NULL) {
255  | 	tree -> top_ptr = gluenode;
256  |       } 
257  |       else {
258  | 	/* fix the child link in the parent. */
259  | 	/* if it was at 1, then let fix the link 1, 0 otherwise*/
260  | 	
261  | 	link = (curnode->parent_ptr->child_ptr[1] == memnode);
262  |       
263  | 	memnode->parent_ptr->child_ptr[link] = gluenode;
264  |       }
265  | 
266  |       /* 2. Fix the links between gluenode and the OLD node*/
267  | 
268  |       link = IP_addr_bit_get( &newpref->ip, dif_bit );
269  | 
270  |       gluenode -> child_ptr[ ! link ] = memnode;
271  |       memnode->parent_ptr = gluenode;
272  | 
273  |       /* 3. Fix the links between gluenode and the NEW node*/
274  |       
275  |       gluenode -> child_ptr[ link ] = newnode;
276  |       newnode -> parent_ptr = gluenode;
277  |     }
278  |     return RX_OK;
279  |   }
280  |   die;
281  |   return -1; /*this is just to calm down the compiler*/
282  | }
283  | 
284  | 
285  | /******************************************************************
286  |  an auxiliary function to delete data from a node 
287  |  (and delete the node or turn it into a glue afterwards)
288  | 
289  |  takes 
290  | 
291  |  tree              tree
292  |  curnode           pointer to the node 
293  |  dataleaf          pointer to a dataleaf with ObjectID (dataleaf->data_key) 
294  |                    set; which is used to choose the right dataleaf
295  | 		   when browsing data leaves. It is never assumed to be 
296  | 		   allocated via malloc, can be a local variable as well.
297  | 
298  |     If the composed flag of the dataleaf in the tree 
299  |     (being the reference count at the same time) 
300  |     is non zero, decrements the count.
301  |     Deletes the dataleaf when it reaches zero.
302  | 
303  |  suceeds always or dies when dataleaf with such data cannot be found 
304  |  in the node
305  | */
306  | 
307  | void
308  | rx_delete_node (rx_tree_t *tree, rx_node_t *curnode, rx_dataleaf_t *dataleaf)
309  | {
310  |   rx_dataleaf_t *leaffound = NULL;
311  |   GList *qitem;
312  |   int leavesum=0;
313  |   
314  |   /* go through leaves, comparing the objectID (data_key) */
315  |   for( qitem = g_list_first(curnode->leaves_ptr);
316  |        qitem != NULL;
317  |        qitem = g_list_next(qitem)) {
318  |     rx_dataleaf_t *leafptr = qitem->data;
319  |     
320  |     if( leafptr->data_key == dataleaf->data_key ) {
321  |       leaffound = leafptr;
322  |       /* no break - we're counting leaves..*/
323  |     }
324  |     leavesum++;
325  |   }
326  |   
327  |   ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "%d dataleaves at the node", leavesum);
328  | 
329  |   /* return error if none of the dataleaves matched */
330  |   if( leaffound == NULL ) die;
331  |   
332  |   /* NO error? good. Remove the leaf from the list */
333  |   curnode->leaves_ptr = g_list_remove ( curnode->leaves_ptr, leaffound );
334  |   
335  |   /* if not >composed< then delete dataleaf */
336  |   if( leaffound->composed == 0 ) {
337  |       if( leaffound->data_ptr != NULL        /* allow dataleafs without attached */
338  | 	  && leaffound->data_len > 0 ) {     /* data */
339  | 	  wr_free(leaffound->data_ptr);
340  |       }
341  |       wr_free(leaffound);
342  | 
343  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "dataleaf refcount = 0, removed");
344  |        
345  |   }
346  |   /* else decrement the reference number ( == number of prefixes 
347  |      composing the range minus 1 == the >composed< flag */
348  |   else {
349  |     leaffound->composed--;
350  |     
351  |     ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "dataleaf refcount -- to %d ",
352  | 	      leaffound->composed );
353  |   }  
354  |   
355  |   /* if that was the last leave at this node, then delete node. */
356  |   if( leavesum == 1 ) {
357  |     rx_node_t *parent = curnode->parent_ptr;
358  | 
359  |     ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "last dataleaf, removing node");
360  | 
361  |     assert(curnode->leaves_ptr == NULL);
362  |     /* To do this, check the number of children: */
363  |     
364  |     /*  0 - just delete this node and the link to it */
365  |     if( curnode->child_ptr[0] == NULL && curnode->child_ptr[1] == NULL ) {
366  | 
367  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "no children, just removing");
368  | 
369  |       if( parent != NULL ) { /* watch the head! */
370  | 	int plink = (parent->child_ptr[1] == curnode);
371  | 	parent->child_ptr[plink] = NULL;
372  |       }
373  |       else {
374  | 	assert(tree->top_ptr == curnode);
375  | 	tree->top_ptr = NULL;
376  |       }
377  |       tree->num_nodes--;
378  |       wr_free(curnode);
379  | 
380  | 
381  |     /* now, if we deleted curnode, let's see if the parent node is a glue.
382  |        If it is, then hook the remaining child up the grandparent,
383  |        and delete the parent */
384  |       if( parent != NULL && parent->glue ) {
385  | 	int slink = (parent->child_ptr[1] != NULL );
386  | 	rx_node_t *schild = parent->child_ptr[slink]; 
387  | 	rx_node_t *gparent = parent->parent_ptr;
388  | 	
389  | 	assert( schild != NULL && parent->child_ptr[ ! slink] == NULL);
390  | 	
391  | 	/* upd parent */
392  | 	if( gparent != NULL ) { /* watch the head! */
393  | 	  int plink = (gparent->child_ptr[1] == parent);
394  | 	  gparent->child_ptr[plink] = parent->child_ptr[slink];
395  | 	} else {
396  | 	  assert(tree->top_ptr == parent);
397  | 	  tree->top_ptr = parent->child_ptr[slink];
398  | 	}
399  | 	
400  | 	/* update the child's parent link too */
401  | 	parent->child_ptr[slink]->parent_ptr = gparent;
402  | 	
403  | 	/* del */
404  | 	tree->num_nodes--;
405  | 	wr_free(parent);
406  | 	
407  |       } /* if parent glue */
408  |     }
409  |     /*  2 - turn into a glue  */
410  |     else if(    curnode->child_ptr[0] != NULL 
411  | 	     && curnode->child_ptr[1] != NULL ) {
412  | 
413  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "two children, turning into a glue");
414  |       
415  |       curnode->glue = 1;
416  | 
417  |     } 
418  |     /*  1 - copy the child's link to parent. then delete */
419  |     else {
420  |       int clink = (curnode->child_ptr[1] != NULL );
421  | 
422  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "one child at %d, shifting it up",
423  | 		clink);
424  | 
425  |       /* upd parent */
426  |       if( parent != NULL ) { /* watch the head! */
427  | 	int plink = (parent->child_ptr[1] == curnode);
428  | 	parent->child_ptr[plink] = curnode->child_ptr[clink];
429  |       } else {
430  | 	/* no parent; the child becomes the top node now */
431  | 	tree->top_ptr = curnode->child_ptr[clink];
432  |       }
433  |       
434  |       /* update the child's parent link too */
435  |       curnode->child_ptr[clink]->parent_ptr = parent;
436  |       
437  |       /* del */
438  |       tree->num_nodes--;
439  |       wr_free(curnode);
440  |     }
441  |     
442  |     
443  |   } /* leavesum == 1 <=> that was the last data leaf */  
444  | } /* rx_delete_node */
445  | 
446  | /*+++++++++++++++++++
447  | 
448  |   General function to operate on dataleaves attached to a single node
449  |   (create / modify / delete).
450  |   
451  |   searches tree, finds and creates/deletes a node,
452  |   copies modified nodes to disk using rx_sql_node_set (not yet implemented).
453  |   Updates memory rollback info.
454  |   
455  |   
456  | 
457  |   
458  |   creation: 
459  |     Add a dataleaf at the node defined by prefix. 
460  |     Create a new node if it doesn't exist yet.
461  | 
462  |  
463  |   MT notes: requires the tree to be locked.
464  |   
465  |   Returns: RX_OK or error code.
466  | 
467  |   Errors from:
468  |   rx_bin_search,
469  |   memory alloc routines.
470  |   
471  |   - no such node (if not in create mode)
472  |   
473  |   - too many nodes found (strange).
474  |   
475  |   +++++++++++++++++*/
476  | 
477  | /*static*/
478  | er_ret_t
479  | rx_bin_node (
480  | 	     rx_oper_mt   mode,       /*+ MODE={cre|mod|del} +*/
481  | 	     ip_prefix_t *newpref,    /*+ prefix of the node +*/
482  | 	     rx_tree_t	*tree,        /*+ pointer to the tree structure +*/
483  | 	     rx_dataleaf_t *dataleaf  /*+ dataleaf to attach at the node +*/
484  | 	     )
485  |      
486  | {
487  |   GList *nodlist = NULL;
488  |   int nodesfound, stackdepth;
489  |   int glue;
490  |   rx_nodcpy_t *curcpy;
491  |   rx_node_t *curnode;
492  |   /* rx_nodcpy_t *stack;*/
493  |   rx_nodcpy_t stack[128];
494  |   er_ret_t err;
495  |   char bbf[IP_PREFSTR_MAX];
496  |   
497  | 
498  |   if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_BOT)) {
499  |     IP_pref_b2a( newpref , bbf, IP_PREFSTR_MAX);
500  |     ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT,
501  | 	      "rx_bin_node: %s in spc %d /fam %d operation %d", 
502  | 	      bbf, tree->space, tree->family, mode);
503  |   }
504  | 
505  |   /* first check: are we using the correct tree ???*/
506  |   if( tree->space != newpref->ip.space ) {
507  |     /* trying to insert a prefix of space %d into a tree of space %d\n",
508  | 	   tree->space,
509  | 	   newpref->ip.space);
510  |     */
511  |     die;
512  |   }
513  | 
514  |   assert( dataleaf );
515  |   assert( newpref->bits <= IP_sizebits(tree->space) );
516  | 
517  |   /* fix the prefix, to make sure all insignificant bits are 0*/
518  |   IP_pref_bit_fix( newpref );
519  | 
520  |   if( (err=rx_build_stack(stack, &stackdepth, tree, newpref, RX_STK_CREAT))
521  |        != RX_OK ) {
522  |     return err; /*die*/
523  |   }
524  |   
525  |   /*   rx_stk_print(stack, stackdepth);*/
526  |   
527  |   /* perform a search on the stack. The result is a list, and it must*/
528  |   /* be properly deleted after use!!*/
529  | 
530  |   if( rx_nod_search(RX_SRCH_CREAT, 0, 0, 
531  | 		    tree, newpref, stack, stackdepth, 
532  | 		    &nodlist, RX_ANS_ALL) != RX_OK ) {
533  |     return err; /* die;*/
534  |   }
535  | 
536  |   
537  |   /* count number of nodes in the answer */
538  |   nodesfound = g_list_length (nodlist);
539  |   
540  |   switch( nodesfound ) {
541  |   case 0:
542  |     /* no such node (yet). See what we're up to.
543  |        if( mode==cre )  create, else - program error, die */
544  |  
545  |     /*  C R E A T I O N */
546  |     ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, 
547  | 	      "rx_bin_node: Creating a new node %s in spc %d /fam %d ", 
548  | 	      bbf, tree->space, tree->family);
549  |     if( mode != RX_OPER_CRE) {
550  |       die;
551  |     }
552  |    
553  |     rx_creat_node(  newpref, tree, dataleaf, stack, stackdepth );
554  |     break;
555  |   case 1: /* found */
556  |     /* set the curnode pointer   */
557  |     curcpy = g_list_nth_data(nodlist, 0);
558  |     curnode = curcpy->srcptr;
559  | 
560  |     switch( mode ) {
561  |     case RX_OPER_CRE:
562  |       /*  attach the data at the node that was found;*/
563  |       
564  |       /* was it glue ?*/
565  |       glue = curnode->glue;
566  |             
567  |       curnode->leaves_ptr = g_list_prepend(curnode->leaves_ptr, dataleaf);
568  |       /* now it's not a glue anymore */
569  |       curnode->glue = 0;
570  | 
571  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "Appended data to a %s node",
572  | 		glue ? "glue" : "data");
573  |       
574  |       break;
575  |     case RX_OPER_DEL: 
576  | 
577  |       ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, 
578  | 		"rx_bin_node: Deleting node %s in spc %d /fam %d ", 
579  | 		bbf, tree->space, tree->family);
580  |       rx_delete_node( tree, curnode, dataleaf);
581  |       break;
582  |     }
583  |     break;
584  |   default:
585  |     /* too many nodes found! from an exact/exact-less-1 search.
586  |        this cannot happen. Call Ghostbusters now.
587  |      */
588  |     die;
589  |   }
590  | 
591  |   wr_clear_list( &nodlist );
592  |   
593  |   return RX_OK;
594  | }
595  | 
596  | 
597  | 
598  | /***************************************************************************/
599  | /* ++++++++++++++++
600  |    A wrapper around RX_bin_node.
601  | 
602  |    It's there only to control the freeing of dataleaf copies passed 
603  |    for comparison during deletion.
604  | 
605  |    +++++++++++++++++*/
606  | er_ret_t
607  | RX_rt_node (
608  | 	     rx_oper_mt   mode,       /*+ MODE={cre|mod|del} +*/
609  | 	     ip_prefix_t *newpref,    /*+ prefix of the node +*/
610  | 	     rx_tree_t	*tree,        /*+ pointer to the tree structure +*/
611  | 	     rx_dataleaf_t *dataleaf  /*+ dataleaf to attach at the node +*/
612  | 	     )
613  | {
614  |   er_ret_t reterr;
615  |   
616  |   reterr = rx_bin_node(mode, newpref, tree, dataleaf);
617  |   
618  |   return reterr;
619  | }
620  |      
621  | /***************************************************************************/
622  | /*+++++++++++++++
623  |   performs the actual update for inetnums (possibly composed of many prefixes).
624  |   Decomposes the ranges into prefixes and then falls back to rx_bin_node
625  |   to perform changes at the nodes.
626  |   
627  |   Requires/returns - practically the same as rx_bin_node.
628  | ++++++++++++++++*/
629  | 
630  | er_ret_t
631  | RX_in_node(   rx_oper_mt mode,       /*+ MODE={cre|mod|del} +*/
632  | 	      ip_range_t *rang,      /*+ range of IP addresses +*/
633  | 	      rx_tree_t *tree,       /*+ pointer to the tree structure +*/
634  | 	      rx_dataleaf_t *leafptr /*+ dataleaf to attach at the node +*/
635  | 	      )     
636  | {
637  |   int i, prefcount;
638  |   GList *preflist = NULL;
639  |   char buf[IP_RANGSTR_MAX];
640  | 
641  |   if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_BOT)) {
642  |     IP_rang_b2a(rang, buf, IP_RANGSTR_MAX );
643  |     ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, 
644  | 	      "rx_inum_node: adding %s", buf);
645  |   }
646  | 
647  |   /* decompose, put links to the data leaf into every prefix*/
648  |   /* that makes up this range.*/
649  |   IP_rang_decomp(rang, &preflist);
650  |   
651  |   /* see if there is more than 1 prefix, set the composed flag*/
652  |   prefcount = g_list_length(preflist);
653  |   leafptr->composed = (prefcount - 1) ;
654  |   
655  |   leafptr->iprange = *rang;
656  |   
657  |   for(i=0; i < prefcount; i++) {
658  |     ip_prefix_t *mypref = g_list_nth_data(preflist, i);
659  |     
660  |     rx_bin_node(mode, mypref, tree, leafptr);
661  |   }
662  |     
663  |   /* free the storage from decomposition*/
664  |   wr_clear_list( &preflist );
665  | 
666  |   return RX_OK;
667  | }