rpatricia 0.04
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes +16 -0
- data/README +179 -0
- data/TODO +2 -0
- data/copyright +34 -0
- data/credits.txt +73 -0
- data/extconf.rb +5 -0
- data/patricia.c +1038 -0
- data/patricia.h +147 -0
- data/rpatricia.c +225 -0
- 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/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
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
|
+
/* } */
|