1 | /***************************************
2 | $Revision: 1.18 $
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.
296 |
297 | suceeds always or dies when dataleaf with such data cannot be found
298 | in the node
299 | */
300 |
301 | void
302 | rx_delete_node (rx_tree_t *tree, rx_node_t *curnode, rx_dataleaf_t *dataleaf)
303 | {
304 | rx_dataleaf_t *leaffound = NULL;
305 | GList *qitem;
306 | int leavesum=0;
307 |
308 | /* go through leaves, comparing the objectID (data_key) */
309 | for( qitem = g_list_first(curnode->leaves_ptr);
310 | qitem != NULL;
311 | qitem = g_list_next(qitem)) {
312 | rx_dataleaf_t *leafptr = qitem->data;
313 |
314 | if( leafptr->data_key == dataleaf->data_key ) {
315 | leaffound = leafptr;
316 | /* no break - we're counting leaves..*/
317 | }
318 | leavesum++;
319 | }
320 |
321 | /* return error if none of the dataleaves matched */
322 | if( leaffound == NULL ) die;
323 |
324 | /* NO error? good. Remove the leaf from the list */
325 | curnode->leaves_ptr = g_list_remove ( curnode->leaves_ptr, leaffound );
326 |
327 | /* if not >composed< then delete dataleaf */
328 | if( leaffound->composed == 0 ) {
329 | wr_free(leaffound);
330 | }
331 | /* else decrement the reference number ( == number of prefixes
332 | composing the range minus 1 == the >composed< flag */
333 | else {
334 | leaffound->composed--;
335 | }
336 |
337 | /* if that was the last leave at this node, then delete node. */
338 | if( leavesum == 1 ) {
339 |
340 | rx_node_t *parent = curnode->parent_ptr;
341 |
342 | assert(curnode->leaves_ptr == NULL);
343 | /* To do this, check the number of children: */
344 |
345 | /* 0 - just delete this node and the link to it */
346 | if( curnode->child_ptr[0] == NULL && curnode->child_ptr[1] == NULL ) {
347 | if( parent != NULL ) { /* watch the head! */
348 | int plink = (parent->child_ptr[1] == curnode);
349 | parent->child_ptr[plink] = NULL;
350 | }
351 | else {
352 | assert(tree->top_ptr == curnode);
353 | tree->top_ptr = NULL;
354 | }
355 | tree->num_nodes--;
356 | wr_free(curnode);
357 |
358 |
359 | /* very good :-) now if we deleted curnode, let's see if the parent node is a glue.
360 | If it is, then hook the remaining child up the grandparent,
361 | and delete the parent */
362 | if( parent != NULL && parent->glue ) {
363 | int slink = (parent->child_ptr[1] != NULL );
364 | rx_node_t *schild = parent->child_ptr[slink];
365 | rx_node_t *gparent = parent->parent_ptr;
366 |
367 | assert( schild != NULL && parent->child_ptr[ ! slink] == NULL);
368 |
369 | /* upd parent */
370 | if( gparent != NULL ) { /* watch the head! */
371 | int plink = (gparent->child_ptr[1] == parent);
372 | gparent->child_ptr[plink] = parent->child_ptr[slink];
373 | } else {
374 | assert(tree->top_ptr == parent);
375 | tree->top_ptr = parent->child_ptr[slink];
376 | }
377 |
378 | /* update the child's parent link too */
379 | parent->child_ptr[slink]->parent_ptr = gparent;
380 |
381 | /* del */
382 | tree->num_nodes--;
383 | wr_free(parent);
384 |
385 | } /* if parent glue */
386 | }
387 | /* 2 - turn into a glue */
388 | else if( curnode->child_ptr[0] != NULL
389 | && curnode->child_ptr[1] != NULL ) {
390 |
391 | curnode->glue = 1;
392 | }
393 | /* 1 - copy the child's link to parent. then delete */
394 | else {
395 | int clink = (curnode->child_ptr[1] != NULL );
396 |
397 | /* upd parent */
398 | if( parent != NULL ) { /* watch the head! */
399 | int plink = (parent->child_ptr[1] == curnode);
400 | parent->child_ptr[plink] = curnode->child_ptr[clink];
401 | }
402 |
403 | /* update the child's parent link too */
404 | curnode->child_ptr[clink]->parent_ptr = parent;
405 |
406 | /* del */
407 | tree->num_nodes--;
408 | wr_free(curnode);
409 | }
410 |
411 |
412 | } /* leavesum == 1 <=> that was the last data leaf */
413 | } /* rx_delete_node */
414 |
415 | /***************************************************************************/
416 | /*+ hook for g_list_foreach to free a list element +*/
417 |
418 | void
419 | rx_free_list_element(void *cpy, void *trash)
420 | {
421 | wr_free(cpy);
422 | }
423 |
424 | /***************************************************************************/
425 | /*+++++++++++++++++++
426 |
427 | General function to operate on dataleaves attached to a single node
428 | (create / modify / delete).
429 |
430 | searches tree, finds and creates (modifies/deletes) a node,
431 | copies modified nodes to disk using rx_sql_node_set (not yet implemented).
432 | Updates memory rollback info.
433 |
434 |
435 |
436 |
437 |
438 | Add a dataleaf at the node defined by prefix.
439 | Create a new node if it doesn't exist yet.
440 |
441 | MT notes: requires the tree to be locked.
442 |
443 | Returns: RX_OK or error code.
444 |
445 | Errors from:
446 | rx_bin_search,
447 | memory alloc routines.
448 |
449 | - no such node (if not in create mode)
450 |
451 | - too many nodes found (strange).
452 |
453 | +++++++++++++++++*/
454 |
455 | /*static*/
456 | er_ret_t
457 | RX_bin_node (
458 | rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
459 | ip_prefix_t *newpref, /*+ prefix of the node +*/
460 | rx_tree_t *tree, /*+ pointer to the tree structure +*/
461 | rx_dataleaf_t *dataleaf /*+ dataleaf to attach at the node +*/
462 | )
463 |
464 | {
465 | GList *nodlist = NULL;
466 | int nodesfound, stackdepth;
467 | int glue;
468 | rx_nodcpy_t *curcpy;
469 | rx_node_t *curnode;
470 | rx_nodcpy_t *stack;
471 | er_ret_t err;
472 | char bbf[IP_PREFSTR_MAX];
473 |
474 |
475 | if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_BOT)) {
476 | IP_pref_b2a( newpref , bbf, IP_PREFSTR_MAX);
477 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT,
478 | "rx_bin_node: new %s in spc %d /fam %d /reg %d",
479 | bbf, tree->space, tree->family, tree->reg_id);
480 | }
481 |
482 | // first check: are we using the correct tree ???
483 | if( tree->space != newpref->ip.space ) {
484 | /* trying to insert a prefix of space %d into a tree of space %d\n",
485 | tree->space,
486 | newpref->ip.space);
487 | */
488 | die;
489 | }
490 |
491 | assert( dataleaf );
492 | assert( newpref->bits <= IP_sizebits(tree->space) );
493 |
494 | // fix the prefix, to make sure all insignificant bits are 0
495 | IP_pref_bit_fix( newpref );
496 |
497 | if( (err=wr_malloc( (void **) &stack,
498 | sizeof(rx_nodcpy_t) * IP_sizebits(tree->space))) != UT_OK) {
499 | return err; //die;
500 | }
501 |
502 | if( (err=rx_build_stack(stack, &stackdepth,
503 | tree, newpref, RX_STK_CREAT) != RX_OK )) {
504 | return err; //die
505 | }
506 |
507 | // rx_stk_print(stack, stackdepth);
508 |
509 | // perform a search on the stack. The result is a list, and it must
510 | // be properly deleted after use!!
511 |
512 | if( rx_nod_search(RX_SRCH_CREAT, 0, 0,
513 | tree, newpref, stack, stackdepth,
514 | &nodlist, RX_ANS_ALL) != RX_OK ) {
515 | return err; // die;
516 | }
517 |
518 |
519 | // count number of nodes in the answer
520 | nodesfound = g_list_length (nodlist);
521 |
522 | switch( nodesfound ) {
523 | case 0:
524 | /* no such node (yet). See what we're up to.
525 | if( mode==cre ) create, else - program error, die */
526 |
527 | if( mode != RX_OPER_CRE) {
528 | die;
529 | }
530 |
531 | /* C R E A T I O N */
532 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT,
533 | "Creating a new node ");
534 | rx_creat_node( newpref, tree, dataleaf, stack, stackdepth );
535 | break;
536 | case 1: /* found */
537 | /* set the curnode pointer */
538 | curcpy = g_list_nth_data(nodlist, 0);
539 | curnode = curcpy->srcptr;
540 |
541 | switch( mode ) {
542 | case RX_OPER_CRE:
543 | // attach the data at the node that was found;
544 |
545 | // was it glue ?
546 | glue = curnode->glue;
547 |
548 | curnode->leaves_ptr = g_list_prepend(curnode->leaves_ptr, dataleaf);
549 | /* now it's not a glue anymore */
550 | curnode->glue = 0;
551 |
552 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "Appended data to a %s node",
553 | glue ? "glue" : "data");
554 |
555 | break;
556 | case RX_OPER_MOD:
557 | /* put new data in place of old - not used (
558 | (the object ID and primary keys stay the same) */
559 | break;
560 | case RX_OPER_DEL:
561 | rx_delete_node( tree, curnode, dataleaf);
562 | break;
563 | }
564 | break;
565 | default:
566 | /* too many nodes found! from an exact/exact-less-1 search.
567 | this cannot happen. Call Ghostbusters now.
568 | */
569 | die;
570 | }
571 |
572 | g_list_foreach(nodlist, rx_free_list_element, NULL);
573 |
574 | wr_free(stack);
575 | return RX_OK;
576 | }
577 |
578 | /* ++++++++++++++++
579 | A wrapper around RX_bin_node.
580 |
581 | It's there only to control the freeing of dataleaf copies passed
582 | for comparison during deletion.
583 |
584 | +++++++++++++++++*/
585 |
586 | er_ret_t
587 | RX_route_node (
588 | rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
589 | ip_prefix_t *newpref, /*+ prefix of the node +*/
590 | rx_tree_t *tree, /*+ pointer to the tree structure +*/
591 | rx_dataleaf_t *dataleaf /*+ dataleaf to attach at the node +*/
592 | )
593 | {
594 | er_ret_t reterr;
595 |
596 |
597 | reterr = RX_bin_node(mode, newpref, tree, dataleaf);
598 |
599 | if( mode == RX_OPER_DEL ) { /* free the dataleaf copy AND the data */
600 | wr_free( dataleaf->data_ptr );
601 | wr_free( dataleaf );
602 | }
603 |
604 | return reterr;
605 | }
606 |
607 | /***************************************************************************/
608 | /*+++++++++++++++
609 | performs the actual update for inetnums (possibly composed of many prefixes).
610 | Decomposes the ranges into prefixes and then falls back to rx_bin_node
611 | to perform changes at the nodes.
612 |
613 | Requires/returns - practically the same as rx_bin_node.
614 | ++++++++++++++++*/
615 |
616 | er_ret_t
617 | RX_inum_node( rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
618 | ip_range_t *rang, /*+ range of IP addresses +*/
619 | rx_tree_t *tree, /*+ pointer to the tree structure +*/
620 | rx_dataleaf_t *leafptr /*+ dataleaf to attach at the node +*/
621 | )
622 | {
623 | int i, prefcount;
624 | GList *preflist = NULL;
625 | char buf[IP_RANGSTR_MAX];
626 |
627 | if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_BOT)) {
628 | IP_rang_b2a(rang, buf, IP_RANGSTR_MAX );
629 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT,
630 | "rx_inum_node: adding %s", buf);
631 | }
632 |
633 | // decompose, put links to the data leaf into every prefix
634 | // that makes up this range.
635 | IP_rang_decomp(rang, &preflist);
636 |
637 | // see if there is more than 1 prefix, set the composed flag
638 | prefcount = g_list_length(preflist);
639 | leafptr->composed = (prefcount - 1) ;
640 |
641 | leafptr->iprange = *rang;
642 |
643 | for(i=0; i < prefcount; i++) {
644 | ip_prefix_t *mypref = g_list_nth_data(preflist, i);
645 |
646 | RX_bin_node(mode, mypref, tree, leafptr);
647 | }
648 |
649 | // free the storage from decomposition
650 | g_list_foreach(preflist, rx_free_list_element, NULL);
651 | g_list_free(preflist);
652 |
653 | return RX_OK;
654 | }
655 |
656 |
657 | /***************************************************************************/
658 | /*+++++++++++++++
659 | translates ranges/prefixes into binary prefixes.
660 | finds tree, locks it.
661 | initiates memory rollback structure (???)
662 |
663 | builds a dataleaf and puts into the node(s),
664 | calling rx_bin_node for every prefix.
665 |
666 | checks rollback condition and (possibly) rolls back ???
667 |
668 | MT-note: locks/unlocks the tree.
669 |
670 | Possible errors
671 | - all errors from:
672 | ip_asc_2_bin,
673 | rx_get_tree,
674 | rx_bin_node,
675 | wr_free
676 |
677 | +++++++++++++++++*/
678 | er_ret_t
679 | RX_asc_node ( rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
680 | char *rangstr, /*+ string prefix/range/IP +*/
681 | rx_regid_t reg_id, /*+ id of the registry +*/
682 | ip_space_t spc_id, /*+ type of space (ipv4/ipv6) +*/
683 | rx_fam_t fam_id, /*+ family of objects (route/inetnum) +*/
684 | void *data /*+ pointer to the payload +*/
685 | )
686 |
687 | {
688 |
689 | /*
690 | For creation of a new node:
691 |
692 | READ-LOCK THE FOREST
693 |
694 | get the root tree for this space (rx_get_tree)
695 | got it ? good. No ? error!!!
696 |
697 | Check if any of the prefixes spans more than one subtree...
698 | Check if they all exist already..
699 |
700 | if any is missing
701 | then
702 | WRITE-LOCK THE FOREST
703 | fi
704 |
705 | for all missing subtrees
706 | create missing trees
707 | rof
708 |
709 | UNLOCK THE FOREST
710 |
711 | **now start writing the data:**
712 |
713 | put *data* records in memory and sql table
714 |
715 | for all matchind [sub]trees (in order of the list)
716 | WRITE-LOCK the in-memory [sub]tree
717 | WRITE-LOCK the sql-table for it
718 |
719 | for(all prefixes in memory that match this tree)
720 | create a node in the tree pointing to the data
721 | rof
722 | UNLOCK the tree
723 | rof
724 |
725 |
726 | */
727 |
728 |
729 | ip_range_t myrang;
730 | ip_prefix_t mypref;
731 | rx_dataleaf_t *leafptr;
732 | rx_tree_t *mytree;
733 | int rang_ok;
734 |
735 | if( RX_get_tree ( &mytree, reg_id, spc_id, fam_id) != RX_OK ) {
736 | die;
737 | }
738 |
739 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT,
740 | "rx_asc_node: inserting object %s", rangstr);
741 |
742 | // set the data leaf values
743 | if( wr_calloc( (void **)& leafptr, sizeof(rx_dataleaf_t), 1)
744 | != UT_OK) {
745 | die;
746 | }
747 |
748 | leafptr->data_ptr = data;
749 |
750 | switch( fam_id )
751 | {
752 | case RX_FAM_IN:
753 | rang_ok = 1;
754 |
755 | if( IP_rang_e2b(&myrang, rangstr) == IP_OK ) {
756 | // that's nice. everything is set.
757 | } else {
758 | // see if's a valid IP, maybe it's an IPv4 classful range
759 | if( IP_addr_e2b( &myrang.begin, rangstr ) == IP_OK ) {
760 | if( IP_rang_classful( &myrang , &myrang.begin ) != IP_OK ) {
761 | rang_ok = 0;
762 | }
763 | }
764 | else {
765 | // sorry. we don't accept that.
766 | rang_ok = 0;
767 | }
768 | }
769 |
770 | if( rang_ok == 1 ) {
771 | return RX_inum_node( mode, &myrang, mytree, leafptr );
772 | }
773 | // else: fall through to the end of the function. (unrecognized arg)
774 |
775 | break;
776 |
777 | case RX_FAM_RT:
778 | if( IP_pref_e2b(&mypref, rangstr) == IP_OK ) {
779 | return RX_bin_node(RX_OPER_CRE, &mypref, mytree, leafptr);
780 | }
781 | }
782 |
783 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT,
784 | "can't understand the key, discarding the OBJECT.");
785 | wr_free(data);
786 | wr_free(leafptr);
787 |
788 | return RX_BADKEY;
789 | }
790 |