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[],
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)
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,
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,
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 (
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 (
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 |