rpatricia 0.04

Sign up to get free protection for your applications and to get access to all the features.
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
+ /* } */