modules/rp/rp_search.c

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

FUNCTIONS

This source file includes following functions.
  1. rp_exclude_datlink
  2. rp_preflist_search
  3. rp_find_smallest_span
  4. rp_leaf_occ_inc
  5. rp_exclude_exact_match
  6. rp_find_longest_prefix
  7. rp_asc_process_datlist
  8. rp_mod_preflist
  9. rp_asc_append_datref
  10. rp_srch_copyresults
  11. rp_begend_preselection
  12. RP_asc_search
  13. RP_new_asc_search

   1 /***************************************
   2   $Revision: 1.9 $
   3 
   4   Radix payload (rp) - user level functions for storing data in radix trees
   5 
   6   rp_search = search the loaded radix trees using an ascii key
   7 
   8               Motto: "And all that for inetnums..."
   9 
  10   Status: NOT REVIEWED, TESTED
  11   
  12   Design and implementation by: Marek Bukowy
  13   
  14   ******************/ /******************
  15   Copyright (c) 1999                              RIPE NCC
  16  
  17   All Rights Reserved
  18   
  19   Permission to use, copy, modify, and distribute this software and its
  20   documentation for any purpose and without fee is hereby granted,
  21   provided that the above copyright notice appear in all copies and that
  22   both that copyright notice and this permission notice appear in
  23   supporting documentation, and that the name of the author not be
  24   used in advertising or publicity pertaining to distribution of the
  25   software without specific, written prior permission.
  26   
  27   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  28   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  29   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  30   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  31   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  32   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33   ***************************************/
  34 
  35 
  36 #include <rp.h>
  37 
  38 static
  39 void
  40 rp_exclude_datlink(GList    **datlist, GList    *element)
     /* [<][>][^][v][top][bottom][index][help] */
  41 {
  42   /* remove element from list(becomes a self-consistent list) */
  43   *datlist = g_list_remove_link(*datlist, element);
  44   
  45   /* free it and the payload */
  46   wr_clear_list( &element );
  47 }
  48 
  49 
  50 /**************************************************************************/
  51 /*+++++++++++
  52    helper: 
  53    this routine goes through the list of prefixes and performs a bin_search
  54    on each of them; attaches the results to datlist.
  55 +++++++++++*/
  56 static
  57 er_ret_t
  58 rp_preflist_search (
     /* [<][>][^][v][top][bottom][index][help] */
  59                     rx_srch_mt search_mode, 
  60                     int par_a,
  61                     int par_b,
  62                     rx_tree_t  *mytree,
  63                     GList    **preflist,
  64                     GList    **datlist
  65                     )
  66 
  67 { 
  68   char   prefstr[IP_PREFSTR_MAX];
  69   GList   *qitem;
  70   ip_prefix_t *querypref;
  71   er_ret_t err;
  72   
  73   for( qitem = g_list_first(*preflist);
  74        qitem != NULL;
  75        qitem = g_list_next(qitem)) {
  76     
  77     querypref = qitem->data;
  78     
  79     if( IP_pref_b2a( querypref, prefstr, IP_PREFSTR_MAX) != IP_OK ) {
  80       die;
  81     }
  82     ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
  83               "rx_preflist_search: mode %d (%s) (par %d) for %s", 
  84               search_mode, RX_text_srch_mode(search_mode), par_a, prefstr);
  85     
  86     if (mytree->num_nodes > 0) {
  87       err = RX_bin_search( search_mode, par_a, par_b, mytree, querypref, 
  88                    datlist, RX_ANS_ALL);
  89       if( err != RX_OK ) {
  90         return err;
  91       }
  92     }
  93   }
  94   
  95   return RX_OK;
  96 }
  97 
  98 /*++++
  99   this is a helper: goes through a datlist and returns the smallest
 100   size of a range
 101 
 102   works for IPv4 only
 103   +++*/
 104 static
 105 ip_rangesize_t
 106 rp_find_smallest_span( GList *datlist ) {
     /* [<][>][^][v][top][bottom][index][help] */
 107   ip_rangesize_t  min_span, span;
 108   GList *ditem;
 109 
 110   min_span = 0xffffffff; /* XXX IPv4 only!!!!*/
 111 
 112     /* go through the list and find the shortest range.    */
 113     for(ditem = g_list_first(datlist);
 114         ditem != NULL;
 115         ditem = g_list_next(ditem)) {
 116       rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 117       
 118       span = IP_rang_span( & refptr->leafptr->iprange);
 119       
 120       if( span < min_span ) {
 121         min_span = span;
 122       }
 123     }
 124     ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 125               "rp_find_smallest_span: minimal span is %d", min_span);
 126 
 127     return min_span;
 128 }
 129 
 130 
 131 
 132 /* helper for the inetnum/exless search - for this one a hash of pairs
 133 (leafptr,occurences) must be maintained.
 134 
 135 This routine increments the counter for a leafptr, creating a new
 136 pair if this leafptr was not referenced before.
 137 
 138 */
 139 static
 140 int rp_leaf_occ_inc(GHashTable *hash, rx_dataleaf_t *leafptr)
     /* [<][>][^][v][top][bottom][index][help] */
 141 {
 142   /* one little trick: store the number of occurences 
 143      as cast (void *) */
 144   int val;
 145   
 146   val = (int) g_hash_table_lookup(hash, leafptr);
 147   /* 0 if it's not known yet. anyway: put it in the hash (value==key) */
 148   
 149   g_hash_table_insert(hash, leafptr, (void *) ++val); 
 150   
 151   return val;
 152 }
 153 
 154 /* exclude exact match - not to be merged with preselction :-( */
 155 static void
 156 rp_exclude_exact_match( GList **datlist, ip_range_t *testrang) 
     /* [<][>][^][v][top][bottom][index][help] */
 157 {
 158   GList *ditem, *newitem;
 159   
 160   ditem = g_list_first(*datlist);
 161 
 162   while( ditem != NULL ) {
 163     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 164 
 165     newitem = g_list_next(ditem);
 166     
 167     if( memcmp( & refptr->leafptr->iprange, 
 168                 testrang, sizeof(ip_range_t)) == 0 ) {  
 169       rp_exclude_datlink(datlist, ditem);
 170       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 171                 "process_datlist: discarded an exact match");
 172     }
 173     ditem = newitem;
 174   } /* while */
 175 }
 176 
 177 static int
 178 rp_find_longest_prefix(GList **datlist)
     /* [<][>][^][v][top][bottom][index][help] */
 179 {
 180   GList *ditem;
 181   int max_pref=0;
 182 
 183   for(ditem = g_list_first(*datlist);
 184       ditem != NULL;
 185       ditem = g_list_next(ditem)) {
 186     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 187     
 188     if( refptr->leafptr->preflen > max_pref ) {
 189       max_pref = refptr->leafptr->preflen;
 190     }
 191   }
 192   
 193   return max_pref;
 194 }
 195 /*+ rp_asc_process_datlist() - helper for 
 196 
 197 
 198 /*+ rp_asc_process_datlist() - helper for RP_asc_search()
 199   
 200   fetches the copies of objects from the radix tree into datlist
 201 
 202      ASSUMES LOCKED TREE
 203 
 204      the behaviour for a default inetnum (range) query is: 
 205        do an exact match; 
 206        if it fails, do an exless match on the encompassing prefix
 207      for routes(prefixes):
 208        do an exless match
 209      
 210      So if it's the default search mode on an inetnum tree,
 211      and the key is a range, 
 212      then an exact search is performed on one of the composing prefixes.
 213 
 214      Then the resulting data leaves are checked for exact matching with 
 215      the range queried for.
 216      Any dataleaves that do not match are discarded, and if none are left,
 217      the procedure falls back to searching for the encompassing prefix.
 218      (calculated in the smart_conv routine). 
 219      Add the dataleaf copies to the list of answers, 
 220      taking span into account 
 221 +*/
 222 static
 223 er_ret_t
 224 rp_asc_process_datlist(
     /* [<][>][^][v][top][bottom][index][help] */
 225                        rx_srch_mt search_mode,
 226                        int        par_a,
 227                        rx_fam_t   fam_id,
 228                        int        prefnumber,
 229                        GList    **datlist,
 230                        ip_range_t *testrang,
 231                        int       *hits
 232                        )
 233 {
 234   ip_rangesize_t  min_span=0, span;
 235   int max_pref = -1;
 236   GList    *ditem, *newitem;
 237   GHashTable *lohash = g_hash_table_new(NULL, NULL);
 238  
 239   /* in MORE and LESS(1) search exact match must not be displayed */
 240   if ( search_mode == RX_SRCH_MORE 
 241        || ( search_mode == RX_SRCH_LESS && par_a == 1 ) ) {
 242     rp_exclude_exact_match(datlist, testrang);
 243   }
 244   
 245   /* Preselection moved to processing, only span calculation done here *
 246    * 
 247     
 248    EXLESS and LESS(1) search: the smallest span must be found,
 249    but if the less spec node is not the same for all composing prefixes,
 250    it means it's not really this one.
 251    
 252    we check that by the number of references to this node is less than
 253    the number of composing prefixes
 254    
 255    We do the same for the less specific search - a node must be less 
 256    specific to all prefixes.
 257    
 258    if the number of references is  not enough, then return no hits,
 259    another try will be made, this time with one, encompassing prefix.
 260   */
 261   
 262   if ( (search_mode == RX_SRCH_EXLESS )   
 263        || ( search_mode == RX_SRCH_LESS && par_a == 1 ) )  {
 264     /* span works only for IP_V4. We use it only for inetnums,
 265        although RT/v4 would work too */
 266     if( testrang->begin.space == IP_V4 &&
 267         fam_id == RX_FAM_IN ) {
 268       min_span = rp_find_smallest_span(*datlist);
 269     }
 270     else {
 271       /* in IPv6 and RT trees in general,  we can obtain the same
 272          result by selecting the longest prefix */
 273       max_pref = rp_find_longest_prefix(datlist);
 274     }
 275   }
 276   
 277   /* Process the dataleaf copies and add to the list of answers. */  
 278   ditem = g_list_first(*datlist);
 279   while(ditem != NULL) {
 280     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 281     int exclude = 0;
 282     
 283     if(search_mode == RX_SRCH_EXLESS || search_mode == RX_SRCH_LESS ) {
 284       
 285       /* min_span defined <=> EXLESS or LESS(1) search of INETNUMS: 
 286          the smallest span must be returned */
 287       if( !exclude && min_span != 0 
 288           && (span = IP_rang_span( &refptr->leafptr->iprange))!=min_span) {
 289         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 290                   "process_datlist: (EX)LESS: discarded object with span %d", span);
 291         exclude = 1;
 292       }
 293       /* max_pref defined <=> EXLESS search of INETNUMS or LESS(1) of RT:
 294        */
 295       if( !exclude && max_pref >= 0
 296           && refptr->leafptr->preflen < max_pref ) {
 297         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 298                   "process_datlist: (EX)LESS: discarded object with preflen %d", 
 299                   refptr->leafptr->preflen);
 300         exclude = 1;
 301       }
 302 
 303       /* number of occurences */
 304       /* XXX this will go when the old algorithm goes */
 305       if( !exclude 
 306           && prefnumber > 1 ) { /* do not check if all will be approved */
 307         
 308         if( rp_leaf_occ_inc(lohash, refptr->leafptr) < prefnumber ) {
 309           ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 310                     "process_datlist: (EX)LESS: leafptr %x not enough",refptr->leafptr);
 311           exclude = 1;
 312         } 
 313         else {
 314           ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 315                     "process_datlist: (EX)LESS: leafptr %x GOOD enough",refptr->leafptr);
 316         }
 317       }
 318     } 
 319     else if( search_mode ==  RX_SRCH_EXACT ) {
 320       /* EXACT search - discard if the range does not match */
 321       if( memcmp( & refptr->leafptr->iprange, 
 322                   testrang, sizeof(ip_range_t)) != 0) {
 323         
 324         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 325                   "process_datlist: EXACT; discarded a mismatch");
 326         exclude = 1;
 327       } /*  EXACT match */
 328     } 
 329     else if( search_mode ==  RX_SRCH_MORE ) {
 330       /* MORE: exclude if not fully contained in the search term */
 331       if( ! (IP_addr_in_rang(&refptr->leafptr->iprange.begin, testrang )
 332           && IP_addr_in_rang(&refptr->leafptr->iprange.end, testrang ))) {
 333         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 334                   "process_datlist: MORE; discarded a not-fully contained one");
 335         exclude = 1;
 336       }
 337     }
 338     
 339     
 340     /* get next item now, before the current gets deleted */
 341     newitem = g_list_next(ditem);
 342     if( exclude ) {
 343       /* get rid of it */
 344       rp_exclude_datlink(datlist, ditem);
 345     } 
 346     else {
 347       /* OK, so we ACCEPT these results*/
 348       /* uniqueness ensured in copy_results */
 349       (*hits)++;
 350     }
 351     ditem = newitem;
 352   } /* while ditem */ 
 353   
 354   /* wr_clear_list(&lolist); */
 355   g_hash_table_destroy(lohash);
 356   return RX_OK;
 357 }    
 358   
 359 /* 
 360    rp_mod_preflist() is a helper function for rp_asc_search().
 361 
 362    modifies the list of prefixes to search for, 
 363 
 364    special treatment for inetnum/exact:
 365    + a range that is equivalent to the search key (which may be a prefix)
 366      is made, to be used later for comparisons
 367      
 368    special treatment for inetnum/exless/composed:
 369    + the first pass mode is set to exact (otherwise to search_mode)
 370 
 371    a few optimisations are made:
 372    + for a route/composed_range/exact : the search is nuked
 373    + for an inetnum/composed_range/(exless|exact) : the list is truncated
 374      to one prefix, because in an exact search, it must be there anyway, 
 375      and for the exless, the smallest encompassing one must match
 376    
 377      
 378   */
 379   
 380 static
 381 er_ret_t 
 382 rp_mod_preflist(
     /* [<][>][^][v][top][bottom][index][help] */
 383                rx_srch_mt search_mode, 
 384                char *key,  
 385                ip_keytype_t key_type,
 386                rx_fam_t   fam_id,  
 387                GList **preflist,
 388                ip_range_t *testrang,
 389                rx_srch_mt *first_pass_mode
 390                ) 
 391 {
 392   int prefcount;
 393 
 394   prefcount = g_list_length(*preflist);
 395 
 396   /* EXACT search of a route tree for a composed range makes no sense */
 397   if( fam_id == RX_FAM_RT && search_mode == RX_SRCH_EXACT 
 398       && key_type == IPK_RANGE && prefcount > 1 ) {
 399     /* abort search - i.e. clear the preflist*/
 400 
 401       wr_clear_list( preflist);
 402       
 403       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 404         "rp_mod_preflist: route/exact/composed - preflist cleared");
 405   }
 406   
 407   /*+ inetnum / exact|exless specific :
 408     optimise: (composed range) 
 409     
 410       perform a separate first pass, with just one exact search on one of 
 411       the composing prefixes - the object must be found if it's in the 
 412       database.
 413       
 414       So a little cheat: remove all but one prefixes from preflist
 415       and force a different search mode
 416       +*/ 
 417   if( fam_id == RX_FAM_IN  
 418       && (search_mode == RX_SRCH_EXLESS || search_mode == RX_SRCH_EXACT) 
 419       && key_type == IPK_RANGE && prefcount > 1 ) { 
 420 
 421       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 422          "rp_mod_preflist: inet/ex***/composed - first pass EXACT forced");
 423 
 424       *first_pass_mode = RX_SRCH_EXACT;
 425   } /* inetnum / exact|exless specific */
 426 
 427   /* exact: set range so a comparison can be performed */
 428   /* must succeed after smart_conv succeeded */
 429   IP_smart_range(key, testrang, IP_EXPN, &key_type);
 430 
 431   return RX_OK;
 432 }
 433 /**************************************************************************/
 434 
 435 /*+ appends the element pointed to by datref to finallist +*/
 436 static
 437 er_ret_t
 438 rp_asc_append_datref(rx_datref_t *refptr, GList **finallist)
     /* [<][>][^][v][top][bottom][index][help] */
 439 {
 440   er_ret_t err;
 441   rx_datcpy_t *datcpy;
 442   void *dataptr;
 443 
 444     /* OK, so we ACCEPT this result. Copy it.*/
 445 
 446     if( (err=wr_calloc( (void **)& datcpy, 1, sizeof(rx_datcpy_t))) != UT_OK) {
 447       return err; /*    die;*/
 448     }
 449     
 450     datcpy->leafcpy = *(refptr->leafptr);
 451     
 452     /* copy the immediate data too. Set the ptr.*/
 453     
 454     if( (err=wr_calloc( (void **) & dataptr, 1, refptr->leafptr->data_len)) 
 455         != UT_OK) {
 456       return err; /*    die;*/
 457     }
 458     memcpy(dataptr, refptr->leafptr->data_ptr, refptr->leafptr->data_len);
 459     
 460     datcpy->leafcpy.data_ptr = dataptr;
 461 
 462     *finallist = g_list_prepend(*finallist, datcpy);
 463 
 464     /* XXX this wouldn't work in access_control */
 465     ER_dbg_va(FAC_RP, ASP_RP_SRCH_DATA,
 466               "rp_asc_append 'ed: %s", dataptr);
 467 
 468     return RX_OK;
 469 }
 470 
 471 /*+ goes through datlist (list of references "datref") and add copies of 
 472 leaves referenced to the finallist 
 473 
 474 maintains its own uniqhash which holds pointers to copied dataleaves.
 475 
 476 modifies: finallist
 477 
 478 returns: error from wr_malloc
 479 
 480 +*/
 481 static
 482 er_ret_t
 483 rp_srch_copyresults(GList *datlist,
     /* [<][>][^][v][top][bottom][index][help] */
 484                     GList **finallist,
 485                     int maxcount)
 486 {
 487   er_ret_t err;
 488   GList    *ditem, *uitem;
 489   GHashTable *uniqhash = g_hash_table_new(NULL, NULL); /* defaults */
 490   int count = 0;
 491 
 492   ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET, "srch_copyresults");
 493 
 494   /*  copy dataleaves pointed to by entries from the datlist
 495       only once (check uniqueness in the hash table) */
 496   for(ditem = g_list_first(datlist);
 497       ditem != NULL;
 498       ditem = g_list_next(ditem)) {
 499     rx_datref_t   *refptr = (rx_datref_t *) (ditem->data);
 500     rx_dataleaf_t *ansptr = refptr->leafptr;
 501 
 502     /* search for every ansptr (dataleaf pointer) in uniqhash */
 503     if( g_hash_table_lookup(uniqhash, ansptr) == NULL ) {
 504       
 505       /* it's not known yet. OK: put it in the hash (value==key) */
 506       g_hash_table_insert(uniqhash, ansptr, ansptr); 
 507       
 508       /* and copy the dataleaf */
 509       if( !NOERR(err = rp_asc_append_datref(refptr, finallist)) ) {
 510         return err;
 511       }
 512     }
 513 
 514     /* check the limit on number of objects if defined ( >0)  */
 515     count++;
 516     if( maxcount > 0 && count > maxcount ) {
 517       break;
 518     }
 519 
 520   } /*  foreach (datlist) */
 521     
 522   g_hash_table_destroy(uniqhash); /* elements are still linked to through datlist */
 523 
 524   return RP_OK;
 525 }
 526 
 527 static 
 528 void
 529 rp_begend_preselection(GList **datlist, rx_fam_t fam_id, ip_range_t *testrang) 
     /* [<][>][^][v][top][bottom][index][help] */
 530 {
 531   GList *ditem, *newitem; 
 532 
 533   ditem = g_list_first(*datlist);
 534 
 535   while( ditem != NULL ) {
 536     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 537     newitem = g_list_next(ditem);
 538 
 539     /* the test is indentical for route & inetnum trees */
 540     if( IP_addr_in_rang(&testrang->end, &refptr->leafptr->iprange) == 0 ) {
 541       
 542       rp_exclude_datlink(datlist, ditem);
 543       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 544                 "process_datlist: discarded an uncovering leafptr %x",
 545                 refptr->leafptr);
 546 
 547     }
 548     ditem = newitem;
 549   } /* while */
 550 }
 551 
 552 /*+++++++++++++++
 553   translates a query into a binary prefix (or prefixes, if range).
 554   for registry+space (or if they are zero, for all
 555   registries/spaces)
 556   finds tree 
 557   calls RX_bin_search (returning node copies).
 558   will not put duplicate entries (composed inetnums).
 559   returns some sort of error code :-) 
 560   
 561   Cuts the number of answers from RX_bin_search down to max_count,
 562   but since some of the answers may have been "normalized" in the
 563   underlying functions (multiple occurences removed), 
 564   the result is _at_most_ max_count.
 565   
 566   appends to a given list of data blocks (not nodes!)
 567 
 568   The EXLESS search on inetnum tree should return the shortest range 
 569   that was found, by means of comparing span (size) of the range.
 570   If there are more of size equal to the smallest one, they are also
 571   returned.
 572 
 573   returns RX_OK or a code from an underlying function
 574 ++++++++++++*/
 575 er_ret_t
 576 RP_asc_search ( 
     /* [<][>][^][v][top][bottom][index][help] */
 577                rx_srch_mt search_mode, 
 578                int par_a,
 579                int par_b,
 580                char *key,          /*+ search term: (string) prefix/range/IP +*/
 581                rp_regid_t   reg_id,
 582                rp_attr_t  attr,    /*+ extra tree id (within the same reg/spc/fam +*/
 583                GList **finallist,    /*+ answers go here, please +*/
 584                int    max_count    /*+ max # of answers. RX_ALLANS == unlimited +*/
 585                )
 586 { 
 587   GList    *preflist = NULL;
 588   GList    *datlist = NULL;
 589 
 590   er_ret_t   err; 
 591   ip_range_t testrang;
 592   int        locked = 0;
 593   rx_srch_mt first_pass_mode = search_mode;
 594   ip_keytype_t key_type;
 595   ip_space_t   spc_id;
 596   rx_fam_t   fam_id = RP_attr2fam( attr );
 597   rx_tree_t   *mytree;
 598   int hits=0;
 599   int par_a_lyse;
 600 
 601   /*  abort on error (but unlock the tree) */  
 602   ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
 603             "RP_asc_search:  query %s : mode %d (%s) (par %d) for %s",
 604             DF_get_attribute_name(attr),
 605             search_mode, RX_text_srch_mode(search_mode), par_a, key);
 606 
 607   /* parse the key */
 608   if( ( err = IP_smart_conv(key, 0, 0,
 609                             &preflist, IP_EXPN, &key_type)) != IP_OK ) {
 610     /* XXX operational trouble (UT_*) or invalid key (IP_INVARG)*/
 611     return err; 
 612   }
 613   
 614   /* 1. find the tree */
 615   if( NOERR(err) ) {
 616     spc_id = IP_pref_b2_space( g_list_first(preflist)->data );
 617     err = RP_tree_get( &mytree, reg_id, spc_id, attr );
 618   }
 619 
 620   if( ! NOERR(err) ) {
 621     return err;
 622   }
 623 
 624   /* 2. lock the tree */
 625   TH_acquire_read_lock( &(mytree->rwlock) );
 626   locked = 1;
 627 
 628 
 629   /* XXX what an awful hack!!! 
 630      In LESS(1) lookup, we have to provide more data so that something
 631      remains after the exact match is discarded.
 632    */
 633   par_a_lyse =  (search_mode == RX_SRCH_LESS && par_a == 1 ) ? 255 : par_a;
 634 
 635   /*   0. check the list of prefixes to search for */
 636   err = rp_mod_preflist(search_mode, key, key_type, fam_id, 
 637                         &preflist, &testrang, &first_pass_mode);
 638 
 639   /*  a special first pass EXACT is needed for inetnums */
 640   if( first_pass_mode != search_mode ) {
 641     ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
 642               "RP_asc_search: doing pass 0 with mode %d", first_pass_mode );    /* 3. do the first pass */
 643     err = rp_preflist_search ( first_pass_mode, par_a, par_b, 
 644                                mytree, &preflist, &datlist);
 645   }
 646   if( NOERR(err) ) {
 647     /* 4. process the data pointers obtained from the search */
 648     err = rp_asc_process_datlist( first_pass_mode, par_a, fam_id, 
 649                                   g_list_length(preflist),  &datlist,  
 650                                   &testrang,  &hits );
 651   }
 652   
 653   if( hits == 0 ) {
 654     /*  clear datlist from discarded elements */
 655     wr_clear_list( &datlist );
 656     /* reuse the preflist */
 657 
 658     ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
 659                 "rp_asc_search: doing pass 1 with mode %d", search_mode);
 660     /* 3. perform the real search on all prefixes the query was converted to */
 661     err = rp_preflist_search ( search_mode, par_a_lyse, par_b, 
 662                                mytree, &preflist, &datlist);
 663     
 664     if( NOERR(err) ) {
 665       /* 4. process the data pointers obtained from the search */
 666       err = rp_asc_process_datlist( search_mode, par_a, fam_id, 
 667                                     g_list_length(preflist), &datlist, 
 668                                     &testrang, &hits );
 669     }
 670   }
 671   
 672   if( NOERR(err) ) {
 673     /* 5. an inetnum/composed/exless was forced to exact in the first go.
 674        So if the exact did not match yet, an encompassing prefix must 
 675        be searched in exless mode */
 676     if(  hits == 0 ) {
 677       ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
 678                 "rp_asc_search: doing pass 2 with mode %d", search_mode);
 679       
 680       /* clean old lists */
 681       wr_clear_list( &preflist );
 682       wr_clear_list( &datlist );
 683       
 684       /* make a new prefix list with the encompassing prefix only */
 685       dieif ( IP_smart_conv(key, 0, 1,
 686                             &preflist, IP_EXPN, &key_type) != IP_OK);
 687       
 688       /* search again, this time with the real search_mode */
 689       err = rp_preflist_search ( search_mode, par_a, par_b, 
 690                                 mytree, &preflist, &datlist);
 691       
 692       if( err == RX_OK ) {
 693         /*  process the data pointers obtained from the search */
 694         err = rp_asc_process_datlist( search_mode, par_a, fam_id, 
 695                                       g_list_length(preflist), &datlist, 
 696                                       &testrang, &hits  );
 697       }
 698     }
 699   }
 700   
 701   if( NOERR(err) ) {
 702     err = rp_srch_copyresults(datlist, finallist, max_count); /* and uniq */
 703   }
 704 
 705   if( locked ) {
 706     /* 100. unlock the tree */
 707     TH_release_read_lock( &(mytree->rwlock) );
 708   }
 709 
 710   /* clean up */
 711   wr_clear_list( &preflist ); 
 712   wr_clear_list( &datlist );  
 713 
 714   return err;
 715 }
 716 
 717 
 718 
 719      
 720 er_ret_t
 721 RP_new_asc_search ( 
     /* [<][>][^][v][top][bottom][index][help] */
 722                rx_srch_mt search_mode, 
 723                int par_a,
 724                int par_b,
 725                char *key,     /*+ search term: (string) prefix/range/IP +*/
 726                rp_regid_t  reg_id,
 727                rp_attr_t  attr,    /*+ extra tree id (within the same reg/spc/fam +*/
 728                GList **finallist,    /*+ answers go here, please +*/
 729                int    max_count    /*+ max # of answers. RX_ALLANS == unlimited +*/
 730                )
 731 { 
 732   GList    *preflist = NULL;
 733   GList    *datlist = NULL;
 734 
 735   er_ret_t   err; 
 736   ip_range_t  testrang;
 737   int        locked = 0;
 738   ip_keytype_t key_type;
 739   ip_space_t   spc_id;
 740   rx_fam_t   fam_id = RP_attr2fam( attr );
 741   rx_tree_t   *mytree;
 742   int hits=0;
 743   unsigned begin,end;
 744   ip_prefix_t beginpref;
 745   
 746 
 747   /*  abort on error (but unlock the tree) */  
 748   ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
 749             "RP_NEW_asc_search:  query %s : mode %d (%s) (par %d) for %s",
 750             DF_get_attribute_name(attr),
 751             search_mode, RX_text_srch_mode(search_mode), par_a, key);
 752 
 753   
 754   /* parse the key into a prefix list */
 755   if( ( err = IP_smart_conv(key, 0, 0,
 756                             &preflist, IP_EXPN, &key_type)) != IP_OK ) {
 757     /* XXX operational trouble (UT_*) or invalid key (IP_INVARG)*/
 758     return err; 
 759   }
 760 
 761   /* set the test values */
 762   IP_smart_range(key, &testrang, IP_EXPN, &key_type);
 763   
 764   /* find the tree */
 765   if( NOERR(err) ) {
 766     spc_id = IP_pref_b2_space( g_list_first(preflist)->data );
 767     if( ! NOERR(err = RP_tree_get( &mytree, reg_id, spc_id, attr ))) {
 768       return err;
 769     }
 770   }
 771   /* the point of no return: now we lock the tree. From here, even if errors
 772      occur, we still go through all procedure to unlock the tree at the end */
 773   
 774   /* lock the tree */
 775   TH_acquire_read_lock( &(mytree->rwlock) );
 776   locked = 1;
 777 
 778   /* Collection: this procedure is used for some search_modes only */
 779   if(    search_mode == RX_SRCH_EXLESS 
 780       || search_mode == RX_SRCH_LESS 
 781       || search_mode == RX_SRCH_EXACT )  {
 782 
 783     /* 1. compose a /32(/128) prefix for beginning of range */
 784     beginpref.ip = testrang.begin;
 785     beginpref.bits = IP_sizebits(spc_id);
 786     
 787     /* 2. dataleaves collection: look up the beginning prefix in LESS(255) mode */
 788     if( NOERR(err) ) {
 789       err = RX_bin_search( RX_SRCH_LESS, 255, 0, mytree, &beginpref, 
 790                            &datlist, RX_ANS_ALL);
 791     }
 792     
 793     /* 3. preselection: exclude those that do not include end of range 
 794      */
 795     if( NOERR(err) ) {
 796       rp_begend_preselection(&datlist, fam_id, &testrang);
 797     }
 798 
 799   } /* if exless|less|exact */
 800   else {
 801     /* MORE */
 802 
 803     /* standard collection using the traditional method: 
 804        repeat the search for all prefixes and join results */
 805 
 806     if( NOERR(err) ) {
 807       err = rp_preflist_search ( search_mode, par_a, par_b, 
 808                                  mytree, &preflist, &datlist);
 809     }
 810   } /* collection */
 811 
 812   ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
 813             "RP_NEW_asc_search: collected %d references ",
 814             g_list_length(datlist));
 815 
 816 
 817   /* 5. processing - using the same processing function */
 818   if( NOERR(err) ) {
 819     err = rp_asc_process_datlist( search_mode, par_a, fam_id, 
 820                                   1, /* one occurence is enough */
 821                                   &datlist,  
 822                                   &testrang,  &hits );
 823   }
 824   
 825   /* 6. copy results */
 826   if( NOERR(err) ) {
 827     err = rp_srch_copyresults(datlist, finallist, max_count); /* and uniq */
 828   }
 829 
 830   if( locked ) {
 831     /* 100. unlock the tree */
 832     TH_release_read_lock( &(mytree->rwlock) );
 833   }
 834 
 835   /* clean up */
 836   wr_clear_list( &preflist ); 
 837   wr_clear_list( &datlist );  
 838 
 839   /* NOTE if error occured, finallist may be partly filled in. */
 840   return err;
 841 }
 842   

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