modules/rp/rp_search.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rp_exclude_datlink
- rp_preflist_search
- rp_find_smallest_span
- rp_leaf_occ_inc
- rp_exclude_exact_match
- rp_find_longest_prefix
- rp_asc_process_datlist
- rp_mod_preflist
- rp_asc_append_datref
- rp_srch_copyresults
- rp_begend_preselection
- RP_asc_search
- 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