modules/rx/rx_search.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rx_build_stack
- rx_nod_append
- rx_walk_hook_addnode
- rx_walk_hook_adddoubles
- rx_nod_search
- RX_bin_search
1 /***************************************
2 $Revision: 1.37 $
3
4 Radix tree (rx). rx_search.c - functions to search nodes of the tree
5
6 Status: NOT REVUED, TESTED, COMPLETE
7
8 Design and implementation by: Marek Bukowy
9
10 ******************/ /******************
11 Copyright (c) 1999,2000,2001,2002 RIPE NCC
12
13 All Rights Reserved
14
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of the author not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22
23 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
25 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
26 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
28 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 ***************************************/
30
31
32 #include "rip.h"
33
34 /***************************************************************************/
35
36 /*++++++++++++++
37 Descends the given tree following the last prefix bit to get [past]
38 the node with the given prefix.
39 It fills up a stack of COPIES of nodes, including glue nodes.
40
41 Then it also sets the number of elements on the stack:
42 set maxdepth to the position where a next one would be written
43 ( = last + 1, or number of nodes pushed)
44
45 The dmodes:
46
47 RX_STK_QUERY_NOGLUE = (search exact/less spec) stop when
48 * the current prefix length >= newprefix length
49 * the current prefix does not match anymore
50 * do not add glue nodes
51
52 RX_STK_QUERY_ALLNOD = as above, except that the glue and data nodes are
53 treated equally (i.e. glue nodes are not skipped)
54
55 RX_STK_CREAT = descend until the next non-glue node past the one found
56 in exact mode (for creation)
57
58 ++++++++++++++*/
59
60 er_ret_t
61 rx_build_stack(rx_nodcpy_t stack[],
/* [<][>][^][v][top][bottom][index][help] */
62 int *maxdepth,
63 rx_tree_t *tree,
64 ip_prefix_t *newpref,
65 rx_stk_mt dmode
66 )
67 {
68 register rx_node_t *curnode;
69 register int link, quit_now=0;
70 register int tracedet = ER_is_traced( FAC_RX, ASP_RX_STKBLD_DET);
71 char bbf[IP_PREFSTR_MAX];
72
73 if( ER_is_traced( FAC_RX, ASP_RX_STKBLD_GEN)) {
74 IP_pref_b2a( newpref , bbf, IP_PREFSTR_MAX);
75 ER_dbg_va(FAC_RX, ASP_RX_STKBLD_GEN,
76 "rx_build_stack: searching for %s in mode %d", bbf, dmode);
77 }
78
79 *maxdepth = 0;
80
81 if ( tree -> num_nodes == 0) {
82 /* The tree was empty. */
83 return RX_OK;
84 }
85
86 curnode = tree->top_ptr;
87 /* this works for RAM, for SQL one would have to call a 'getsqlnode' here*/
88
89 /* OK, there is at least one node. Descend the tree */
90 /* as long as the correct bit length is not exceeded*/
91 /* or a glue is being found (take the last non-glue node then) */
92 /* or you run out of nodes in the direction of descending*/
93
94 do {
95 /* check at the current node, where the one we look for would fit*/
96 /* (the second argument of IP_addr_bit_get starts with 0,*/
97 /* so this effectively looks at the bit next to the last significant bit*/
98 /* of the current node*/
99
100 link = IP_addr_bit_get( & newpref->ip, curnode->prefix.bits );
101
102 /* check conditions for leaving the loop */
103 if(curnode->child_ptr[link] == NULL) {
104 /* end of branch. quit after adding the current node to the stack*/
105 /* (or before - subject to bit test in QUERY mode)*/
106 quit_now = 1;
107 }
108 else {
109 /* check the node.
110 BIG DIFFERENCE between the modes:
111 in CREAT we don't mind the stack to go too deep,
112 in QUERY it can lead to false answers
113 (e.g. a /24 is found for a /23 query).
114
115 So this must be "peeled off the stack" later in the search routine,
116 if both types of stack are to work properly with query searches.
117 */
118
119
120 if( curnode->prefix.bits > newpref->bits ) {
121 /* deep enough.*/
122 quit_now = 2;
123 }
124
125 if(dmode == RX_STK_CREAT && curnode->glue) {
126 /* mode: creation. */
127 /* Cancel quitting if glue -- in CREAT mode the stack building */
128 /* should stop at the next real (non-glue) node.*/
129 /* ("next" meaning following link #0)*/
130 quit_now = 0;
131 }
132 }
133
134 /* now that the conditions for leaving the loop after the node is
135 added on the stack, see if we shouldn't leave the loop BEFOREHAND */
136
137 /* In query mode, we should quit as soon as we see a mismatch */
138
139 if(dmode != RX_STK_CREAT
140 && 0 != IP_addr_cmp(&curnode->prefix.ip, &newpref->ip,
141 curnode->prefix.bits) ) {
142 /*QUIT NOW! (but add this node)*/
143 quit_now = 4;
144 }
145
146 /* push the current node on the stack. RAM only.*/
147 /* */
148 /* (unless quit_now is 64 which means do NOT copy the current node.*/
149 /**/
150 /* In CREAT and QUERY_ALLNOD modes, push everything. */
151 /* In QUERY_NOGLUE mode, only non-glues.*/
152
153 if( /* quit_now < 64 && disabled as 64 is not in use right now */
154 (dmode != RX_STK_QUERY_NOGLUE || curnode->glue == 0 )) {
155 memcpy( & stack[*maxdepth].cpy, curnode, sizeof(rx_node_t));
156 stack[*maxdepth].srcptr = curnode;
157 stack[*maxdepth].srckey = SQ_NOKEY;
158 stack[*maxdepth].tree = tree;
159 (*maxdepth)++;
160 }
161
162 /* make debug info.*/
163
164 if( tracedet ) {
165 IP_pref_b2a( & curnode->prefix , bbf, IP_PREFSTR_MAX );
166 ER_dbg_va(FAC_RX, ASP_RX_STKBLD_DET,
167 "rx_build_stack: %s%d at %s%s (stk len: %d)",
168 quit_now ? "stop/" : "link ",
169 quit_now ? quit_now : link,
170 bbf, ( curnode->glue ) ? " ++glue++" : "",
171 *maxdepth );
172 }
173
174 curnode = curnode -> child_ptr[link];
175
176 } while( !quit_now );
177
178 return RX_OK;
179 }
180
181 /***************************************************************************/
182 /*+++++++++
183 helper for the nod_search routine:
184
185 allocate a new node copy struct, copy the struct and add to nodlist
186 ++++++++++*/
187
188 static
189 er_ret_t
190 rx_nod_append( GList **nodlist, rx_nodcpy_t *element)
/* [<][>][^][v][top][bottom][index][help] */
191 {
192 rx_nodcpy_t *newcpy;
193
194 newcpy = (rx_nodcpy_t *)UT_malloc(sizeof(rx_nodcpy_t));
195 memcpy(newcpy, element, sizeof(rx_nodcpy_t));
196 (*nodlist) = g_list_prepend( *nodlist, newcpy );
197
198 return RX_OK;
199 }
200
201
202
203
204 /***************************************************************************/
205
206 /*+++++++++++
207 helper for MORE specific lookup in rx_nod_search
208
209 adds a node to the list of answers.
210 +++++++++++*/
211
212 static
213 er_ret_t
214 rx_walk_hook_addnode(rx_node_t *node, int level, int nodecounter,
/* [<][>][^][v][top][bottom][index][help] */
215 void *userptr)
216 {
217 rx_nodcpy_t nodcpy;
218 hook_addnode_userdat_t *userdat = userptr;
219
220
221 /* do not append glue nodes*/
222 if( node->glue == 1 ) return RX_OK;
223
224 /* in RAM mode, do not copy the node.*/
225 /* memcpy( &nodcpy.cpy, node, sizeof(rx_node_t));*/
226
227 /* XXX reset to 0 to avoid warnings from workshop: but it
228 slows things down! */
229 memset( &nodcpy.cpy, 0, sizeof(rx_node_t));
230
231 nodcpy.srcptr = node;
232 nodcpy.srckey = SQ_NOKEY;
233 nodcpy.tree = userdat->tree;
234
235 return rx_nod_append( userdat->nodlist, &nodcpy);
236 }
237
238
239 /***************************************************************************/
240
241 /*+++++++++++
242 helper for DBLS lookup in rx_nod_search
243
244 adds a node to the list of answers.
245 +++++++++++*/
246
247 static
248 er_ret_t
249 rx_walk_hook_adddoubles(rx_node_t *node, int level, int nodecounter,
/* [<][>][^][v][top][bottom][index][help] */
250 void *userptr)
251 {
252 rx_nodcpy_t nodcpy;
253 hook_addnode_userdat_t *userdat = userptr;
254 int leaves = g_list_length(node->leaves_ptr);
255 char buf[1024];
256
257 /* do not append glue nodes*/
258 if( node->glue == 1 ) return RX_OK;
259
260
261 /* add only nodes with more than 1 dataleaf*/
262 if( leaves < 2 ) return RX_OK;
263
264 if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
265 rx_nod_print(node, buf, 1024);
266 ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
267 "rx_walk_hook_adddoubles: %30s, %d leaves", buf, leaves);
268 }
269
270 /* memcpy( &nodcpy.cpy, node, sizeof(rx_node_t));*/
271 nodcpy.srcptr = node;
272 nodcpy.srckey = SQ_NOKEY;
273 nodcpy.tree = userdat->tree;
274
275 return rx_nod_append( userdat->nodlist, &nodcpy);
276 }
277
278
279 /***************************************************************************/
280 er_ret_t
281 rx_nod_search (
/* [<][>][^][v][top][bottom][index][help] */
282 rx_srch_mt search_mode,
283 int par_a,
284 int par_b,
285 /* see rx_asc_search() for explanation */
286 rx_tree_t *tree, /* tree ptr*/
287 ip_prefix_t *prefix, /* binary prefix*/
288
289 rx_nodcpy_t stack[], /* stack==array of node_copies*/
290 int stackcount, /* number of element on the stack,*/
291 /* can come from a creat stack!*/
292
293 GList **nodlist, /* answers go here*/
294 int max_count /* max # of answers*/
295 )
296 /*
297 searches the stack for a given prefix, finds *nodes* in the stack
298 and appends *copies of the nodes* to the nodlist;
299
300 finds
301 0 or 1 nodes for exact search
302 0 or 1 nodes for exless (0 if no less specific node found)
303 any number (incl. 0) for {more|less}^n-m specific
304
305 returns errcode.
306
307
308 */
309 {
310 char buf[1024];
311 int sps = stackcount-1; /* stack position.*/
312 int depthcounter=0;
313 er_ret_t err=RX_OK;
314 int i;
315 hook_addnode_userdat_t datstr;
316 er_ret_t (*hook_function)(); /* pointer to the walk_hook function*/
317 /* (see MORE spec lookup)*/
318
319 /* structure for carrying data to walk_tree hook functions, used only
320 in MORE, DBLS and RANG search modes
321 */
322 datstr.nodlist = nodlist;
323 datstr.tree = tree;
324 datstr.prefix = prefix;
325
326
327 if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
328 IP_pref_b2a( prefix , buf, IP_PREFSTR_MAX);
329 ER_dbg_va(FAC_RX, ASP_RX_SRCH_GEN,
330 "rx_nod_search: searching for %s in mode %d (%s)",
331 buf, search_mode, RX_text_srch_mode(search_mode) );
332 }
333
334 /* in non-CREAT modes, glue nodes are skipped anyway.
335 (they should normally not be there if the stack was created in
336 the STK_QUERY mode, but it's possible to use a CREAT stack too).
337
338 It's also possible that the stack is too deep.
339 So, truncate the stack to the last non-glue node
340 of the length <= search term.
341 otherwise a /24 would be returned for a /23 query.
342
343 For LESS SPECIFIC searches one has to peel off entries
344 whose prefixes do not contain the search term,
345 */
346
347 if( search_mode != RX_SRCH_CREAT ) {
348
349 while( sps >= 0 ) {
350 char *reason = NULL;
351
352 if( stack[sps].cpy.prefix.bits > prefix->bits ) { /* too deep*/
353 reason = "2deep";
354 }
355 else if( 0 != IP_addr_cmp(& stack[sps].cpy.prefix.ip, &prefix->ip,
356 stack[sps].cpy.prefix.bits) ) { /* mismatch */
357 reason = "mismatch";
358 }
359 else if ( search_mode != RX_SRCH_MORE && search_mode != RX_SRCH_DBLS
360 && search_mode != RX_SRCH_RANG && stack[sps].cpy.glue == 1 ) { /* is glue*/
361 reason = "glue";
362 }
363 #if 0
364 /* mhm. it can't be limited here, must be done in RP */
365 else if ( search_mode == RX_SRCH_LESS && par_a == 1
366 && stack[sps].cpy.prefix.bits == prefix->bits ) { /* too deep*/
367 reason = "2deep4less";
368 }
369 #endif
370
371 else {
372
373 break; /* stop peeling off */
374 }
375
376 if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
377 rx_nod_print( & stack[sps].cpy , buf, IP_PREFSTR_MAX);
378 ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
379 "rx_nod_search: peeling off %d: %s (%s)", sps, buf, reason);
380 }
381 sps--;
382 }
383 }
384
385 /* nothing left on the stack. Sorry.*/
386 /* we allow that for more spec search -- this means*/
387 /* that the search term is a shorter prefix than the one*/
388 /* in the top node. Possibly it's 0/0 which is valid for more spec search.*/
389
390 if( search_mode != RX_SRCH_MORE && search_mode != RX_SRCH_DBLS
391 && sps < 0 ) {
392 return RX_OK;
393 }
394
395 switch(search_mode) {
396 case RX_SRCH_EXACT:
397 case RX_SRCH_CREAT:
398 /* go up the tree (stack) and exit when the proper prefix is found.*/
399 /* For RX_SRCH_EXACT skip glue nodes, for RX_SRCH_CREAT take all.*/
400 /* They may contain a valid prefix, so watch out.*/
401
402 while(sps >= 0) {
403
404 if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
405 rx_nod_print(& stack[sps].cpy, buf, 1024);
406 ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
407 "rx_nod_search: position %d: %s", sps, buf);
408 }
409
410 if ( search_mode == RX_SRCH_EXACT
411 && stack[sps].cpy.glue ) {
412 die;
413 }
414
415 if ( memcmp( & stack[sps].cpy.prefix,
416 prefix,
417 sizeof(ip_prefix_t)) == 0 ) {
418 /* FOUND!!*/
419 /* add to the nodlist.*/
420
421 if( (err=rx_nod_append( nodlist, & stack[sps])) != RX_OK ) {
422 return err;
423 }
424
425 ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET, "rx_nod_search: found!");
426 break;
427 }
428 sps--;
429 }
430 break;
431
432 case RX_SRCH_EXLESS:
433 /* just fetch the last element off the stack (if any). */
434 /* Must be non-glue for EXLESS.*/
435
436 if( sps >= 0 ) {
437 rx_nod_append( nodlist, & stack[sps]);
438 }
439
440 /* else : nothing found.*/
441 /* For EXLESS: check if the stack contains only non-glue nodes.*/
442 /* If it contains a glue, it means it was created in the CREAT mode,*/
443 /* which renders the above algorithm absolutely useless. Then crash,*/
444 /* this is a programmer's error.*/
445
446 while( sps >= 0 ) {
447 if( stack[sps].cpy.glue ) {
448 die;
449 }
450 sps--;
451 }
452
453 break;
454
455 case RX_SRCH_LESS:
456 while( sps >= 0 && depthcounter < par_a ) {
457 if( stack[sps].cpy.glue == 0 ) {
458 rx_nod_append( nodlist, & stack[sps]);
459 depthcounter++;
460 }
461 sps--;
462 }
463 break;
464
465 case RX_SRCH_MORE:
466 case RX_SRCH_DBLS: /* special (debug?) mode : find nodes with multiple*/
467 /* data leaves. Much like more specific, except that*/
468 /* most nodes will be skipped.*/
469 /* The difference is in calling another hook function*/
470 hook_function = ( search_mode == RX_SRCH_MORE )
471 ? rx_walk_hook_addnode
472 : rx_walk_hook_adddoubles;
473
474 /* the result of a more spec search should NOT contain the object exactly*/
475 /* matching the query, even if it exists in the database. So two walks are */
476 /* performed, one for each child (if it exists). */
477 /* MEMORY IMPLEMENTATION ONLY FOR THE MOMENT*/
478
479 /* start from the top node if the searched prefix is between the
480 top node and the first node on the stack (i.e. the first node is
481 contained within the search term) */
482
483 /* COVERS THE CASE 0.0.0.0/0 */
484 /* or any other prefix that the tree might be set to represent,*/
485 /* but there is no actual object for it (not even glue)*/
486
487 if( sps < 0 ) {
488 if( tree->num_nodes > 0 /* there is any node in the tree */
489 && 0 == IP_addr_cmp( & prefix->ip,
490 & stack[0].cpy.prefix.ip,
491 prefix->bits) ) { /* addr match */
492 rx_walk_tree( tree->top_ptr, hook_function,
493 /* RX_WALK_REVERS | */ RX_WALK_SKPGLU, /* skip glue nodes while counting*/
494 par_a, /* display this many levels */
495 0, 0, &datstr, &err);
496 if( err != RX_OK ) {
497 return err;
498 }
499 }
500 } /* if nothing on stack */
501 else {
502
503 /* walk from this node if it matches the query prefix and is
504 long enough (if it is shorter, then it will harvest too many
505 results
506 */
507 if( prefix->bits <= stack[sps].srcptr->prefix.bits
508 && 0 == IP_addr_cmp( & stack[sps].srcptr->prefix.ip,
509 & prefix->ip,
510 prefix->bits) ) {
511 rx_walk_tree( stack[sps].srcptr, hook_function,
512 /* RX_WALK_REVERS | */ RX_WALK_SKPGLU, /* skip glue nodes while counting*/
513 par_a, /* display up to this max length*/
514 0, 0, &datstr, &err);
515 if( err != RX_OK ) {
516 return err;
517 }
518 }
519 else {
520 /* or walk the child nodes otherwise (still check the address) */
521
522 for( i = 1; i >= 0; i--) {
523 if( stack[sps].cpy.child_ptr[i] != NULL ) {
524 if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
525 IP_pref_b2a(& stack[sps].cpy.child_ptr[i]->prefix, buf, 1023);
526 }
527
528 if( 0 == IP_addr_cmp( & stack[sps].cpy.child_ptr[i]->prefix.ip,
529 & prefix->ip,
530 prefix->bits) ) {
531
532 ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
533 "rx_nod_search: digging child %d: %s", i, buf);
534
535 rx_walk_tree( stack[sps].cpy.child_ptr[i], hook_function,
536 /* RX_WALK_REVERS | */ RX_WALK_SKPGLU, /* skip glue nodes while counting*/
537 par_a, /* display this many levels */
538 0, 0, &datstr, &err);
539 if( err != RX_OK ) {
540 return err;
541 }
542 }
543 else {
544 ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
545 "rx_nod_search: prefix mismatch with child %d: %s",
546 i, buf);
547 }
548 }
549 }
550 } /* if node does not match, dig child nodes */
551
552 }
553 break;
554
555 case RX_SRCH_RANG:
556 /* OK, start from the node at the end of the stack (exless match including
557 glue nodes) then
558
559
560 if its prefix length is
561 OK -> found! descend from here as long as the prefixes are in range
562 shorter -> apparently there is even no such glue node. come back down
563 one step
564
565 */
566
567 i = sps; /* go up the tree (down the stack) */
568 /* until too far (one node too much, after >= )*/
569 while( i >= 0 && stack[i].cpy.prefix.bits >= prefix->bits ) {
570 i--;
571 }
572
573 /* look where you are:*/
574
575 if( i < 0 ) /* it was the top object, but its prefix was too long*/
576 i=0; /* take the top object as the base*/
577 else
578 i++; /* went one too much, now come back one step*/
579
580
581 rx_walk_tree( stack[i].srcptr, rx_walk_hook_addnode,
582 RX_WALK_PRFLEN, /* skip glue nodes while counting*/
583 par_a, /* display up to this max length*/
584 0, 0, &datstr, &err);
585 if( err != RX_OK ) {
586 return err;
587 }
588
589 break;
590
591 /* return RX_NOYETI;*/
592 /*not implemented*/
593 /* die; */
594 default:
595 die; /* are you nuts??*/
596 }
597
598 return err;
599
600 }
601
602
603
604 /*****************************************************************************/
605
606 /*+++++++++++++
607 builds a stack for this prefix, finds *nodes* in the stack
608 and appends *copies of the data leaves* to the LL of answers;
609
610 sorts by SQL object keys and uniq's the data
611
612 finds:
613 0 or 1 nodes for exact search
614 0 or 1 nodes for exless (0 if no less specific node found)
615 any number (incl. 0) for {more|less}-n specific
616
617 then copies the nodes/dataleaves to the answer structs and appends them
618 to the given LL. So, effectively, the number of answers can be
619 anything from 0 to infinity, because objects may be duplicate
620 even at the same node.
621
622 returns errcode.
623
624 algorithm:
625
626 builds stack[MAXBIT (==128)];
627
628 if( more/less-depth && par_a == 0)
629
630 run rx_nod_search, then
631
632 if(more spec) rx_nod_walk(maxdepth=n, append_to_LL() );
633 if(less spec) do { append(LL, stack[i]) } while(i-- && n--);
634 otherwise just set LL
635
636
637 The routine provides _at_least_ max_count answers.
638 It will *try* to stop after max_count as soon as possible
639 - but it's the higher level routine that should do the final cut.
640 +++++++++++++++*/
641
642 er_ret_t
643 RX_bin_search (
/* [<][>][^][v][top][bottom][index][help] */
644 rx_srch_mt search_mode,
645 int par_a,
646 int par_b,
647 rx_tree_t *tree, /* tree ptr*/
648 ip_prefix_t *prefix, /* binary prefix*/
649 GList **datleaves, /* data leaves go here*/
650 int max_count
651 )
652
653 {
654 rx_nodcpy_t stack[128];
655 unsigned k;
656 int stkcnt, resnum = 0, maxleaves;
657 GList *nodlist = NULL, *nitem;
658 rx_node_t *curnode;
659 rx_nodcpy_t *curcpy;
660 rx_datref_t *datref;
661 rx_stk_mt dmode;
662
663 /* more specific node search may start from a glue node, */
664 /* for all others the stack should not contain glues.*/
665
666 dmode = ( search_mode == RX_SRCH_MORE
667 || search_mode == RX_SRCH_DBLS
668 || search_mode == RX_SRCH_RANG )
669 ? RX_STK_QUERY_ALLNOD
670 : RX_STK_QUERY_NOGLUE;
671
672 rx_build_stack(stack, &stkcnt, tree, prefix, dmode);
673
674 rx_nod_search( search_mode, par_a, par_b, tree, prefix,
675 stack, stkcnt, &nodlist, 1000);
676
677 ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET, "RX_bin_search: processing nodes");
678
679 for( nitem = g_list_first(nodlist);
680 nitem != NULL;
681 nitem = g_list_next(nitem)) {
682
683 resnum++;
684 curcpy = nitem->data;
685
686 /*
687 if memory mode includes RAM:
688 * do not expect copies of nodes in the list received from bin_search.
689 * iterate through data leaves with g_list_nth_data.
690 */
691
692 curnode = curcpy->srcptr;
693
694 /* rx_nod_print( curnode, buf, 1024 );*/
695
696 maxleaves = g_list_length(curnode->leaves_ptr);
697 /* fprintf(stderr,"###node %d, %d dataleaves attached:", i, maxleaves);*/
698
699 /* iterate through dataleafs attached to this node*/
700 for(k=0; k<maxleaves; k++) {
701 rx_dataleaf_t *leafptr = g_list_nth_data(curnode->leaves_ptr, k);
702
703 /*
704 check the conditions to add the leaf:
705
706 XXX never add composed inetnum for exact prefix search
707 (but do for exact range search...) - must be solved in upper layer.
708
709 */
710
711
712 /* add*/
713
714 datref = (rx_datref_t *)UT_calloc(1, sizeof(rx_datref_t));
715 datref->leafptr = leafptr;
716 /* srckey and excluded fields are initialised to 0 by calloc */
717
718 *datleaves = g_list_prepend(*datleaves, datref);
719 }
720 }
721
722 wr_clear_list( &nodlist );
723
724 ER_dbg_va(FAC_RX, ASP_RX_SRCH_GEN,
725 "RX_bin_search: found %d nodes", resnum);
726
727
728 /* the LL of answers (*datleaves) contains pointers to answer structs,
729 that SHOULD BE NORMALIZED HERE (==with no redundant entries)
730 */
731
732 return RX_OK;
733 }
734