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