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 |