## 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.10 $
       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
     196
     197 /*+ rp_asc_process_datlist() - helper for RP_asc_search()
     198
     199   fetches the copies of objects from the radix tree into datlist
     200
     201      ASSUMES LOCKED TREE
     202
     203      the behaviour for a default inetnum (range) query is:
     204        do an exact match;
     205        if it fails, do an exless match on the encompassing prefix
     206      for routes(prefixes):
     207        do an exless match
     208
     209      So if it's the default search mode on an inetnum tree,
     210      and the key is a range,
     211      then an exact search is performed on one of the composing prefixes.
     212
     213      Then the resulting data leaves are checked for exact matching with
     214      the range queried for.
     215      Any dataleaves that do not match are discarded, and if none are left,
     216      the procedure falls back to searching for the encompassing prefix.
     217      (calculated in the smart_conv routine).
     218      Add the dataleaf copies to the list of answers,
     219      taking span into account
     220 +*/
     221 static
     222 er_ret_t
     223 rp_asc_process_datlist(
         /* [<][>][^][v][top][bottom][index][help] */
     224                        rx_srch_mt search_mode,
     225                        int        par_a,
     226                        rx_fam_t   fam_id,
     227                        int        prefnumber,
     228                        GList    **datlist,
     229                        ip_range_t *testrang,
     230                        int       *hits
     231                        )
     232 {
     233   ip_rangesize_t  min_span=0, span;
     234   int max_pref = -1;
     235   GList    *ditem, *newitem;
     236   GHashTable *lohash = g_hash_table_new(NULL, NULL);
     237
     238   /* in MORE and LESS(1) search exact match must not be displayed */
     239   if ( search_mode == RX_SRCH_MORE
     240        || ( search_mode == RX_SRCH_LESS && par_a == 1 ) ) {
     241     rp_exclude_exact_match(datlist, testrang);
     242   }
     243
     244   /* Preselection moved to processing, only span calculation done here *
     245    *
     246
     247    EXLESS and LESS(1) search: the smallest span must be found,
     248    but if the less spec node is not the same for all composing prefixes,
     249    it means it's not really this one.
     250
     251    we check that by the number of references to this node is less than
     252    the number of composing prefixes
     253
     254    We do the same for the less specific search - a node must be less
     255    specific to all prefixes.
     256
     257    if the number of references is  not enough, then return no hits,
     258    another try will be made, this time with one, encompassing prefix.
     259   */
     260
     261   if ( (search_mode == RX_SRCH_EXLESS )
     262        || ( search_mode == RX_SRCH_LESS && par_a == 1 ) )  {
     263     /* span works only for IP_V4. We use it only for inetnums,
     264        although RT/v4 would work too */
     265     if( testrang->begin.space == IP_V4 &&
     266         fam_id == RX_FAM_IN ) {
     267       min_span = rp_find_smallest_span(*datlist);
     268     }
     269     else {
     270       /* in IPv6 and RT trees in general,  we can obtain the same
     271          result by selecting the longest prefix */
     272       max_pref = rp_find_longest_prefix(datlist);
     273     }
     274   }
     275
     276   /* Process the dataleaf copies and add to the list of answers. */
     277   ditem = g_list_first(*datlist);
     278   while(ditem != NULL) {
     279     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
     280     int exclude = 0;
     281
     282     if(search_mode == RX_SRCH_EXLESS || search_mode == RX_SRCH_LESS ) {
     283
     284       /* min_span defined <=> EXLESS or LESS(1) search of INETNUMS:
     285          the smallest span must be returned */
     286       if( !exclude && min_span != 0
     287           && (span = IP_rang_span( &refptr->leafptr->iprange))!=min_span) {
     288         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
     289                   "process_datlist: (EX)LESS: discarded object with span %d", span);
     290         exclude = 1;
     291       }
     292       /* max_pref defined <=> EXLESS search of INETNUMS or LESS(1) of RT:
     293        */
     294       if( !exclude && max_pref >= 0
     295           && refptr->leafptr->preflen < max_pref ) {
     296         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
     297                   "process_datlist: (EX)LESS: discarded object with preflen %d",
     298                   refptr->leafptr->preflen);
     299         exclude = 1;
     300       }
     301
     302       /* number of occurences */
     303       /* XXX this will go when the old algorithm goes */
     304       if( !exclude
     305           && prefnumber > 1 ) { /* do not check if all will be approved */
     306
     307         if( rp_leaf_occ_inc(lohash, refptr->leafptr) < prefnumber ) {
     308           ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
     309                     "process_datlist: (EX)LESS: leafptr %x not enough",refptr->leafptr);
     310           exclude = 1;
     311         }
     312         else {
     313           ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
     314                     "process_datlist: (EX)LESS: leafptr %x GOOD enough",refptr->leafptr);
     315         }
     316       }
     317     }
     318     else if( search_mode ==  RX_SRCH_EXACT ) {
     319       /* EXACT search - discard if the range does not match */
     320       if( memcmp( & refptr->leafptr->iprange,
     321                   testrang, sizeof(ip_range_t)) != 0) {
     322
     323         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
     324                   "process_datlist: EXACT; discarded a mismatch");
     325         exclude = 1;
     326       } /*  EXACT match */
     327     }
     328     else if( search_mode ==  RX_SRCH_MORE ) {
     329       /* MORE: exclude if not fully contained in the search term */
     330       if( ! (IP_addr_in_rang(&refptr->leafptr->iprange.begin, testrang )
     331           && IP_addr_in_rang(&refptr->leafptr->iprange.end, testrang ))) {
     332         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
     333                   "process_datlist: MORE; discarded a not-fully contained one");
     334         exclude = 1;
     335       }
     336     }
     337
     338
     339     /* get next item now, before the current gets deleted */
     340     newitem = g_list_next(ditem);
     341     if( exclude ) {
     342       /* get rid of it */
     343       rp_exclude_datlink(datlist, ditem);
     344     }
     345     else {
     346       /* OK, so we ACCEPT these results*/
     347       /* uniqueness ensured in copy_results */
     348       (*hits)++;
     349     }
     350     ditem = newitem;
     351   } /* while ditem */
     352
     353   /* wr_clear_list(&lolist); */
     354   g_hash_table_destroy(lohash);
     355   return RX_OK;
     356 }
     357
     358 /*
     359    rp_mod_preflist() is a helper function for rp_asc_search().
     360
     361    modifies the list of prefixes to search for,
     362
     363    special treatment for inetnum/exact:
     364    + a range that is equivalent to the search key (which may be a prefix)
     365      is made, to be used later for comparisons
     366
     367    special treatment for inetnum/exless/composed:
     368    + the first pass mode is set to exact (otherwise to search_mode)
     369
     370    a few optimisations are made:
     371    + for a route/composed_range/exact : the search is nuked
     372    + for an inetnum/composed_range/(exless|exact) : the list is truncated
     373      to one prefix, because in an exact search, it must be there anyway,
     374      and for the exless, the smallest encompassing one must match
     375
     376
     377   */
     378
     379 static
     380 er_ret_t
     381 rp_mod_preflist(
         /* [<][>][^][v][top][bottom][index][help] */
     382                rx_srch_mt search_mode,
     383                char *key,
     384                ip_keytype_t key_type,
     385                rx_fam_t   fam_id,
     386                GList **preflist,
     387                ip_range_t *testrang,
     388                rx_srch_mt *first_pass_mode
     389                )
     390 {
     391   int prefcount;
     392
     393   prefcount = g_list_length(*preflist);
     394
     395   /* EXACT search of a route tree for a composed range makes no sense */
     396   if( fam_id == RX_FAM_RT && search_mode == RX_SRCH_EXACT
     397       && key_type == IPK_RANGE && prefcount > 1 ) {
     398     /* abort search - i.e. clear the preflist*/
     399
     400       wr_clear_list( preflist);
     401
     402       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
     403         "rp_mod_preflist: route/exact/composed - preflist cleared");
     404   }
     405
     406   /*+ inetnum / exact|exless specific :
     407     optimise: (composed range)
     408
     409       perform a separate first pass, with just one exact search on one of
     410       the composing prefixes - the object must be found if it's in the
     411       database.
     412
     413       So a little cheat: remove all but one prefixes from preflist
     414       and force a different search mode
     415       +*/
     416   if( fam_id == RX_FAM_IN
     417       && (search_mode == RX_SRCH_EXLESS || search_mode == RX_SRCH_EXACT)
     418       && key_type == IPK_RANGE && prefcount > 1 ) {
     419
     420       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
     421          "rp_mod_preflist: inet/ex***/composed - first pass EXACT forced");
     422
     423       *first_pass_mode = RX_SRCH_EXACT;
     424   } /* inetnum / exact|exless specific */
     425
     426   /* exact: set range so a comparison can be performed */
     427   /* must succeed after smart_conv succeeded */
     428   IP_smart_range(key, testrang, IP_EXPN, &key_type);
     429
     430   return RX_OK;
     431 }
     432 /**************************************************************************/
     433
     434 /*+ appends the element pointed to by datref to finallist +*/
     435 static
     436 er_ret_t
     437 rp_asc_append_datref(rx_datref_t *refptr, GList **finallist)
         /* [<][>][^][v][top][bottom][index][help] */
     438 {
     439   er_ret_t err;
     440   rx_datcpy_t *datcpy;
     441   void *dataptr;
     442
     443     /* OK, so we ACCEPT this result. Copy it.*/
     444
     445     if( (err=wr_calloc( (void **)& datcpy, 1, sizeof(rx_datcpy_t))) != UT_OK) {
     446       return err; /*    die;*/
     447     }
     448
     449     datcpy->leafcpy = *(refptr->leafptr);
     450
     451     /* copy the immediate data too. Set the ptr.*/
     452
     453     if( (err=wr_calloc( (void **) & dataptr, 1, refptr->leafptr->data_len))
     454         != UT_OK) {
     455       return err; /*    die;*/
     456     }
     457     memcpy(dataptr, refptr->leafptr->data_ptr, refptr->leafptr->data_len);
     458
     459     datcpy->leafcpy.data_ptr = dataptr;
     460
     461     *finallist = g_list_prepend(*finallist, datcpy);
     462
     463     /* XXX this wouldn't work in access_control */
     464     ER_dbg_va(FAC_RP, ASP_RP_SRCH_DATA,
     465               "rp_asc_append 'ed: %s", dataptr);
     466
     467     return RX_OK;
     468 }
     469
     470 /*+ goes through datlist (list of references "datref") and add copies of
     471 leaves referenced to the finallist
     472
     473 maintains its own uniqhash which holds pointers to copied dataleaves.
     474
     475 modifies: finallist
     476
     477 returns: error from wr_malloc
     478
     479 +*/
     480 static
     481 er_ret_t
     482 rp_srch_copyresults(GList *datlist,
         /* [<][>][^][v][top][bottom][index][help] */
     483                     GList **finallist,
     484                     int maxcount)
     485 {
     486   er_ret_t err;
     487   GList    *ditem;
     488   GHashTable *uniqhash = g_hash_table_new(NULL, NULL); /* defaults */
     489   int count = 0;
     490
     491   ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET, "srch_copyresults");
     492
     493   /*  copy dataleaves pointed to by entries from the datlist
     494       only once (check uniqueness in the hash table) */
     495   for(ditem = g_list_first(datlist);
     496       ditem != NULL;
     497       ditem = g_list_next(ditem)) {
     498     rx_datref_t   *refptr = (rx_datref_t *) (ditem->data);
     499     rx_dataleaf_t *ansptr = refptr->leafptr;
     500
     501     /* search for every ansptr (dataleaf pointer) in uniqhash */
     502     if( g_hash_table_lookup(uniqhash, ansptr) == NULL ) {
     503
     504       /* it's not known yet. OK: put it in the hash (value==key) */
     505       g_hash_table_insert(uniqhash, ansptr, ansptr);
     506
     507       /* and copy the dataleaf */
     508       if( !NOERR(err = rp_asc_append_datref(refptr, finallist)) ) {
     509         return err;
     510       }
     511     }
     512
     513     /* check the limit on number of objects if defined ( >0)  */
     514     count++;
     515     if( maxcount > 0 && count > maxcount ) {
     516       break;
     517     }
     518
     519   } /*  foreach (datlist) */
     520
     521   g_hash_table_destroy(uniqhash); /* elements are still linked to through datlist */
     522
     523   return RP_OK;
     524 }
     525
     526 static
     527 void
     528 rp_begend_preselection(GList **datlist, rx_fam_t fam_id, ip_range_t *testrang)
         /* [<][>][^][v][top][bottom][index][help] */
     529 {
     530   GList *ditem, *newitem;
     531
     532   ditem = g_list_first(*datlist);
     533
     534   while( ditem != NULL ) {
     535     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
     536     newitem = g_list_next(ditem);
     537
     538     /* the test is indentical for route & inetnum trees */
     539     if( IP_addr_in_rang(&testrang->end, &refptr->leafptr->iprange) == 0 ) {
     540
     541       rp_exclude_datlink(datlist, ditem);
     542       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
     543                 "process_datlist: discarded an uncovering leafptr %x",
     544                 refptr->leafptr);
     545
     546     }
     547     ditem = newitem;
     548   } /* while */
     549 }
     550
     551 /*+++++++++++++++
     552   translates a query into a binary prefix (or prefixes, if range).
     553   for registry+space (or if they are zero, for all
     554   registries/spaces)
     555   finds tree
     556   calls RX_bin_search (returning node copies).
     557   will not put duplicate entries (composed inetnums).
     558   returns some sort of error code :-)
     559
     560   Cuts the number of answers from RX_bin_search down to max_count,
     561   but since some of the answers may have been "normalized" in the
     562   underlying functions (multiple occurences removed),
     563   the result is _at_most_ max_count.
     564
     565   appends to a given list of data blocks (not nodes!)
     566
     567   The EXLESS search on inetnum tree should return the shortest range
     568   that was found, by means of comparing span (size) of the range.
     569   If there are more of size equal to the smallest one, they are also
     570   returned.
     571
     572   returns RX_OK or a code from an underlying function
     573 ++++++++++++*/
     574 er_ret_t
     575 RP_asc_search (
         /* [<][>][^][v][top][bottom][index][help] */
     576                rx_srch_mt search_mode,
     577                int par_a,
     578                int par_b,
     579                char *key,          /*+ search term: (string) prefix/range/IP +*/
     580                rp_regid_t   reg_id,
     581                rp_attr_t  attr,    /*+ extra tree id (within the same reg/spc/fam +*/
     582                GList **finallist,    /*+ answers go here, please +*/
     583                int    max_count    /*+ max # of answers. RX_ALLANS == unlimited +*/
     584                )
     585 {
     586   GList    *preflist = NULL;
     587   GList    *datlist = NULL;
     588
     589   er_ret_t   err;
     590   ip_range_t testrang;
     591   int        locked = 0;
     592   rx_srch_mt first_pass_mode = search_mode;
     593   ip_keytype_t key_type;
     594   ip_space_t   spc_id;
     595   rx_fam_t   fam_id = RP_attr2fam( attr );
     596   rx_tree_t   *mytree;
     597   int hits=0;
     598   int par_a_lyse;
     599
     600   /*  abort on error (but unlock the tree) */
     601   ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
     602             "RP_asc_search:  query %s : mode %d (%s) (par %d) for %s",
     603             DF_get_attribute_name(attr),
     604             search_mode, RX_text_srch_mode(search_mode), par_a, key);
     605
     606   /* parse the key */
     607   if( ( err = IP_smart_conv(key, 0, 0,
     608                             &preflist, IP_EXPN, &key_type)) != IP_OK ) {
     609     /* XXX operational trouble (UT_*) or invalid key (IP_INVARG)*/
     610     return err;
     611   }
     612
     613   /* 1. find the tree */
     614   if( NOERR(err) ) {
     615     spc_id = IP_pref_b2_space( g_list_first(preflist)->data );
     616     err = RP_tree_get( &mytree, reg_id, spc_id, attr );
     617   }
     618
     619   if( ! NOERR(err) ) {
     620     return err;
     621   }
     622
     623   /* 2. lock the tree */
     624   TH_acquire_read_lock( &(mytree->rwlock) );
     625   locked = 1;
     626
     627
     628   /* XXX what an awful hack!!!
     629      In LESS(1) lookup, we have to provide more data so that something
     630      remains after the exact match is discarded.
     631    */
     632   par_a_lyse =  (search_mode == RX_SRCH_LESS && par_a == 1 ) ? 255 : par_a;
     633
     634   /*   0. check the list of prefixes to search for */
     635   err = rp_mod_preflist(search_mode, key, key_type, fam_id,
     636                         &preflist, &testrang, &first_pass_mode);
     637
     638   /*  a special first pass EXACT is needed for inetnums */
     639   if( first_pass_mode != search_mode ) {
     640     ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
     641               "RP_asc_search: doing pass 0 with mode %d", first_pass_mode );    /* 3. do the first pass */
     642     err = rp_preflist_search ( first_pass_mode, par_a, par_b,
     643                                mytree, &preflist, &datlist);
     644   }
     645   if( NOERR(err) ) {
     646     /* 4. process the data pointers obtained from the search */
     647     err = rp_asc_process_datlist( first_pass_mode, par_a, fam_id,
     648                                   g_list_length(preflist),  &datlist,
     649                                   &testrang,  &hits );
     650   }
     651
     652   if( hits == 0 ) {
     653     /*  clear datlist from discarded elements */
     654     wr_clear_list( &datlist );
     655     /* reuse the preflist */
     656
     657     ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
     658                 "rp_asc_search: doing pass 1 with mode %d", search_mode);
     659     /* 3. perform the real search on all prefixes the query was converted to */
     660     err = rp_preflist_search ( search_mode, par_a_lyse, par_b,
     661                                mytree, &preflist, &datlist);
     662
     663     if( NOERR(err) ) {
     664       /* 4. process the data pointers obtained from the search */
     665       err = rp_asc_process_datlist( search_mode, par_a, fam_id,
     666                                     g_list_length(preflist), &datlist,
     667                                     &testrang, &hits );
     668     }
     669   }
     670
     671   if( NOERR(err) ) {
     672     /* 5. an inetnum/composed/exless was forced to exact in the first go.
     673        So if the exact did not match yet, an encompassing prefix must
     674        be searched in exless mode */
     675     if(  hits == 0 ) {
     676       ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
     677                 "rp_asc_search: doing pass 2 with mode %d", search_mode);
     678
     679       /* clean old lists */
     680       wr_clear_list( &preflist );
     681       wr_clear_list( &datlist );
     682
     683       /* make a new prefix list with the encompassing prefix only */
     684       dieif ( IP_smart_conv(key, 0, 1,
     685                             &preflist, IP_EXPN, &key_type) != IP_OK);
     686
     687       /* search again, this time with the real search_mode */
     688       err = rp_preflist_search ( search_mode, par_a, par_b,
     689                                 mytree, &preflist, &datlist);
     690
     691       if( err == RX_OK ) {
     692         /*  process the data pointers obtained from the search */
     693         err = rp_asc_process_datlist( search_mode, par_a, fam_id,
     694                                       g_list_length(preflist), &datlist,
     695                                       &testrang, &hits  );
     696       }
     697     }
     698   }
     699
     700   if( NOERR(err) ) {
     701     err = rp_srch_copyresults(datlist, finallist, max_count); /* and uniq */
     702   }
     703
     704   if( locked ) {
     705     /* 100. unlock the tree */
     706     TH_release_read_lock( &(mytree->rwlock) );
     707   }
     708
     709   /* clean up */
     710   wr_clear_list( &preflist );
     711   wr_clear_list( &datlist );
     712
     713   return err;
     714 }
     715
     716
     717
     718
     719 er_ret_t
     720 RP_new_asc_search (
         /* [<][>][^][v][top][bottom][index][help] */
     721                rx_srch_mt search_mode,
     722                int par_a,
     723                int par_b,
     724                char *key,     /*+ search term: (string) prefix/range/IP +*/
     725                rp_regid_t  reg_id,
     726                rp_attr_t  attr,    /*+ extra tree id (within the same reg/spc/fam +*/
     727                GList **finallist,    /*+ answers go here, please +*/
     728                int    max_count    /*+ max # of answers. RX_ALLANS == unlimited +*/
     729                )
     730 {
     731   GList    *preflist = NULL;
     732   GList    *datlist = NULL;
     733   er_ret_t   err;
     734   ip_range_t  testrang;
     735   int        locked = 0;
     736   ip_keytype_t key_type;
     737   ip_space_t   spc_id;
     738   rx_fam_t   fam_id = RP_attr2fam( attr );
     739   rx_tree_t   *mytree;
     740   int hits=0;
     741   ip_prefix_t beginpref;
     742
     743
     744   /*  abort on error (but unlock the tree) */
     745   ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
     746             "RP_NEW_asc_search:  query %s : mode %d (%s) (par %d) for %s",
     747             DF_get_attribute_name(attr),
     748             search_mode, RX_text_srch_mode(search_mode), par_a, key);
     749
     750
     751   /* parse the key into a prefix list */
     752   if( ( err = IP_smart_conv(key, 0, 0,
     753                             &preflist, IP_EXPN, &key_type)) != IP_OK ) {
     754     /* XXX operational trouble (UT_*) or invalid key (IP_INVARG)*/
     755     return err;
     756   }
     757
     758   /* set the test values */
     759   IP_smart_range(key, &testrang, IP_EXPN, &key_type);
     760
     761   /* find the tree */
     762   if( NOERR(err) ) {
     763     spc_id = IP_pref_b2_space( g_list_first(preflist)->data );
     764     if( ! NOERR(err = RP_tree_get( &mytree, reg_id, spc_id, attr ))) {
     765       return err;
     766     }
     767   }
     768   /* the point of no return: now we lock the tree. From here, even if errors
     769      occur, we still go through all procedure to unlock the tree at the end */
     770
     771   /* lock the tree */
     772   TH_acquire_read_lock( &(mytree->rwlock) );
     773   locked = 1;
     774
     775   /* Collection: this procedure is used for some search_modes only */
     776   if(    search_mode == RX_SRCH_EXLESS
     777       || search_mode == RX_SRCH_LESS
     778       || search_mode == RX_SRCH_EXACT )  {
     779
     780     /* 1. compose a /32(/128) prefix for beginning of range */
     781     beginpref.ip = testrang.begin;
     782     beginpref.bits = IP_sizebits(spc_id);
     783
     784     /* 2. dataleaves collection: look up the beginning prefix in LESS(255) mode */
     785     if( NOERR(err) ) {
     786       err = RX_bin_search( RX_SRCH_LESS, 255, 0, mytree, &beginpref,
     787                            &datlist, RX_ANS_ALL);
     788     }
     789
     790     /* 3. preselection: exclude those that do not include end of range
     791      */
     792     if( NOERR(err) ) {
     793       rp_begend_preselection(&datlist, fam_id, &testrang);
     794     }
     795
     796   } /* if exless|less|exact */
     797   else {
     798     /* MORE */
     799
     800     /* standard collection using the traditional method:
     801        repeat the search for all prefixes and join results */
     802
     803     if( NOERR(err) ) {
     804       err = rp_preflist_search ( search_mode, par_a, par_b,
     805                                  mytree, &preflist, &datlist);
     806     }
     807   } /* collection */
     808
     809   ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
     810             "RP_NEW_asc_search: collected %d references ",
     811             g_list_length(datlist));
     812
     813
     814   /* 5. processing - using the same processing function */
     815   if( NOERR(err) ) {
     816     err = rp_asc_process_datlist( search_mode, par_a, fam_id,
     817                                   1, /* one occurence is enough */
     818                                   &datlist,
     819                                   &testrang,  &hits );
     820   }
     821
     822   /* 6. copy results */
     823   if( NOERR(err) ) {
     824     err = rp_srch_copyresults(datlist, finallist, max_count); /* and uniq */
     825   }
     826
     827   if( locked ) {
     828     /* 100. unlock the tree */
     829     TH_release_read_lock( &(mytree->rwlock) );
     830   }
     831
     832   /* clean up */
     833   wr_clear_list( &preflist );
     834   wr_clear_list( &datlist );
     835
     836   /* NOTE if error occured, finallist may be partly filled in. */
     837   return err;
     838 }
     839

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