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.
- 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
|
+
/* } */
|