rpatricia 0.04

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (10) hide show
  1. data/Changes +16 -0
  2. data/README +179 -0
  3. data/TODO +2 -0
  4. data/copyright +34 -0
  5. data/credits.txt +73 -0
  6. data/extconf.rb +5 -0
  7. data/patricia.c +1038 -0
  8. data/patricia.h +147 -0
  9. data/rpatricia.c +225 -0
  10. metadata +71 -0
data/Changes ADDED
@@ -0,0 +1,16 @@
1
+ 0.04 2008/2/19
2
+ - fixed the bug of "clear" method (destroy)
3
+ node data were not cleared correctly
4
+
5
+ - fixed the memory leak in search methods
6
+ I had to clear the prefix instances
7
+
8
+ 0.03 2008/2/17
9
+ - fixed the bug of allocating user_data strings
10
+
11
+ 0.02 2008/1/31
12
+ - fixed the bug of printing prefix for 64-bit architecture
13
+ from Aki Nakao
14
+
15
+ 0.01 2007/11/16
16
+ - the first version
data/README ADDED
@@ -0,0 +1,179 @@
1
+ README for Ruby wrapper of Net::Patricia
2
+ ---------------------------------------
3
+
4
+ rPatricia - A ruby wrapper of Net::Patricia
5
+
6
+ DESCRIPTION
7
+ -----------
8
+
9
+ This is a ruby wrapper of Net::Patricia, which has been developed by
10
+ Dave Plonka. The original Net::Patricia and its C API are available
11
+ from:
12
+ http://net.doit.wisc.edu/~plonka/Net-Patricia/
13
+
14
+ Net::Patricia is a module for fast IP address/prefix lookups.
15
+ I have modified some interfaces for the Ruby wrapper version.
16
+
17
+ NO WARANTY
18
+ ----------
19
+ THE PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
20
+ WITHOUT ANY WARRANTY. IT IS PROVIDED "AS IS" WITHOUT WARRANTY OF
21
+ ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED
22
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23
+ PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
24
+ PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
25
+ DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR
26
+ OR CORRECTION.
27
+
28
+ INSTALLATION
29
+ ------------
30
+
31
+ This package extracts, builds, installs in the usual fashion, i.e.:
32
+
33
+ $ tar xvfz rpatricia.tar.gz
34
+ $ cd rpatricia
35
+ $ ruby extconf.rb
36
+ $ make
37
+ $ ruby test.rb
38
+ # make install
39
+
40
+ SYNOPSIS
41
+ --------
42
+
43
+ require 'rpatricia'
44
+ pt = Patricia.new
45
+ pt.add("192.168.1.0/24")
46
+ pt.add("127.0.0.0/8", "user_data")
47
+ node = pt.search_best("127.0.0.1")
48
+ puts node.data
49
+ puts node.prefix
50
+ puts node.network
51
+ puts node.prefixlen
52
+ pt.remove("127.0.0.0/8")
53
+ puts pt.num_nodes
54
+ pt.show_nodes
55
+ pt.clear
56
+
57
+ METHODS
58
+ -------
59
+ new:
60
+
61
+ pt = Patricia.new
62
+
63
+ This is the class' constructor - it returns a Patricia object upon
64
+ success or nil on failure. For now, the constructor takes no
65
+ arguments, and defaults to creating a tree which uses AF_INET IPv4
66
+ address and mask values as keys.
67
+
68
+ The Patricia object will be destroyed automatically when there are
69
+ no longer any references to it.
70
+
71
+ add:
72
+ pt.add(key_string[,user_data])
73
+
74
+ The first argument, key_string, is a network or subnet
75
+ specification in canonical form, e.g. ``10.0.0.0/8'', where the
76
+ number after the slash represents the number of bits in the
77
+ netmask. If no mask width is specified, the longest possible mask
78
+ is assumed, i.e. 32 bits for AF_INET addresses.
79
+
80
+ The second argument, user_data, is optional. If supplied, it
81
+ should be a STRING object specifying the user data that will be
82
+ stored in the Patricia Trie node. Subsequently, this value will
83
+ be returned by the match methods described below to indicate a
84
+ successful search.
85
+
86
+ If no second argument is passed, the key_string will be stored as
87
+ the user data and therfore will likewise be returned by the match
88
+ functions.
89
+
90
+ On success, this method returns the object of the Patricia Trie
91
+ node.
92
+
93
+ add_node: An alias of add.
94
+
95
+ search_best:
96
+
97
+ pt.search_best(key_string);
98
+
99
+ This method searches the Patricia Trie to find a matching node,
100
+ according to normal subnetting rules for the address and mask
101
+ specified.
102
+
103
+ The key_string argument is a network or subnet specification in
104
+ canonical form, e.g. ``10.0.0.0/8'', where the number after the
105
+ slash represents the number of bits in the netmask. If no mask
106
+ width value is specified, the longest mask is assumed, i.e. 32
107
+ bits for AF_INET addresses.
108
+
109
+ If a matching node is found in the Patricia Trie, this method
110
+ returns the object of the node. This method returns nil on
111
+ failure.
112
+
113
+ match_best: An alias of search_best.
114
+
115
+ search_exact:
116
+
117
+ pt.search_exact(key_string);
118
+
119
+ This method searches the Patricia Trie to find a matching
120
+ node. Its semantics are exactly the same as those described for
121
+ search_best except that the key must match a node exactly. I.e.,
122
+ it is not sufficient that the address and mask specified merely
123
+ falls within the subnet specified by a particular node.
124
+
125
+ match_exact: An alias of search_exact.
126
+
127
+ remove:
128
+
129
+ pt.remove(key_string);
130
+
131
+ This method removes the node which exactly matches the the address
132
+ and mask specified from the Patricia Trie.
133
+
134
+ If the matching node is found in the Patricia Trie, it is removed,
135
+ and this method returns the true. This method returns nil on
136
+ failure.
137
+
138
+ remove_node: An alias of remove
139
+
140
+ num_nodes:
141
+
142
+ pt.num_nodes
143
+
144
+ This method returns the number of nodes in the Patricia Trie.
145
+
146
+ show_nodes:
147
+
148
+ pt.print_nodes
149
+
150
+ This method prints all the nodes in the Patricia Trie.
151
+
152
+ data:
153
+
154
+ node.data
155
+
156
+ This method returns the user data of the Patricia Trie node.
157
+
158
+ network:
159
+
160
+ node.network
161
+
162
+ This method returns the network of the Patricia Trie node.
163
+
164
+ prefix:
165
+
166
+ node.prefix
167
+
168
+ This method returns the prefix of the Patricia Trie node.
169
+
170
+ prefixlen:
171
+
172
+ node.prefixlen
173
+
174
+ This method returns the prefix length of the Patricia Trie
175
+ node.
176
+
177
+ AUTHOR
178
+ ------
179
+ Tatsuya Mori <mori.tatsuya@gmail.com>
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ 1. figure out bugs
2
+ 2. extension for AF_INET6
data/copyright ADDED
@@ -0,0 +1,34 @@
1
+ Copyright (c) 1997, 1998, 1999
2
+
3
+
4
+ The Regents of the University of Michigan ("The Regents") and Merit Network,
5
+ Inc. All rights reserved.
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+ 1. Redistributions of source code must retain the above
9
+ copyright notice, this list of conditions and the
10
+ following disclaimer.
11
+ 2. Redistributions in binary form must reproduce the above
12
+ copyright notice, this list of conditions and the
13
+ following disclaimer in the documentation and/or other
14
+ materials provided with the distribution.
15
+ 3. All advertising materials mentioning features or use of
16
+ this software must display the following acknowledgement:
17
+ This product includes software developed by the University of Michigan, Merit
18
+ Network, Inc., and their contributors.
19
+ 4. Neither the name of the University, Merit Network, nor the
20
+ names of their contributors may be used to endorse or
21
+ promote products derived from this software without
22
+ specific prior written permission.
23
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY
24
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
27
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+
34
+
data/credits.txt ADDED
@@ -0,0 +1,73 @@
1
+
2
+ [newtool.gif]
3
+
4
+ MRT Credits
5
+
6
+ The Multi-Threaded Routing Toolkit
7
+ _________________________________________________________________
8
+
9
+ MRT was developed by [1]Merit Network, Inc., under National Science
10
+ Foundation grant NCR-9318902, "Experimentation with Routing Technology
11
+ to be Used for Inter-Domain Routing in the Internet."
12
+
13
+ Current MRT Staff
14
+
15
+ * [2]Craig Labovitz <labovit@merit.edu>
16
+ * [3]Makaki Hirabaru <masaki@merit.edu>
17
+ * [4]Farnam Jahanian <farnam@eecs.umich.edu>
18
+ * Susan Hares <skh@merit.edu>
19
+ * Susan R. Harris <srh@merit.edu>
20
+ * Nathan Binkert <binkertn@eecs.umich.edu>
21
+ * Gerald Winters <gerald@merit.edu>
22
+
23
+ Project Alumni
24
+
25
+ * [5]Marc Unangst <mju@merit.edu>
26
+ * John Scudder <jgs@ieng.com>
27
+
28
+ The BGP4+ extension was originally written by Francis Dupont
29
+ <Francis.Dupont@inria.fr>.
30
+
31
+ The public domain Struct C-library of linked list, hash table and
32
+ memory allocation routines was developed by Jonathan Dekock
33
+ <dekock@cadence.com>.
34
+
35
+ Susan Rebecca Harris <srh@merit.edu> provided help with the
36
+ documentation.
37
+ David Ward <dward@netstar.com> provided bug fixes and helpful
38
+ suggestions.
39
+ Some sections of code and architecture ideas were taken from the GateD
40
+ routing daemon.
41
+
42
+ The first port to Linux with IPv6 was done by Pedro Roque
43
+ <roque@di.fc.ul.pt>. Some interface routines to the Linux kernel were
44
+ originally written by him.
45
+
46
+ Alexey Kuznetsov made enhancements to 1.4.3a and fixed the Linux
47
+ kernel intarface. Linux's netlink interface was written, referring to
48
+ his code "iproute2".
49
+
50
+ We would also like to thank our other colleagues in Japan, Portugal,
51
+ the Netherlands, the UK, and the US for their many contributions to
52
+ the MRT development effort.
53
+ _________________________________________________________________
54
+
55
+ Cisco is a registered trademark of Cisco Systems Inc.
56
+ _________________________________________________________________
57
+
58
+ Merit Network 4251 Plymouth Road Suite C Ann Arbor, MI 48105-2785
59
+ 734-764-9430
60
+ info@merit.edu
61
+ _________________________________________________________________
62
+
63
+ � 1999 Merit Network, Inc.
64
+ [6]www@merit.edu
65
+
66
+ References
67
+
68
+ 1. http://www.merit.edu/
69
+ 2. http://www.merit.edu/~labovit
70
+ 3. http://www.merit.edu/~masaki
71
+ 4. http://www.eecs.umich.edu/~farnam
72
+ 5. http://www.contrib.andrew.cmu.edu/~mju/
73
+ 6. mailto:www@merit.edu
data/extconf.rb ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require "mkmf"
3
+
4
+ create_makefile("rpatricia")
5
+
data/patricia.c ADDED
@@ -0,0 +1,1038 @@
1
+ /*
2
+ * $Id: patricia.c,v 1.7 2005/12/07 20:46:41 dplonka Exp $
3
+ * Dave Plonka <plonka@doit.wisc.edu>
4
+ *
5
+ * This product includes software developed by the University of Michigan,
6
+ * Merit Network, Inc., and their contributors.
7
+ *
8
+ * This file had been called "radix.c" in the MRT sources.
9
+ *
10
+ * I renamed it to "patricia.c" since it's not an implementation of a general
11
+ * radix trie. Also I pulled in various requirements from "prefix.c" and
12
+ * "demo.c" so that it could be used as a standalone API.
13
+ */
14
+
15
+ static char copyright[] =
16
+ "This product includes software developed by the University of Michigan, Merit"
17
+ "Network, Inc., and their contributors.";
18
+
19
+ #include <assert.h> /* assert */
20
+ #include <ctype.h> /* isdigit */
21
+ #include <errno.h> /* errno */
22
+ #include <math.h> /* sin */
23
+ #include <stddef.h> /* NULL */
24
+ #include <stdio.h> /* sprintf, fprintf, stderr */
25
+ #include <stdlib.h> /* free, atol, calloc */
26
+ #include <string.h> /* memcpy, strchr, strlen */
27
+ #include <sys/types.h> /* BSD: for inet_addr */
28
+ #include <sys/socket.h> /* BSD, Linux: for inet_addr */
29
+ #include <netinet/in.h> /* BSD, Linux: for inet_addr */
30
+ #include <arpa/inet.h> /* BSD, Linux, Solaris: for inet_addr */
31
+
32
+ #include "patricia.h"
33
+
34
+ #define Delete free
35
+
36
+ /* { from prefix.c */
37
+
38
+ /* prefix_tochar
39
+ * convert prefix information to bytes
40
+ */
41
+ u_char *
42
+ prefix_tochar (prefix_t * prefix)
43
+ {
44
+ if (prefix == NULL)
45
+ return (NULL);
46
+
47
+ return ((u_char *) & prefix->add.sin);
48
+ }
49
+
50
+ int
51
+ comp_with_mask (void *addr, void *dest, u_int mask)
52
+ {
53
+
54
+ if ( /* mask/8 == 0 || */ memcmp (addr, dest, mask / 8) == 0) {
55
+ int n = mask / 8;
56
+ int m = ((-1) << (8 - (mask % 8)));
57
+
58
+ if (mask % 8 == 0 || (((u_char *)addr)[n] & m) == (((u_char *)dest)[n] & m))
59
+ return (1);
60
+ }
61
+ return (0);
62
+ }
63
+
64
+ /* inet_pton substitute implementation
65
+ * Uses inet_addr to convert an IP address in dotted decimal notation into
66
+ * unsigned long and copies the result to dst.
67
+ * Only supports AF_INET. Follows standard error return conventions of
68
+ * inet_pton.
69
+ */
70
+ int
71
+ inet_pton (int af, const char *src, void *dst)
72
+ {
73
+ u_long result;
74
+
75
+ if (af == AF_INET) {
76
+ result = inet_addr(src);
77
+ if (result == -1)
78
+ return 0;
79
+ else {
80
+ memcpy (dst, &result, 4);
81
+ return 1;
82
+ }
83
+ }
84
+ #ifdef NT
85
+ #ifdef HAVE_IPV6
86
+ else if (af == AF_INET6) {
87
+ struct in6_addr Address;
88
+ return (inet6_addr(src, &Address));
89
+ }
90
+ #endif /* HAVE_IPV6 */
91
+ #endif /* NT */
92
+ #ifndef NT
93
+ else {
94
+
95
+ errno = EAFNOSUPPORT;
96
+ return -1;
97
+ }
98
+ #endif /* NT */
99
+ }
100
+
101
+ /* this allows imcomplete prefix */
102
+ int
103
+ my_inet_pton (int af, const char *src, void *dst)
104
+ {
105
+ if (af == AF_INET) {
106
+ int i, c, val;
107
+ u_char xp[4] = {0, 0, 0, 0};
108
+
109
+ for (i = 0; ; i++) {
110
+ c = *src++;
111
+ if (!isdigit (c))
112
+ return (-1);
113
+ val = 0;
114
+ do {
115
+ val = val * 10 + c - '0';
116
+ if (val > 255)
117
+ return (0);
118
+ c = *src++;
119
+ } while (c && isdigit (c));
120
+ xp[i] = val;
121
+ if (c == '\0')
122
+ break;
123
+ if (c != '.')
124
+ return (0);
125
+ if (i >= 3)
126
+ return (0);
127
+ }
128
+ memcpy (dst, xp, 4);
129
+ return (1);
130
+ #ifdef HAVE_IPV6
131
+ } else if (af == AF_INET6) {
132
+ return (inet_pton (af, src, dst));
133
+ #endif /* HAVE_IPV6 */
134
+ } else {
135
+ #ifndef NT
136
+ errno = EAFNOSUPPORT;
137
+ #endif /* NT */
138
+ return -1;
139
+ }
140
+ }
141
+
142
+ /*
143
+ * convert prefix information to ascii string with length
144
+ * thread safe and (almost) re-entrant implementation
145
+ */
146
+ char *
147
+ prefix_toa2x (prefix_t *prefix, char *buff, int with_len)
148
+ {
149
+ if (prefix == NULL)
150
+ return ("(Null)");
151
+ assert (prefix->ref_count >= 0);
152
+ if (buff == NULL) {
153
+
154
+ struct buffer {
155
+ char buffs[16][48+5];
156
+ u_int i;
157
+ } *buffp;
158
+
159
+ # if 0
160
+ THREAD_SPECIFIC_DATA (struct buffer, buffp, 1);
161
+ # else
162
+ { /* for scope only */
163
+ static struct buffer local_buff;
164
+ buffp = &local_buff;
165
+ }
166
+ # endif
167
+ if (buffp == NULL) {
168
+ /* XXX should we report an error? */
169
+ return (NULL);
170
+ }
171
+
172
+ buff = buffp->buffs[buffp->i++%16];
173
+ }
174
+ if (prefix->family == AF_INET) {
175
+ u_char *a;
176
+ assert (prefix->bitlen <= 32);
177
+ a = prefix_touchar (prefix);
178
+ if (with_len) {
179
+ sprintf (buff, "%d.%d.%d.%d/%d", a[0], a[1], a[2], a[3],
180
+ prefix->bitlen);
181
+ }
182
+ else {
183
+ sprintf (buff, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
184
+ }
185
+ return (buff);
186
+ }
187
+ #ifdef HAVE_IPV6
188
+ else if (prefix->family == AF_INET6) {
189
+ char *r;
190
+ r = (char *) inet_ntop (AF_INET6, &prefix->add.sin6, buff, 48 /* a guess value */ );
191
+ if (r && with_len) {
192
+ assert (prefix->bitlen <= 128);
193
+ sprintf (buff + strlen (buff), "/%d", prefix->bitlen);
194
+ }
195
+ return (buff);
196
+ }
197
+ #endif /* HAVE_IPV6 */
198
+ else
199
+ return (NULL);
200
+ }
201
+
202
+ /* prefix_toa2
203
+ * convert prefix information to ascii string
204
+ */
205
+ char *
206
+ prefix_toa2 (prefix_t *prefix, char *buff)
207
+ {
208
+ return (prefix_toa2x (prefix, buff, 0));
209
+ }
210
+
211
+ /* prefix_toa
212
+ */
213
+ char *
214
+ prefix_toa (prefix_t * prefix)
215
+ {
216
+ return (prefix_toa2 (prefix, (char *) NULL));
217
+ }
218
+
219
+ prefix_t *
220
+ New_Prefix2 (int family, void *dest, int bitlen, prefix_t *prefix)
221
+ {
222
+ int dynamic_allocated = 0;
223
+ int default_bitlen = 32;
224
+
225
+ #ifdef HAVE_IPV6
226
+ if (family == AF_INET6) {
227
+ default_bitlen = 128;
228
+ if (prefix == NULL) {
229
+ prefix = calloc(1, sizeof (prefix6_t));
230
+ dynamic_allocated++;
231
+ }
232
+ memcpy (&prefix->add.sin6, dest, 16);
233
+ }
234
+ else
235
+ #endif /* HAVE_IPV6 */
236
+ if (family == AF_INET) {
237
+ if (prefix == NULL) {
238
+ #ifndef NT
239
+ prefix = calloc(1, sizeof (prefix4_t));
240
+ #else
241
+ //for some reason, compiler is getting
242
+ //prefix4_t size incorrect on NT
243
+ prefix = calloc(1, sizeof (prefix_t));
244
+ #endif /* NT */
245
+
246
+ dynamic_allocated++;
247
+ }
248
+ memcpy (&prefix->add.sin, dest, 4);
249
+ }
250
+ else {
251
+ return (NULL);
252
+ }
253
+
254
+ prefix->bitlen = (bitlen >= 0)? bitlen: default_bitlen;
255
+ prefix->family = family;
256
+ prefix->ref_count = 0;
257
+ if (dynamic_allocated) {
258
+ prefix->ref_count++;
259
+ }
260
+ /* fprintf(stderr, "[C %s, %d]\n", prefix_toa (prefix), prefix->ref_count); */
261
+ return (prefix);
262
+ }
263
+
264
+ prefix_t *
265
+ New_Prefix (int family, void *dest, int bitlen)
266
+ {
267
+ return (New_Prefix2 (family, dest, bitlen, NULL));
268
+ }
269
+
270
+ /* ascii2prefix
271
+ */
272
+ prefix_t *
273
+ ascii2prefix (int family, char *string)
274
+ {
275
+ u_long bitlen, maxbitlen = 0;
276
+ char *cp;
277
+ struct in_addr sin;
278
+ #ifdef HAVE_IPV6
279
+ struct in6_addr sin6;
280
+ #endif /* HAVE_IPV6 */
281
+ int result;
282
+ char save[MAXLINE];
283
+
284
+ if (string == NULL)
285
+ return (NULL);
286
+
287
+ /* easy way to handle both families */
288
+ if (family == 0) {
289
+ family = AF_INET;
290
+ #ifdef HAVE_IPV6
291
+ if (strchr (string, ':')) family = AF_INET6;
292
+ #endif /* HAVE_IPV6 */
293
+ }
294
+
295
+ if (family == AF_INET) {
296
+ maxbitlen = 32;
297
+ }
298
+ #ifdef HAVE_IPV6
299
+ else if (family == AF_INET6) {
300
+ maxbitlen = 128;
301
+ }
302
+ #endif /* HAVE_IPV6 */
303
+
304
+ if ((cp = strchr (string, '/')) != NULL) {
305
+ bitlen = atol (cp + 1);
306
+ /* *cp = '\0'; */
307
+ /* copy the string to save. Avoid destroying the string */
308
+ assert (cp - string < MAXLINE);
309
+ memcpy (save, string, cp - string);
310
+ save[cp - string] = '\0';
311
+ string = save;
312
+ if (bitlen < 0 || bitlen > maxbitlen)
313
+ bitlen = maxbitlen;
314
+ }
315
+ else {
316
+ bitlen = maxbitlen;
317
+ }
318
+
319
+ if (family == AF_INET) {
320
+ if ((result = my_inet_pton (AF_INET, string, &sin)) <= 0)
321
+ return (NULL);
322
+ return (New_Prefix (AF_INET, &sin, bitlen));
323
+ }
324
+
325
+ #ifdef HAVE_IPV6
326
+ else if (family == AF_INET6) {
327
+ // Get rid of this with next IPv6 upgrade
328
+ #if defined(NT) && !defined(HAVE_INET_NTOP)
329
+ inet6_addr(string, &sin6);
330
+ return (New_Prefix (AF_INET6, &sin6, bitlen));
331
+ #else
332
+ if ((result = inet_pton (AF_INET6, string, &sin6)) <= 0)
333
+ return (NULL);
334
+ #endif /* NT */
335
+ return (New_Prefix (AF_INET6, &sin6, bitlen));
336
+ }
337
+ #endif /* HAVE_IPV6 */
338
+ else
339
+ return (NULL);
340
+ }
341
+
342
+ prefix_t *
343
+ Ref_Prefix (prefix_t * prefix)
344
+ {
345
+ if (prefix == NULL)
346
+ return (NULL);
347
+ if (prefix->ref_count == 0) {
348
+ /* make a copy in case of a static prefix */
349
+ return (New_Prefix2 (prefix->family, &prefix->add, prefix->bitlen, NULL));
350
+ }
351
+ prefix->ref_count++;
352
+ /* fprintf(stderr, "[A %s, %d]\n", prefix_toa (prefix), prefix->ref_count); */
353
+ return (prefix);
354
+ }
355
+
356
+ void
357
+ Deref_Prefix (prefix_t * prefix)
358
+ {
359
+ if (prefix == NULL)
360
+ return;
361
+ /* for secure programming, raise an assert. no static prefix can call this */
362
+ assert (prefix->ref_count > 0);
363
+
364
+ prefix->ref_count--;
365
+ assert (prefix->ref_count >= 0);
366
+ if (prefix->ref_count <= 0) {
367
+ Delete (prefix);
368
+ return;
369
+ }
370
+ }
371
+
372
+ /* } */
373
+
374
+ /* #define PATRICIA_DEBUG 1 */
375
+
376
+ static int num_active_patricia = 0;
377
+
378
+ /* these routines support continuous mask only */
379
+
380
+ patricia_tree_t *
381
+ New_Patricia (int maxbits)
382
+ {
383
+ patricia_tree_t *patricia = calloc(1, sizeof *patricia);
384
+
385
+ patricia->maxbits = maxbits;
386
+ patricia->head = NULL;
387
+ patricia->num_active_node = 0;
388
+ assert (maxbits <= PATRICIA_MAXBITS); /* XXX */
389
+ num_active_patricia++;
390
+ return (patricia);
391
+ }
392
+
393
+
394
+ /*
395
+ * if func is supplied, it will be called as func(node->data)
396
+ * before deleting the node
397
+ */
398
+
399
+ void
400
+ Clear_Patricia (patricia_tree_t *patricia, void_fn_t func)
401
+ {
402
+ assert (patricia);
403
+ if (patricia->head) {
404
+
405
+ patricia_node_t *Xstack[PATRICIA_MAXBITS+1];
406
+ patricia_node_t **Xsp = Xstack;
407
+ patricia_node_t *Xrn = patricia->head;
408
+
409
+ while (Xrn) {
410
+ patricia_node_t *l = Xrn->l;
411
+ patricia_node_t *r = Xrn->r;
412
+
413
+ if (Xrn->prefix) {
414
+ Deref_Prefix (Xrn->prefix);
415
+ if (Xrn->data && func)
416
+ func (Xrn->data);
417
+ }
418
+ else {
419
+ assert (Xrn->data == NULL);
420
+ }
421
+ Delete (Xrn);
422
+ patricia->num_active_node--;
423
+
424
+ if (l) {
425
+ if (r) {
426
+ *Xsp++ = r;
427
+ }
428
+ Xrn = l;
429
+ } else if (r) {
430
+ Xrn = r;
431
+ } else if (Xsp != Xstack) {
432
+ Xrn = *(--Xsp);
433
+ } else {
434
+ Xrn = (patricia_node_t *) 0;
435
+ }
436
+ }
437
+ }
438
+ assert (patricia->num_active_node == 0);
439
+ /* Delete (patricia); */
440
+ }
441
+
442
+
443
+ void
444
+ Destroy_Patricia (patricia_tree_t *patricia, void_fn_t func)
445
+ {
446
+ Clear_Patricia (patricia, func);
447
+ Delete (patricia);
448
+ num_active_patricia--;
449
+ }
450
+
451
+
452
+ /*
453
+ * if func is supplied, it will be called as func(node->prefix, node->data)
454
+ */
455
+
456
+ void
457
+ patricia_process (patricia_tree_t *patricia, void_fn_t func)
458
+ {
459
+ patricia_node_t *node;
460
+ assert (func);
461
+
462
+ PATRICIA_WALK (patricia->head, node) {
463
+ func (node->prefix, node->data);
464
+ } PATRICIA_WALK_END;
465
+ }
466
+
467
+ size_t
468
+ patricia_walk_inorder(patricia_node_t *node, void_fn_t func)
469
+ {
470
+ size_t n = 0;
471
+ assert(func);
472
+
473
+ if (node->l) {
474
+ n += patricia_walk_inorder(node->l, func);
475
+ }
476
+
477
+ if (node->prefix) {
478
+ func(node->prefix, node->data);
479
+ n++;
480
+ }
481
+
482
+ if (node->r) {
483
+ n += patricia_walk_inorder(node->r, func);
484
+ }
485
+
486
+ return n;
487
+ }
488
+
489
+
490
+ patricia_node_t *
491
+ patricia_search_exact (patricia_tree_t *patricia, prefix_t *prefix)
492
+ {
493
+ patricia_node_t *node;
494
+ u_char *addr;
495
+ u_int bitlen;
496
+
497
+ assert (patricia);
498
+ assert (prefix);
499
+ assert (prefix->bitlen <= patricia->maxbits);
500
+
501
+ if (patricia->head == NULL)
502
+ return (NULL);
503
+
504
+ node = patricia->head;
505
+ addr = prefix_touchar (prefix);
506
+ bitlen = prefix->bitlen;
507
+
508
+ while (node->bit < bitlen) {
509
+
510
+ if (BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
511
+ #ifdef PATRICIA_DEBUG
512
+ if (node->prefix)
513
+ fprintf (stderr, "patricia_search_exact: take right %s/%d\n",
514
+ prefix_toa (node->prefix), node->prefix->bitlen);
515
+ else
516
+ fprintf (stderr, "patricia_search_exact: take right at %d\n",
517
+ node->bit);
518
+ #endif /* PATRICIA_DEBUG */
519
+ node = node->r;
520
+ }
521
+ else {
522
+ #ifdef PATRICIA_DEBUG
523
+ if (node->prefix)
524
+ fprintf (stderr, "patricia_search_exact: take left %s/%d\n",
525
+ prefix_toa (node->prefix), node->prefix->bitlen);
526
+ else
527
+ fprintf (stderr, "patricia_search_exact: take left at %d\n",
528
+ node->bit);
529
+ #endif /* PATRICIA_DEBUG */
530
+ node = node->l;
531
+ }
532
+
533
+ if (node == NULL)
534
+ return (NULL);
535
+ }
536
+
537
+ #ifdef PATRICIA_DEBUG
538
+ if (node->prefix)
539
+ fprintf (stderr, "patricia_search_exact: stop at %s/%d\n",
540
+ prefix_toa (node->prefix), node->prefix->bitlen);
541
+ else
542
+ fprintf (stderr, "patricia_search_exact: stop at %d\n", node->bit);
543
+ #endif /* PATRICIA_DEBUG */
544
+ if (node->bit > bitlen || node->prefix == NULL)
545
+ return (NULL);
546
+ assert (node->bit == bitlen);
547
+ assert (node->bit == node->prefix->bitlen);
548
+ if (comp_with_mask (prefix_tochar (node->prefix), prefix_tochar (prefix),
549
+ bitlen)) {
550
+ #ifdef PATRICIA_DEBUG
551
+ fprintf (stderr, "patricia_search_exact: found %s/%d\n",
552
+ prefix_toa (node->prefix), node->prefix->bitlen);
553
+ #endif /* PATRICIA_DEBUG */
554
+ return (node);
555
+ }
556
+ return (NULL);
557
+ }
558
+
559
+
560
+ /* if inclusive != 0, "best" may be the given prefix itself */
561
+ patricia_node_t *
562
+ patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, int inclusive)
563
+ {
564
+ patricia_node_t *node;
565
+ patricia_node_t *stack[PATRICIA_MAXBITS + 1];
566
+ u_char *addr;
567
+ u_int bitlen;
568
+ int cnt = 0;
569
+
570
+ assert (patricia);
571
+ assert (prefix);
572
+ assert (prefix->bitlen <= patricia->maxbits);
573
+
574
+ if (patricia->head == NULL)
575
+ return (NULL);
576
+
577
+ node = patricia->head;
578
+ addr = prefix_touchar (prefix);
579
+ bitlen = prefix->bitlen;
580
+
581
+ while (node->bit < bitlen) {
582
+
583
+ if (node->prefix) {
584
+ #ifdef PATRICIA_DEBUG
585
+ fprintf (stderr, "patricia_search_best: push %s/%d\n",
586
+ prefix_toa (node->prefix), node->prefix->bitlen);
587
+ #endif /* PATRICIA_DEBUG */
588
+ stack[cnt++] = node;
589
+ }
590
+
591
+ if (BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
592
+ #ifdef PATRICIA_DEBUG
593
+ if (node->prefix)
594
+ fprintf (stderr, "patricia_search_best: take right %s/%d\n",
595
+ prefix_toa (node->prefix), node->prefix->bitlen);
596
+ else
597
+ fprintf (stderr, "patricia_search_best: take right at %d\n",
598
+ node->bit);
599
+ #endif /* PATRICIA_DEBUG */
600
+ node = node->r;
601
+ }
602
+ else {
603
+ #ifdef PATRICIA_DEBUG
604
+ if (node->prefix)
605
+ fprintf (stderr, "patricia_search_best: take left %s/%d\n",
606
+ prefix_toa (node->prefix), node->prefix->bitlen);
607
+ else
608
+ fprintf (stderr, "patricia_search_best: take left at %d\n",
609
+ node->bit);
610
+ #endif /* PATRICIA_DEBUG */
611
+ node = node->l;
612
+ }
613
+
614
+ if (node == NULL)
615
+ break;
616
+ }
617
+
618
+ if (inclusive && node && node->prefix)
619
+ stack[cnt++] = node;
620
+
621
+ #ifdef PATRICIA_DEBUG
622
+ if (node == NULL)
623
+ fprintf (stderr, "patricia_search_best: stop at null\n");
624
+ else if (node->prefix)
625
+ fprintf (stderr, "patricia_search_best: stop at %s/%d\n",
626
+ prefix_toa (node->prefix), node->prefix->bitlen);
627
+ else
628
+ fprintf (stderr, "patricia_search_best: stop at %d\n", node->bit);
629
+ #endif /* PATRICIA_DEBUG */
630
+
631
+ if (cnt <= 0)
632
+ return (NULL);
633
+
634
+ while (--cnt >= 0) {
635
+ node = stack[cnt];
636
+ #ifdef PATRICIA_DEBUG
637
+ fprintf (stderr, "patricia_search_best: pop %s/%d\n",
638
+ prefix_toa (node->prefix), node->prefix->bitlen);
639
+ #endif /* PATRICIA_DEBUG */
640
+ if (comp_with_mask (prefix_tochar (node->prefix),
641
+ prefix_tochar (prefix),
642
+ node->prefix->bitlen)) {
643
+ #ifdef PATRICIA_DEBUG
644
+ fprintf (stderr, "patricia_search_best: found %s/%d\n",
645
+ prefix_toa (node->prefix), node->prefix->bitlen);
646
+ #endif /* PATRICIA_DEBUG */
647
+ return (node);
648
+ }
649
+ }
650
+ return (NULL);
651
+ }
652
+
653
+
654
+ patricia_node_t *
655
+ patricia_search_best (patricia_tree_t *patricia, prefix_t *prefix)
656
+ {
657
+ return (patricia_search_best2 (patricia, prefix, 1));
658
+ }
659
+
660
+
661
+ patricia_node_t *
662
+ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
663
+ {
664
+ patricia_node_t *node, *new_node, *parent, *glue;
665
+ u_char *addr, *test_addr;
666
+ u_int bitlen, check_bit, differ_bit;
667
+ int i, j, r;
668
+
669
+ assert (patricia);
670
+ assert (prefix);
671
+ assert (prefix->bitlen <= patricia->maxbits);
672
+
673
+ if (patricia->head == NULL) {
674
+ node = calloc(1, sizeof *node);
675
+ node->bit = prefix->bitlen;
676
+ node->prefix = Ref_Prefix (prefix);
677
+ node->parent = NULL;
678
+ node->l = node->r = NULL;
679
+ node->data = NULL;
680
+ patricia->head = node;
681
+ #ifdef PATRICIA_DEBUG
682
+ fprintf (stderr, "patricia_lookup: new_node #0 %s/%d (head)\n",
683
+ prefix_toa (prefix), prefix->bitlen);
684
+ #endif /* PATRICIA_DEBUG */
685
+ patricia->num_active_node++;
686
+ return (node);
687
+ }
688
+
689
+ addr = prefix_touchar (prefix);
690
+ bitlen = prefix->bitlen;
691
+ node = patricia->head;
692
+
693
+ while (node->bit < bitlen || node->prefix == NULL) {
694
+
695
+ if (node->bit < patricia->maxbits &&
696
+ BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
697
+ if (node->r == NULL)
698
+ break;
699
+ #ifdef PATRICIA_DEBUG
700
+ if (node->prefix)
701
+ fprintf (stderr, "patricia_lookup: take right %s/%d\n",
702
+ prefix_toa (node->prefix), node->prefix->bitlen);
703
+ else
704
+ fprintf (stderr, "patricia_lookup: take right at %d\n", node->bit);
705
+ #endif /* PATRICIA_DEBUG */
706
+ node = node->r;
707
+ }
708
+ else {
709
+ if (node->l == NULL)
710
+ break;
711
+ #ifdef PATRICIA_DEBUG
712
+ if (node->prefix)
713
+ fprintf (stderr, "patricia_lookup: take left %s/%d\n",
714
+ prefix_toa (node->prefix), node->prefix->bitlen);
715
+ else
716
+ fprintf (stderr, "patricia_lookup: take left at %d\n", node->bit);
717
+ #endif /* PATRICIA_DEBUG */
718
+ node = node->l;
719
+ }
720
+
721
+ assert (node);
722
+ }
723
+
724
+ assert (node->prefix);
725
+ #ifdef PATRICIA_DEBUG
726
+ fprintf (stderr, "patricia_lookup: stop at %s/%d\n",
727
+ prefix_toa (node->prefix), node->prefix->bitlen);
728
+ #endif /* PATRICIA_DEBUG */
729
+
730
+ test_addr = prefix_touchar (node->prefix);
731
+ /* find the first bit different */
732
+ check_bit = (node->bit < bitlen)? node->bit: bitlen;
733
+ differ_bit = 0;
734
+ for (i = 0; i*8 < check_bit; i++) {
735
+ if ((r = (addr[i] ^ test_addr[i])) == 0) {
736
+ differ_bit = (i + 1) * 8;
737
+ continue;
738
+ }
739
+ /* I know the better way, but for now */
740
+ for (j = 0; j < 8; j++) {
741
+ if (BIT_TEST (r, (0x80 >> j)))
742
+ break;
743
+ }
744
+ /* must be found */
745
+ assert (j < 8);
746
+ differ_bit = i * 8 + j;
747
+ break;
748
+ }
749
+ if (differ_bit > check_bit)
750
+ differ_bit = check_bit;
751
+ #ifdef PATRICIA_DEBUG
752
+ fprintf (stderr, "patricia_lookup: differ_bit %d\n", differ_bit);
753
+ #endif /* PATRICIA_DEBUG */
754
+
755
+ parent = node->parent;
756
+ while (parent && parent->bit >= differ_bit) {
757
+ node = parent;
758
+ parent = node->parent;
759
+ #ifdef PATRICIA_DEBUG
760
+ if (node->prefix)
761
+ fprintf (stderr, "patricia_lookup: up to %s/%d\n",
762
+ prefix_toa (node->prefix), node->prefix->bitlen);
763
+ else
764
+ fprintf (stderr, "patricia_lookup: up to %d\n", node->bit);
765
+ #endif /* PATRICIA_DEBUG */
766
+ }
767
+
768
+ if (differ_bit == bitlen && node->bit == bitlen) {
769
+ if (node->prefix) {
770
+ #ifdef PATRICIA_DEBUG
771
+ fprintf (stderr, "patricia_lookup: found %s/%d\n",
772
+ prefix_toa (node->prefix), node->prefix->bitlen);
773
+ #endif /* PATRICIA_DEBUG */
774
+ return (node);
775
+ }
776
+ node->prefix = Ref_Prefix (prefix);
777
+ #ifdef PATRICIA_DEBUG
778
+ fprintf (stderr, "patricia_lookup: new node #1 %s/%d (glue mod)\n",
779
+ prefix_toa (prefix), prefix->bitlen);
780
+ #endif /* PATRICIA_DEBUG */
781
+ assert (node->data == NULL);
782
+ return (node);
783
+ }
784
+
785
+ new_node = calloc(1, sizeof *new_node);
786
+ new_node->bit = prefix->bitlen;
787
+ new_node->prefix = Ref_Prefix (prefix);
788
+ new_node->parent = NULL;
789
+ new_node->l = new_node->r = NULL;
790
+ new_node->data = NULL;
791
+ patricia->num_active_node++;
792
+
793
+ if (node->bit == differ_bit) {
794
+ new_node->parent = node;
795
+ if (node->bit < patricia->maxbits &&
796
+ BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
797
+ assert (node->r == NULL);
798
+ node->r = new_node;
799
+ }
800
+ else {
801
+ assert (node->l == NULL);
802
+ node->l = new_node;
803
+ }
804
+ #ifdef PATRICIA_DEBUG
805
+ fprintf (stderr, "patricia_lookup: new_node #2 %s/%d (child)\n",
806
+ prefix_toa (prefix), prefix->bitlen);
807
+ #endif /* PATRICIA_DEBUG */
808
+ return (new_node);
809
+ }
810
+
811
+ if (bitlen == differ_bit) {
812
+ if (bitlen < patricia->maxbits &&
813
+ BIT_TEST (test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07))) {
814
+ new_node->r = node;
815
+ }
816
+ else {
817
+ new_node->l = node;
818
+ }
819
+ new_node->parent = node->parent;
820
+ if (node->parent == NULL) {
821
+ assert (patricia->head == node);
822
+ patricia->head = new_node;
823
+ }
824
+ else if (node->parent->r == node) {
825
+ node->parent->r = new_node;
826
+ }
827
+ else {
828
+ node->parent->l = new_node;
829
+ }
830
+ node->parent = new_node;
831
+ #ifdef PATRICIA_DEBUG
832
+ fprintf (stderr, "patricia_lookup: new_node #3 %s/%d (parent)\n",
833
+ prefix_toa (prefix), prefix->bitlen);
834
+ #endif /* PATRICIA_DEBUG */
835
+ }
836
+ else {
837
+ glue = calloc(1, sizeof *glue);
838
+ glue->bit = differ_bit;
839
+ glue->prefix = NULL;
840
+ glue->parent = node->parent;
841
+ glue->data = NULL;
842
+ patricia->num_active_node++;
843
+ if (differ_bit < patricia->maxbits &&
844
+ BIT_TEST (addr[differ_bit >> 3], 0x80 >> (differ_bit & 0x07))) {
845
+ glue->r = new_node;
846
+ glue->l = node;
847
+ }
848
+ else {
849
+ glue->r = node;
850
+ glue->l = new_node;
851
+ }
852
+ new_node->parent = glue;
853
+
854
+ if (node->parent == NULL) {
855
+ assert (patricia->head == node);
856
+ patricia->head = glue;
857
+ }
858
+ else if (node->parent->r == node) {
859
+ node->parent->r = glue;
860
+ }
861
+ else {
862
+ node->parent->l = glue;
863
+ }
864
+ node->parent = glue;
865
+ #ifdef PATRICIA_DEBUG
866
+ fprintf (stderr, "patricia_lookup: new_node #4 %s/%d (glue+node)\n",
867
+ prefix_toa (prefix), prefix->bitlen);
868
+ #endif /* PATRICIA_DEBUG */
869
+ }
870
+ return (new_node);
871
+ }
872
+
873
+
874
+ void
875
+ patricia_remove (patricia_tree_t *patricia, patricia_node_t *node)
876
+ {
877
+ patricia_node_t *parent, *child;
878
+
879
+ assert (patricia);
880
+ assert (node);
881
+
882
+ if (node->r && node->l) {
883
+ #ifdef PATRICIA_DEBUG
884
+ fprintf (stderr, "patricia_remove: #0 %s/%d (r & l)\n",
885
+ prefix_toa (node->prefix), node->prefix->bitlen);
886
+ #endif /* PATRICIA_DEBUG */
887
+
888
+ /* this might be a placeholder node -- have to check and make sure
889
+ * there is a prefix aossciated with it ! */
890
+ if (node->prefix != NULL)
891
+ Deref_Prefix (node->prefix);
892
+ node->prefix = NULL;
893
+ /* Also I needed to clear data pointer -- masaki */
894
+ node->data = NULL;
895
+ return;
896
+ }
897
+
898
+ if (node->r == NULL && node->l == NULL) {
899
+ #ifdef PATRICIA_DEBUG
900
+ fprintf (stderr, "patricia_remove: #1 %s/%d (!r & !l)\n",
901
+ prefix_toa (node->prefix), node->prefix->bitlen);
902
+ #endif /* PATRICIA_DEBUG */
903
+ parent = node->parent;
904
+ Deref_Prefix (node->prefix);
905
+ Delete (node);
906
+ patricia->num_active_node--;
907
+
908
+ if (parent == NULL) {
909
+ assert (patricia->head == node);
910
+ patricia->head = NULL;
911
+ return;
912
+ }
913
+
914
+ if (parent->r == node) {
915
+ parent->r = NULL;
916
+ child = parent->l;
917
+ }
918
+ else {
919
+ assert (parent->l == node);
920
+ parent->l = NULL;
921
+ child = parent->r;
922
+ }
923
+
924
+ if (parent->prefix)
925
+ return;
926
+
927
+ /* we need to remove parent too */
928
+
929
+ if (parent->parent == NULL) {
930
+ assert (patricia->head == parent);
931
+ patricia->head = child;
932
+ }
933
+ else if (parent->parent->r == parent) {
934
+ parent->parent->r = child;
935
+ }
936
+ else {
937
+ assert (parent->parent->l == parent);
938
+ parent->parent->l = child;
939
+ }
940
+ child->parent = parent->parent;
941
+ Delete (parent);
942
+ patricia->num_active_node--;
943
+ return;
944
+ }
945
+
946
+ #ifdef PATRICIA_DEBUG
947
+ fprintf (stderr, "patricia_remove: #2 %s/%d (r ^ l)\n",
948
+ prefix_toa (node->prefix), node->prefix->bitlen);
949
+ #endif /* PATRICIA_DEBUG */
950
+ if (node->r) {
951
+ child = node->r;
952
+ }
953
+ else {
954
+ assert (node->l);
955
+ child = node->l;
956
+ }
957
+ parent = node->parent;
958
+ child->parent = parent;
959
+
960
+ Deref_Prefix (node->prefix);
961
+ Delete (node);
962
+ patricia->num_active_node--;
963
+
964
+ if (parent == NULL) {
965
+ assert (patricia->head == node);
966
+ patricia->head = child;
967
+ return;
968
+ }
969
+
970
+ if (parent->r == node) {
971
+ parent->r = child;
972
+ }
973
+ else {
974
+ assert (parent->l == node);
975
+ parent->l = child;
976
+ }
977
+ }
978
+
979
+ /* { from demo.c */
980
+
981
+ patricia_node_t *
982
+ make_and_lookup (patricia_tree_t *tree, char *string)
983
+ {
984
+ prefix_t *prefix;
985
+ patricia_node_t *node;
986
+
987
+ prefix = ascii2prefix (AF_INET, string);
988
+ printf ("make_and_lookup: %s/%d\n", prefix_toa (prefix), prefix->bitlen);
989
+ node = patricia_lookup (tree, prefix);
990
+ Deref_Prefix (prefix);
991
+ return (node);
992
+ }
993
+
994
+ patricia_node_t *
995
+ try_search_exact (patricia_tree_t *tree, char *string)
996
+ {
997
+ prefix_t *prefix;
998
+ patricia_node_t *node;
999
+
1000
+ prefix = ascii2prefix (AF_INET, string);
1001
+ printf ("try_search_exact: %s/%d\n", prefix_toa (prefix), prefix->bitlen);
1002
+ if ((node = patricia_search_exact (tree, prefix)) == NULL) {
1003
+ printf ("try_search_exact: not found\n");
1004
+ }
1005
+ else {
1006
+ printf ("try_search_exact: %s/%d found\n",
1007
+ prefix_toa (node->prefix), node->prefix->bitlen);
1008
+ }
1009
+ Deref_Prefix (prefix);
1010
+ return (node);
1011
+ }
1012
+
1013
+ void
1014
+ lookup_then_remove (patricia_tree_t *tree, char *string)
1015
+ {
1016
+ patricia_node_t *node;
1017
+
1018
+ if (node = try_search_exact (tree, string))
1019
+ patricia_remove (tree, node);
1020
+ }
1021
+
1022
+ patricia_node_t *
1023
+ try_search_best (patricia_tree_t *tree, char *string)
1024
+ {
1025
+ prefix_t *prefix;
1026
+ patricia_node_t *node;
1027
+
1028
+ prefix = ascii2prefix (AF_INET, string);
1029
+ printf ("try_search_best: %s/%d\n", prefix_toa (prefix), prefix->bitlen);
1030
+ if ((node = patricia_search_best (tree, prefix)) == NULL)
1031
+ printf ("try_search_best: not found\n");
1032
+ else
1033
+ printf ("try_search_best: %s/%d found\n",
1034
+ prefix_toa (node->prefix), node->prefix->bitlen);
1035
+ Deref_Prefix (prefix);
1036
+ }
1037
+
1038
+ /* } */