## modules/rx/rx_search.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following functions.

1. rx_build_stack
2. rx_nod_append
3. rx_walk_hook_addnode
4. rx_walk_hook_adddoubles
5. rx_nod_search
6. 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

/* [<][>][^][v][top][bottom][index][help] */