1 |
michael |
5042 |
/* |
2 |
michael |
6259 |
* $Id$ |
3 |
michael |
5042 |
* Dave Plonka <plonka@doit.wisc.edu> |
4 |
|
|
* |
5 |
|
|
* This file had been called "radix.c" in the MRT sources. |
6 |
|
|
* |
7 |
|
|
* I renamed it to "patricia.c" since it's not an implementation of a general |
8 |
|
|
* radix trie. Also I pulled in various requirements from "prefix.c" and |
9 |
|
|
* "demo.c" so that it could be used as a standalone API. |
10 |
michael |
5046 |
* |
11 |
|
|
* Copyright (c) 1999-2013 |
12 |
|
|
* |
13 |
|
|
* The Regents of the University of Michigan ("The Regents") and Merit |
14 |
|
|
* Network, Inc. |
15 |
|
|
* |
16 |
|
|
* Redistributions of source code must retain the above copyright notice, |
17 |
|
|
* this list of conditions and the following disclaimer. |
18 |
|
|
* |
19 |
|
|
* Redistributions in binary form must reproduce the above copyright |
20 |
|
|
* notice, this list of conditions and the following disclaimer in the |
21 |
|
|
* documentation and/or other materials provided with the distribution. |
22 |
|
|
* |
23 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
24 |
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
25 |
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
26 |
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
27 |
|
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
28 |
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
29 |
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
30 |
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
31 |
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
32 |
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
33 |
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 |
michael |
5042 |
*/ |
35 |
|
|
|
36 |
|
|
#include <assert.h> /* assert */ |
37 |
|
|
#include <ctype.h> /* isdigit */ |
38 |
|
|
#include <errno.h> /* errno */ |
39 |
|
|
#include <math.h> /* sin */ |
40 |
|
|
#include <stddef.h> /* NULL */ |
41 |
|
|
#include <stdio.h> /* sprintf, fprintf, stderr */ |
42 |
|
|
#include <stdlib.h> /* free, atol, calloc */ |
43 |
|
|
#include <string.h> /* memcpy, strchr, strlen */ |
44 |
|
|
#include <sys/types.h> /* BSD: for inet_addr */ |
45 |
|
|
#include <sys/socket.h> /* BSD, Linux: for inet_addr */ |
46 |
|
|
#include <netinet/in.h> /* BSD, Linux: for inet_addr */ |
47 |
|
|
#include <arpa/inet.h> /* BSD, Linux, Solaris: for inet_addr */ |
48 |
|
|
|
49 |
|
|
#include "patricia.h" |
50 |
michael |
5047 |
#include "memory.h" |
51 |
michael |
5042 |
|
52 |
|
|
/* { from prefix.c */ |
53 |
|
|
|
54 |
|
|
/* prefix_tochar |
55 |
|
|
* convert prefix information to bytes |
56 |
|
|
*/ |
57 |
michael |
7806 |
static unsigned char * |
58 |
michael |
7834 |
prefix_tochar(prefix_t * prefix) |
59 |
michael |
5042 |
{ |
60 |
michael |
7834 |
if (prefix == NULL) |
61 |
|
|
return NULL; |
62 |
|
|
return (unsigned char *)&prefix->add.sin; |
63 |
michael |
5042 |
} |
64 |
|
|
|
65 |
michael |
6607 |
static int |
66 |
michael |
7834 |
comp_with_mask(void *addr, void *dest, unsigned int mask) |
67 |
michael |
5042 |
{ |
68 |
michael |
7834 |
if ( /* mask/8 == 0 || */ memcmp(addr, dest, mask / 8) == 0) |
69 |
|
|
{ |
70 |
|
|
int n = mask / 8; |
71 |
|
|
int m = ((-1) << (8 - (mask % 8))); |
72 |
michael |
5042 |
|
73 |
michael |
7834 |
if (mask % 8 == 0 || (((unsigned char *)addr)[n] & m) == (((unsigned char *)dest)[n] & m)) |
74 |
|
|
return 1; |
75 |
|
|
} |
76 |
michael |
5042 |
|
77 |
michael |
7834 |
return 0; |
78 |
michael |
5042 |
} |
79 |
|
|
|
80 |
michael |
6607 |
/* |
81 |
michael |
5042 |
* convert prefix information to ascii string with length |
82 |
|
|
*/ |
83 |
michael |
7824 |
const char * |
84 |
michael |
7839 |
prefix_toa(const prefix_t *prefix, int with_len) |
85 |
michael |
5042 |
{ |
86 |
michael |
7839 |
static char buf[INET6_ADDRSTRLEN + sizeof("/128")]; |
87 |
michael |
5042 |
|
88 |
michael |
7839 |
assert(prefix); |
89 |
michael |
7834 |
assert(prefix->ref_count >= 0); |
90 |
michael |
7839 |
assert((prefix->family == AF_INET && prefix->bitlen <= 32) || |
91 |
|
|
(prefix->family == AF_INET6 && prefix->bitlen <= 128)); |
92 |
michael |
7834 |
|
93 |
michael |
7839 |
inet_ntop(prefix->family, &prefix->add.sin6, buf, INET6_ADDRSTRLEN); |
94 |
michael |
7834 |
|
95 |
michael |
7839 |
if (with_len) |
96 |
|
|
sprintf(buf + strlen(buf), "/%d", prefix->bitlen); |
97 |
|
|
return buf; |
98 |
michael |
5042 |
} |
99 |
|
|
|
100 |
michael |
7814 |
static prefix_t * |
101 |
michael |
7834 |
New_Prefix2(int family, void *dest, int bitlen, prefix_t *prefix) |
102 |
michael |
5042 |
{ |
103 |
michael |
7834 |
int dynamic_allocated = 0; |
104 |
michael |
7841 |
int addr_size = 0; |
105 |
michael |
5042 |
|
106 |
michael |
7841 |
switch (family) |
107 |
michael |
7834 |
{ |
108 |
michael |
7841 |
case AF_INET: |
109 |
|
|
addr_size = sizeof(struct in_addr); |
110 |
|
|
break; |
111 |
|
|
case AF_INET6: |
112 |
|
|
addr_size = sizeof(struct in6_addr); |
113 |
|
|
break; |
114 |
|
|
default: return NULL; |
115 |
michael |
7834 |
} |
116 |
michael |
5042 |
|
117 |
michael |
7841 |
if (!prefix) |
118 |
michael |
7834 |
{ |
119 |
michael |
7841 |
prefix = xcalloc(sizeof(prefix_t)); |
120 |
|
|
dynamic_allocated = 1; |
121 |
michael |
7834 |
} |
122 |
|
|
|
123 |
michael |
7841 |
memcpy(&prefix->add.sin6, dest, addr_size); |
124 |
|
|
prefix->bitlen = (bitlen >= 0) ? bitlen : addr_size * 8; |
125 |
michael |
7834 |
prefix->family = family; |
126 |
michael |
7841 |
prefix->ref_count = dynamic_allocated == 1; |
127 |
michael |
7834 |
|
128 |
|
|
/* fprintf(stderr, "[C %s, %d]\n", prefix_toa(prefix), prefix->ref_count); */ |
129 |
|
|
return prefix; |
130 |
michael |
5042 |
} |
131 |
|
|
|
132 |
michael |
7814 |
static prefix_t * |
133 |
michael |
5042 |
New_Prefix (int family, void *dest, int bitlen) |
134 |
|
|
{ |
135 |
michael |
7834 |
return New_Prefix2(family, dest, bitlen, NULL); |
136 |
michael |
5042 |
} |
137 |
|
|
|
138 |
|
|
/* ascii2prefix |
139 |
|
|
*/ |
140 |
michael |
7814 |
static prefix_t * |
141 |
michael |
7834 |
ascii2prefix(int family, const char *string) |
142 |
michael |
5042 |
{ |
143 |
michael |
7842 |
int bitlen, maxbitlen = 0; |
144 |
michael |
7834 |
char *cp; |
145 |
|
|
char save[MAXLINE]; |
146 |
michael |
7840 |
union |
147 |
|
|
{ |
148 |
|
|
struct in_addr sin; |
149 |
|
|
struct in6_addr sin6; |
150 |
|
|
} sin; |
151 |
michael |
5042 |
|
152 |
michael |
7840 |
assert(string); |
153 |
michael |
5042 |
|
154 |
michael |
7840 |
/* Easy way to handle both families */ |
155 |
michael |
7834 |
if (family == 0) |
156 |
|
|
{ |
157 |
|
|
family = AF_INET; |
158 |
michael |
5044 |
|
159 |
michael |
7834 |
if (strchr (string, ':')) |
160 |
|
|
family = AF_INET6; |
161 |
|
|
} |
162 |
michael |
5042 |
|
163 |
michael |
7834 |
if (family == AF_INET) |
164 |
michael |
7840 |
maxbitlen = sizeof(struct in_addr) * 8; |
165 |
michael |
7834 |
else if (family == AF_INET6) |
166 |
|
|
maxbitlen = sizeof(struct in6_addr) * 8; |
167 |
michael |
5042 |
|
168 |
michael |
7840 |
if ((cp = strchr(string, '/'))) |
169 |
michael |
7834 |
{ |
170 |
michael |
7842 |
bitlen = atoi(cp + 1); |
171 |
michael |
5042 |
|
172 |
michael |
7834 |
/* *cp = '\0'; */ |
173 |
|
|
/* copy the string to save. Avoid destroying the string */ |
174 |
|
|
assert(cp - string < MAXLINE); |
175 |
|
|
memcpy(save, string, cp - string); |
176 |
michael |
5045 |
|
177 |
michael |
7834 |
save[cp - string] = '\0'; |
178 |
|
|
string = save; |
179 |
|
|
|
180 |
|
|
if (bitlen < 0 || bitlen > maxbitlen) |
181 |
|
|
bitlen = maxbitlen; |
182 |
|
|
} |
183 |
|
|
else |
184 |
|
|
bitlen = maxbitlen; |
185 |
|
|
|
186 |
michael |
7840 |
if (inet_pton(family, string, &sin) <= 0) |
187 |
michael |
7834 |
return NULL; |
188 |
michael |
7840 |
return New_Prefix(family, &sin, bitlen); |
189 |
michael |
5042 |
} |
190 |
|
|
|
191 |
michael |
5048 |
static prefix_t * |
192 |
michael |
7834 |
Ref_Prefix(prefix_t *prefix) |
193 |
michael |
5042 |
{ |
194 |
michael |
7834 |
if (prefix == NULL) |
195 |
|
|
return NULL; |
196 |
|
|
|
197 |
|
|
if (prefix->ref_count == 0) |
198 |
|
|
{ |
199 |
|
|
/* make a copy in case of a static prefix */ |
200 |
|
|
return New_Prefix2(prefix->family, &prefix->add, prefix->bitlen, NULL); |
201 |
|
|
} |
202 |
|
|
|
203 |
|
|
prefix->ref_count++; |
204 |
|
|
|
205 |
|
|
/* fprintf(stderr, "[A %s, %d]\n", prefix_toa(prefix), prefix->ref_count); */ |
206 |
|
|
return prefix; |
207 |
michael |
5042 |
} |
208 |
|
|
|
209 |
michael |
5048 |
static void |
210 |
michael |
7834 |
Deref_Prefix(prefix_t *prefix) |
211 |
michael |
5042 |
{ |
212 |
michael |
7834 |
if (prefix == NULL) |
213 |
|
|
return; |
214 |
michael |
5042 |
|
215 |
michael |
7837 |
/* For secure programming, raise an assert. No static prefix can call this */ |
216 |
michael |
7834 |
assert(prefix->ref_count > 0); |
217 |
michael |
7837 |
if (--prefix->ref_count <= 0) |
218 |
michael |
7834 |
xfree(prefix); |
219 |
michael |
5042 |
} |
220 |
|
|
|
221 |
|
|
/* } */ |
222 |
|
|
|
223 |
|
|
/* #define PATRICIA_DEBUG 1 */ |
224 |
|
|
|
225 |
|
|
/* these routines support continuous mask only */ |
226 |
|
|
|
227 |
|
|
patricia_tree_t * |
228 |
michael |
7843 |
New_Patricia(unsigned int maxbits) |
229 |
michael |
5042 |
{ |
230 |
michael |
7834 |
patricia_tree_t *patricia = xcalloc(sizeof *patricia); |
231 |
|
|
patricia->maxbits = maxbits; |
232 |
michael |
7830 |
|
233 |
michael |
7834 |
assert(maxbits <= PATRICIA_MAXBITS); /* XXX */ |
234 |
|
|
return patricia; |
235 |
michael |
5042 |
} |
236 |
|
|
|
237 |
|
|
/* |
238 |
|
|
* if func is supplied, it will be called as func(node->data) |
239 |
|
|
* before deleting the node |
240 |
|
|
*/ |
241 |
|
|
void |
242 |
michael |
7834 |
Clear_Patricia(patricia_tree_t *patricia, void (*func)(void *)) |
243 |
michael |
5042 |
{ |
244 |
michael |
7834 |
assert(patricia); |
245 |
michael |
5042 |
|
246 |
michael |
7834 |
if (patricia->head) |
247 |
|
|
{ |
248 |
|
|
patricia_node_t *Xstack[PATRICIA_MAXBITS + 1]; |
249 |
|
|
patricia_node_t **Xsp = Xstack; |
250 |
|
|
patricia_node_t *Xrn = patricia->head; |
251 |
michael |
5042 |
|
252 |
michael |
7834 |
while (Xrn) |
253 |
|
|
{ |
254 |
|
|
patricia_node_t *l = Xrn->l; |
255 |
|
|
patricia_node_t *r = Xrn->r; |
256 |
michael |
5042 |
|
257 |
michael |
7834 |
if (Xrn->prefix) |
258 |
|
|
{ |
259 |
|
|
Deref_Prefix(Xrn->prefix); |
260 |
michael |
5042 |
|
261 |
michael |
7834 |
if (Xrn->data && func) |
262 |
|
|
func(Xrn->data); |
263 |
|
|
} |
264 |
|
|
else |
265 |
|
|
{ |
266 |
|
|
assert(Xrn->data == NULL); |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
xfree (Xrn); |
270 |
|
|
patricia->num_active_node--; |
271 |
|
|
|
272 |
|
|
if (l) |
273 |
|
|
{ |
274 |
|
|
if (r) |
275 |
|
|
{ |
276 |
|
|
*Xsp++ = r; |
277 |
michael |
5042 |
} |
278 |
michael |
7834 |
|
279 |
|
|
Xrn = l; |
280 |
|
|
} |
281 |
|
|
else if (r) |
282 |
|
|
{ |
283 |
|
|
Xrn = r; |
284 |
|
|
} |
285 |
|
|
else if (Xsp != Xstack) |
286 |
|
|
{ |
287 |
|
|
Xrn = *(--Xsp); |
288 |
|
|
} |
289 |
|
|
else |
290 |
|
|
{ |
291 |
|
|
Xrn = NULL; |
292 |
|
|
} |
293 |
michael |
5042 |
} |
294 |
michael |
7834 |
} |
295 |
|
|
|
296 |
|
|
assert(patricia->num_active_node == 0); |
297 |
|
|
/* xfree (patricia); */ |
298 |
michael |
5042 |
} |
299 |
|
|
|
300 |
|
|
void |
301 |
michael |
7834 |
Destroy_Patricia(patricia_tree_t *patricia, void (*func)(void *)) |
302 |
michael |
5042 |
{ |
303 |
michael |
7834 |
Clear_Patricia(patricia, func); |
304 |
|
|
xfree(patricia); |
305 |
michael |
5042 |
} |
306 |
|
|
|
307 |
|
|
/* |
308 |
|
|
* if func is supplied, it will be called as func(node->prefix, node->data) |
309 |
|
|
*/ |
310 |
|
|
void |
311 |
michael |
7834 |
patricia_process(patricia_tree_t *patricia, void (*func)(prefix_t *, void *)) |
312 |
michael |
5042 |
{ |
313 |
michael |
7834 |
patricia_node_t *node; |
314 |
michael |
5042 |
|
315 |
michael |
7834 |
assert(func); |
316 |
|
|
|
317 |
|
|
PATRICIA_WALK (patricia->head, node) { |
318 |
michael |
7838 |
func(node->prefix, node->data); |
319 |
michael |
7834 |
} PATRICIA_WALK_END; |
320 |
michael |
5042 |
} |
321 |
|
|
|
322 |
|
|
patricia_node_t * |
323 |
michael |
7834 |
patricia_search_exact(patricia_tree_t *patricia, prefix_t *prefix) |
324 |
michael |
5042 |
{ |
325 |
michael |
7834 |
patricia_node_t *node; |
326 |
|
|
unsigned char *addr; |
327 |
|
|
unsigned int bitlen; |
328 |
michael |
5042 |
|
329 |
michael |
7834 |
assert(patricia); |
330 |
|
|
assert(prefix); |
331 |
|
|
assert(prefix->bitlen <= patricia->maxbits); |
332 |
michael |
5042 |
|
333 |
michael |
7834 |
if (patricia->head == NULL) |
334 |
|
|
return NULL; |
335 |
michael |
5042 |
|
336 |
michael |
7834 |
node = patricia->head; |
337 |
michael |
7838 |
addr = prefix_touchar(prefix); |
338 |
michael |
7834 |
bitlen = prefix->bitlen; |
339 |
michael |
5042 |
|
340 |
michael |
7834 |
while (node->bit < bitlen) |
341 |
|
|
{ |
342 |
|
|
if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) |
343 |
|
|
{ |
344 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
345 |
michael |
7834 |
if (node->prefix) |
346 |
|
|
fprintf(stderr, "patricia_search_exact: take right %s/%d\n", |
347 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
348 |
|
|
else |
349 |
|
|
fprintf(stderr, "patricia_search_exact: take right at %u\n", node->bit); |
350 |
|
|
#endif /* PATRICIA_DEBUG */ |
351 |
|
|
node = node->r; |
352 |
|
|
} |
353 |
|
|
else |
354 |
|
|
{ |
355 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
356 |
michael |
7834 |
if (node->prefix) |
357 |
|
|
fprintf(stderr, "patricia_search_exact: take left %s/%d\n", |
358 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
359 |
|
|
else |
360 |
|
|
fprintf(stderr, "patricia_search_exact: take left at %u\n", node->bit); |
361 |
|
|
#endif /* PATRICIA_DEBUG */ |
362 |
|
|
node = node->l; |
363 |
michael |
5042 |
} |
364 |
|
|
|
365 |
michael |
7834 |
if (node == NULL) |
366 |
|
|
return NULL; |
367 |
|
|
} |
368 |
|
|
|
369 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
370 |
michael |
7834 |
if (node->prefix) |
371 |
|
|
fprintf(stderr, "patricia_search_exact: stop at %s/%d\n", |
372 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
373 |
|
|
else |
374 |
|
|
fprintf(stderr, "patricia_search_exact: stop at %u\n", node->bit); |
375 |
|
|
#endif /* PATRICIA_DEBUG */ |
376 |
|
|
|
377 |
|
|
if (node->bit > bitlen || node->prefix == NULL) |
378 |
|
|
return NULL; |
379 |
|
|
|
380 |
|
|
assert(node->bit == bitlen); |
381 |
|
|
assert(node->bit == node->prefix->bitlen); |
382 |
|
|
|
383 |
|
|
if (comp_with_mask(prefix_tochar(node->prefix), prefix_tochar(prefix), bitlen)) |
384 |
|
|
{ |
385 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
386 |
michael |
7834 |
fprintf(stderr, "patricia_search_exact: found %s/%d\n", |
387 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
388 |
|
|
#endif /* PATRICIA_DEBUG */ |
389 |
|
|
return node; |
390 |
|
|
} |
391 |
|
|
|
392 |
|
|
return NULL; |
393 |
michael |
5042 |
} |
394 |
|
|
|
395 |
|
|
/* if inclusive != 0, "best" may be the given prefix itself */ |
396 |
|
|
patricia_node_t * |
397 |
michael |
7834 |
patricia_search_best2(patricia_tree_t *patricia, prefix_t *prefix, int inclusive) |
398 |
michael |
5042 |
{ |
399 |
michael |
7834 |
patricia_node_t *node; |
400 |
|
|
patricia_node_t *stack[PATRICIA_MAXBITS + 1]; |
401 |
|
|
unsigned char *addr; |
402 |
|
|
unsigned int bitlen; |
403 |
|
|
int cnt = 0; |
404 |
michael |
5042 |
|
405 |
michael |
7834 |
assert(patricia); |
406 |
|
|
assert(prefix); |
407 |
|
|
assert(prefix->bitlen <= patricia->maxbits); |
408 |
michael |
5042 |
|
409 |
michael |
7834 |
if (patricia->head == NULL) |
410 |
|
|
return NULL; |
411 |
michael |
5042 |
|
412 |
michael |
7834 |
node = patricia->head; |
413 |
michael |
7838 |
addr = prefix_touchar(prefix); |
414 |
michael |
7834 |
bitlen = prefix->bitlen; |
415 |
michael |
5042 |
|
416 |
michael |
7834 |
while (node->bit < bitlen) |
417 |
|
|
{ |
418 |
|
|
if (node->prefix) |
419 |
|
|
{ |
420 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
421 |
michael |
7834 |
fprintf(stderr, "patricia_search_best: push %s/%d\n", |
422 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
423 |
|
|
#endif /* PATRICIA_DEBUG */ |
424 |
|
|
stack[cnt++] = node; |
425 |
|
|
} |
426 |
michael |
5042 |
|
427 |
michael |
7838 |
if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) |
428 |
michael |
7834 |
{ |
429 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
430 |
michael |
7834 |
if (node->prefix) |
431 |
|
|
fprintf(stderr, "patricia_search_best: take right %s/%d\n", |
432 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
433 |
|
|
else |
434 |
|
|
fprintf(stderr, "patricia_search_best: take right at %u\n", node->bit); |
435 |
|
|
#endif /* PATRICIA_DEBUG */ |
436 |
|
|
node = node->r; |
437 |
|
|
} |
438 |
|
|
else |
439 |
|
|
{ |
440 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
441 |
michael |
7834 |
if (node->prefix) |
442 |
|
|
fprintf(stderr, "patricia_search_best: take left %s/%d\n", |
443 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
444 |
|
|
else |
445 |
|
|
fprintf(stderr, "patricia_search_best: take left at %u\n", node->bit); |
446 |
|
|
#endif /* PATRICIA_DEBUG */ |
447 |
|
|
node = node->l; |
448 |
michael |
5042 |
} |
449 |
|
|
|
450 |
michael |
7834 |
if (node == NULL) |
451 |
|
|
break; |
452 |
|
|
} |
453 |
michael |
5042 |
|
454 |
michael |
7834 |
if (inclusive && node && node->prefix) |
455 |
|
|
stack[cnt++] = node; |
456 |
|
|
|
457 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
458 |
michael |
7834 |
if (node == NULL) |
459 |
|
|
fprintf(stderr, "patricia_search_best: stop at null\n"); |
460 |
|
|
else if (node->prefix) |
461 |
|
|
fprintf(stderr, "patricia_search_best: stop at %s/%d\n", |
462 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
463 |
|
|
else |
464 |
|
|
fprintf(stderr, "patricia_search_best: stop at %u\n", node->bit); |
465 |
|
|
#endif /* PATRICIA_DEBUG */ |
466 |
michael |
5042 |
|
467 |
michael |
7834 |
if (cnt <= 0) |
468 |
|
|
return NULL; |
469 |
michael |
5042 |
|
470 |
michael |
7834 |
while (--cnt >= 0) |
471 |
|
|
{ |
472 |
|
|
node = stack[cnt]; |
473 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
474 |
michael |
7834 |
fprintf(stderr, "patricia_search_best: pop %s/%d\n", |
475 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
476 |
|
|
#endif /* PATRICIA_DEBUG */ |
477 |
|
|
|
478 |
|
|
if (comp_with_mask(prefix_tochar(node->prefix), |
479 |
|
|
prefix_tochar(prefix), node->prefix->bitlen) && node->prefix->bitlen <= bitlen) |
480 |
|
|
{ |
481 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
482 |
michael |
7834 |
fprintf(stderr, "patricia_search_best: found %s/%d\n", |
483 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
484 |
|
|
#endif /* PATRICIA_DEBUG */ |
485 |
|
|
return node; |
486 |
michael |
5042 |
} |
487 |
michael |
7834 |
} |
488 |
|
|
|
489 |
|
|
return NULL; |
490 |
michael |
5042 |
} |
491 |
|
|
|
492 |
|
|
patricia_node_t * |
493 |
michael |
7834 |
patricia_search_best(patricia_tree_t *patricia, prefix_t *prefix) |
494 |
michael |
5042 |
{ |
495 |
michael |
7834 |
return patricia_search_best2(patricia, prefix, 1); |
496 |
michael |
5042 |
} |
497 |
|
|
|
498 |
|
|
patricia_node_t * |
499 |
michael |
7834 |
patricia_lookup(patricia_tree_t *patricia, prefix_t *prefix) |
500 |
michael |
5042 |
{ |
501 |
michael |
7834 |
patricia_node_t *node, *new_node, *parent, *glue; |
502 |
|
|
unsigned char *addr, *test_addr; |
503 |
|
|
unsigned int bitlen, check_bit, differ_bit; |
504 |
|
|
int j, r; |
505 |
michael |
5042 |
|
506 |
michael |
7834 |
assert(patricia); |
507 |
|
|
assert(prefix); |
508 |
|
|
assert(prefix->bitlen <= patricia->maxbits); |
509 |
michael |
5042 |
|
510 |
michael |
7834 |
if (patricia->head == NULL) |
511 |
|
|
{ |
512 |
|
|
node = xcalloc(sizeof *node); |
513 |
|
|
node->bit = prefix->bitlen; |
514 |
|
|
node->prefix = Ref_Prefix (prefix); |
515 |
|
|
node->parent = NULL; |
516 |
|
|
node->l = node->r = NULL; |
517 |
|
|
node->data = NULL; |
518 |
|
|
patricia->head = node; |
519 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
520 |
michael |
7834 |
fprintf(stderr, "patricia_lookup: new_node #0 %s/%d (head)\n", |
521 |
|
|
prefix_toa(prefix), prefix->bitlen); |
522 |
|
|
#endif /* PATRICIA_DEBUG */ |
523 |
|
|
patricia->num_active_node++; |
524 |
|
|
return node; |
525 |
|
|
} |
526 |
michael |
5042 |
|
527 |
michael |
7838 |
addr = prefix_touchar(prefix); |
528 |
michael |
7834 |
bitlen = prefix->bitlen; |
529 |
|
|
node = patricia->head; |
530 |
michael |
5042 |
|
531 |
michael |
7834 |
while (node->bit < bitlen || node->prefix == NULL) |
532 |
|
|
{ |
533 |
|
|
if (node->bit < patricia->maxbits && BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) |
534 |
|
|
{ |
535 |
|
|
if (node->r == NULL) |
536 |
|
|
break; |
537 |
|
|
#ifdef PATRICIA_DEBUG |
538 |
|
|
if (node->prefix) |
539 |
|
|
fprintf(stderr, "patricia_lookup: take right %s/%d\n", |
540 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
541 |
|
|
else |
542 |
|
|
fprintf(stderr, "patricia_lookup: take right at %u\n", node->bit); |
543 |
|
|
#endif /* PATRICIA_DEBUG */ |
544 |
michael |
5042 |
|
545 |
michael |
7834 |
node = node->r; |
546 |
|
|
} |
547 |
|
|
else |
548 |
|
|
{ |
549 |
|
|
if (node->l == NULL) |
550 |
|
|
break; |
551 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
552 |
michael |
7834 |
if (node->prefix) |
553 |
|
|
fprintf(stderr, "patricia_lookup: take left %s/%d\n", |
554 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
555 |
|
|
else |
556 |
|
|
fprintf(stderr, "patricia_lookup: take left at %u\n", node->bit); |
557 |
|
|
#endif /* PATRICIA_DEBUG */ |
558 |
michael |
5042 |
|
559 |
michael |
7834 |
node = node->l; |
560 |
michael |
5042 |
} |
561 |
|
|
|
562 |
michael |
7834 |
assert(node); |
563 |
|
|
} |
564 |
|
|
|
565 |
michael |
7838 |
assert(node->prefix); |
566 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
567 |
michael |
7834 |
fprintf(stderr, "patricia_lookup: stop at %s/%d\n", |
568 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
569 |
michael |
5042 |
#endif /* PATRICIA_DEBUG */ |
570 |
|
|
|
571 |
michael |
7838 |
test_addr = prefix_touchar(node->prefix); |
572 |
michael |
7834 |
|
573 |
|
|
/* Find the first bit different */ |
574 |
|
|
check_bit = (node->bit < bitlen) ? node->bit : bitlen; |
575 |
|
|
differ_bit = 0; |
576 |
|
|
|
577 |
|
|
for (unsigned int i = 0; i * 8 < check_bit; i++) |
578 |
|
|
{ |
579 |
|
|
if ((r = (addr[i] ^ test_addr[i])) == 0) |
580 |
|
|
{ |
581 |
|
|
differ_bit = (i + 1) * 8; |
582 |
|
|
continue; |
583 |
michael |
5042 |
} |
584 |
michael |
7834 |
|
585 |
|
|
/* I know the better way, but for now */ |
586 |
|
|
for (j = 0; j < 8; j++) |
587 |
|
|
{ |
588 |
|
|
if (BIT_TEST (r, (0x80 >> j))) |
589 |
|
|
break; |
590 |
|
|
} |
591 |
|
|
|
592 |
|
|
/* Must be found */ |
593 |
michael |
7838 |
assert(j < 8); |
594 |
michael |
7834 |
differ_bit = i * 8 + j; |
595 |
|
|
break; |
596 |
|
|
} |
597 |
|
|
|
598 |
|
|
if (differ_bit > check_bit) |
599 |
|
|
differ_bit = check_bit; |
600 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
601 |
michael |
7834 |
fprintf(stderr, "patricia_lookup: differ_bit %d\n", differ_bit); |
602 |
|
|
#endif /* PATRICIA_DEBUG */ |
603 |
michael |
5042 |
|
604 |
michael |
7834 |
parent = node->parent; |
605 |
|
|
|
606 |
|
|
while (parent && parent->bit >= differ_bit) |
607 |
|
|
{ |
608 |
|
|
node = parent; |
609 |
michael |
5042 |
parent = node->parent; |
610 |
michael |
7834 |
|
611 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
612 |
michael |
7834 |
if (node->prefix) |
613 |
|
|
fprintf(stderr, "patricia_lookup: up to %s/%d\n", |
614 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
615 |
|
|
else |
616 |
|
|
fprintf(stderr, "patricia_lookup: up to %u\n", node->bit); |
617 |
|
|
#endif /* PATRICIA_DEBUG */ |
618 |
|
|
} |
619 |
|
|
|
620 |
|
|
if (differ_bit == bitlen && node->bit == bitlen) |
621 |
|
|
{ |
622 |
|
|
if (node->prefix) |
623 |
|
|
{ |
624 |
|
|
#ifdef PATRICIA_DEBUG |
625 |
|
|
fprintf(stderr, "patricia_lookup: found %s/%d\n", |
626 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
627 |
|
|
#endif /* PATRICIA_DEBUG */ |
628 |
|
|
|
629 |
|
|
return node; |
630 |
michael |
5042 |
} |
631 |
|
|
|
632 |
michael |
7834 |
node->prefix = Ref_Prefix(prefix); |
633 |
michael |
6607 |
#ifdef PATRICIA_DEBUG |
634 |
michael |
7834 |
fprintf(stderr, "patricia_lookup: new node #1 %s/%d (glue mod)\n", |
635 |
|
|
prefix_toa(prefix), prefix->bitlen); |
636 |
|
|
#endif /* PATRICIA_DEBUG */ |
637 |
|
|
|
638 |
|
|
assert(node->data == NULL); |
639 |
|
|
return node; |
640 |
|
|
} |
641 |
|
|
|
642 |
|
|
new_node = xcalloc(sizeof *new_node); |
643 |
|
|
new_node->bit = prefix->bitlen; |
644 |
|
|
new_node->prefix = Ref_Prefix (prefix); |
645 |
|
|
new_node->parent = NULL; |
646 |
|
|
new_node->l = new_node->r = NULL; |
647 |
|
|
new_node->data = NULL; |
648 |
|
|
patricia->num_active_node++; |
649 |
|
|
|
650 |
|
|
if (node->bit == differ_bit) |
651 |
|
|
{ |
652 |
|
|
new_node->parent = node; |
653 |
|
|
|
654 |
|
|
if (node->bit < patricia->maxbits && BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) |
655 |
|
|
{ |
656 |
|
|
assert(node->r == NULL); |
657 |
|
|
node->r = new_node; |
658 |
|
|
} |
659 |
|
|
else |
660 |
|
|
{ |
661 |
|
|
assert(node->l == NULL); |
662 |
|
|
node->l = new_node; |
663 |
|
|
} |
664 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
665 |
michael |
7834 |
fprintf(stderr, "patricia_lookup: new_node #2 %s/%d (child)\n", |
666 |
|
|
prefix_toa(prefix), prefix->bitlen); |
667 |
|
|
#endif /* PATRICIA_DEBUG */ |
668 |
|
|
return new_node; |
669 |
|
|
} |
670 |
|
|
|
671 |
|
|
if (bitlen == differ_bit) |
672 |
|
|
{ |
673 |
|
|
if (bitlen < patricia->maxbits && BIT_TEST(test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07))) |
674 |
|
|
{ |
675 |
|
|
new_node->r = node; |
676 |
michael |
5042 |
} |
677 |
michael |
7834 |
else |
678 |
|
|
{ |
679 |
|
|
new_node->l = node; |
680 |
|
|
} |
681 |
michael |
5042 |
|
682 |
michael |
7834 |
new_node->parent = node->parent; |
683 |
michael |
5042 |
|
684 |
michael |
7834 |
if (node->parent == NULL) |
685 |
|
|
{ |
686 |
|
|
assert(patricia->head == node); |
687 |
|
|
patricia->head = new_node; |
688 |
michael |
5042 |
} |
689 |
michael |
7834 |
else if (node->parent->r == node) |
690 |
|
|
{ |
691 |
|
|
node->parent->r = new_node; |
692 |
|
|
} |
693 |
|
|
else |
694 |
|
|
{ |
695 |
|
|
node->parent->l = new_node; |
696 |
|
|
} |
697 |
michael |
5042 |
|
698 |
michael |
7834 |
node->parent = new_node; |
699 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
700 |
michael |
7834 |
fprintf(stderr, "patricia_lookup: new_node #3 %s/%d (parent)\n", |
701 |
|
|
prefix_toa(prefix), prefix->bitlen); |
702 |
|
|
#endif /* PATRICIA_DEBUG */ |
703 |
|
|
} |
704 |
|
|
else |
705 |
|
|
{ |
706 |
|
|
glue = xcalloc(sizeof *glue); |
707 |
|
|
glue->bit = differ_bit; |
708 |
|
|
glue->prefix = NULL; |
709 |
|
|
glue->parent = node->parent; |
710 |
|
|
glue->data = NULL; |
711 |
|
|
patricia->num_active_node++; |
712 |
|
|
|
713 |
|
|
if (differ_bit < patricia->maxbits && BIT_TEST(addr[differ_bit >> 3], 0x80 >> (differ_bit & 0x07))) |
714 |
|
|
{ |
715 |
|
|
glue->r = new_node; |
716 |
|
|
glue->l = node; |
717 |
michael |
5042 |
} |
718 |
michael |
7834 |
else |
719 |
|
|
{ |
720 |
|
|
glue->r = node; |
721 |
|
|
glue->l = new_node; |
722 |
|
|
} |
723 |
michael |
5042 |
|
724 |
michael |
7834 |
new_node->parent = glue; |
725 |
|
|
|
726 |
|
|
if (node->parent == NULL) |
727 |
|
|
{ |
728 |
|
|
assert(patricia->head == node); |
729 |
|
|
patricia->head = glue; |
730 |
|
|
} |
731 |
|
|
else if (node->parent->r == node) |
732 |
|
|
{ |
733 |
|
|
node->parent->r = glue; |
734 |
|
|
} |
735 |
|
|
else |
736 |
|
|
{ |
737 |
|
|
node->parent->l = glue; |
738 |
|
|
} |
739 |
|
|
|
740 |
|
|
node->parent = glue; |
741 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
742 |
michael |
7834 |
fprintf(stderr, "patricia_lookup: new_node #4 %s/%d (glue+node)\n", |
743 |
|
|
prefix_toa(prefix), prefix->bitlen); |
744 |
|
|
#endif /* PATRICIA_DEBUG */ |
745 |
|
|
} |
746 |
|
|
|
747 |
|
|
return new_node; |
748 |
michael |
5042 |
} |
749 |
|
|
|
750 |
|
|
void |
751 |
michael |
7834 |
patricia_remove(patricia_tree_t *patricia, patricia_node_t *node) |
752 |
michael |
5042 |
{ |
753 |
michael |
7834 |
patricia_node_t *parent, *child; |
754 |
michael |
5042 |
|
755 |
michael |
7834 |
assert(patricia); |
756 |
|
|
assert(node); |
757 |
michael |
5042 |
|
758 |
michael |
7834 |
if (node->r && node->l) |
759 |
|
|
{ |
760 |
michael |
5042 |
#ifdef PATRICIA_DEBUG |
761 |
michael |
7834 |
fprintf(stderr, "patricia_remove: #0 %s/%d (r & l)\n", |
762 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
763 |
|
|
#endif /* PATRICIA_DEBUG */ |
764 |
michael |
5042 |
|
765 |
michael |
7834 |
/* |
766 |
|
|
* This might be a placeholder node -- have to check and make sure |
767 |
|
|
* there is a prefix associated with it ! |
768 |
|
|
*/ |
769 |
|
|
if (node->prefix != NULL) |
770 |
|
|
Deref_Prefix(node->prefix); |
771 |
michael |
5042 |
|
772 |
michael |
7834 |
node->prefix = NULL; |
773 |
|
|
/* Also I needed to clear data pointer -- masaki */ |
774 |
|
|
node->data = NULL; |
775 |
|
|
return; |
776 |
|
|
} |
777 |
michael |
5042 |
|
778 |
michael |
7834 |
if (node->r == NULL && node->l == NULL) |
779 |
|
|
{ |
780 |
|
|
#ifdef PATRICIA_DEBUG |
781 |
|
|
fprintf(stderr, "patricia_remove: #1 %s/%d (!r & !l)\n", |
782 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
783 |
|
|
#endif /* PATRICIA_DEBUG */ |
784 |
michael |
5042 |
|
785 |
michael |
7834 |
parent = node->parent; |
786 |
|
|
Deref_Prefix(node->prefix); |
787 |
|
|
xfree(node); |
788 |
|
|
patricia->num_active_node--; |
789 |
michael |
5042 |
|
790 |
michael |
7834 |
if (parent == NULL) |
791 |
|
|
{ |
792 |
|
|
assert(patricia->head == node); |
793 |
|
|
patricia->head = NULL; |
794 |
|
|
return; |
795 |
|
|
} |
796 |
michael |
5042 |
|
797 |
michael |
7834 |
if (parent->r == node) |
798 |
|
|
{ |
799 |
|
|
parent->r = NULL; |
800 |
|
|
child = parent->l; |
801 |
michael |
5042 |
} |
802 |
michael |
7834 |
else |
803 |
|
|
{ |
804 |
|
|
assert(parent->l == node); |
805 |
michael |
5042 |
|
806 |
michael |
7834 |
parent->l = NULL; |
807 |
|
|
child = parent->r; |
808 |
michael |
5042 |
} |
809 |
michael |
7834 |
|
810 |
|
|
if (parent->prefix) |
811 |
|
|
return; |
812 |
|
|
|
813 |
|
|
/* We need to remove parent too */ |
814 |
|
|
if (parent->parent == NULL) |
815 |
|
|
{ |
816 |
|
|
assert(patricia->head == parent); |
817 |
|
|
patricia->head = child; |
818 |
michael |
5042 |
} |
819 |
michael |
7834 |
else if (parent->parent->r == parent) |
820 |
|
|
{ |
821 |
|
|
parent->parent->r = child; |
822 |
|
|
} |
823 |
|
|
else |
824 |
|
|
{ |
825 |
|
|
assert(parent->parent->l == parent); |
826 |
|
|
parent->parent->l = child; |
827 |
|
|
} |
828 |
michael |
5042 |
|
829 |
michael |
7834 |
child->parent = parent->parent; |
830 |
|
|
xfree(parent); |
831 |
michael |
5042 |
patricia->num_active_node--; |
832 |
michael |
7834 |
return; |
833 |
|
|
} |
834 |
michael |
5042 |
|
835 |
michael |
7834 |
#ifdef PATRICIA_DEBUG |
836 |
|
|
fprintf(stderr, "patricia_remove: #2 %s/%d (r ^ l)\n", |
837 |
|
|
prefix_toa(node->prefix), node->prefix->bitlen); |
838 |
|
|
#endif /* PATRICIA_DEBUG */ |
839 |
michael |
5042 |
|
840 |
michael |
7834 |
if (node->r) |
841 |
|
|
{ |
842 |
|
|
child = node->r; |
843 |
|
|
} |
844 |
|
|
else |
845 |
|
|
{ |
846 |
|
|
assert(node->l); |
847 |
|
|
child = node->l; |
848 |
|
|
} |
849 |
|
|
|
850 |
|
|
parent = node->parent; |
851 |
|
|
child->parent = parent; |
852 |
|
|
|
853 |
|
|
Deref_Prefix(node->prefix); |
854 |
|
|
xfree(node); |
855 |
|
|
patricia->num_active_node--; |
856 |
|
|
|
857 |
|
|
if (parent == NULL) |
858 |
|
|
{ |
859 |
|
|
assert(patricia->head == node); |
860 |
|
|
patricia->head = child; |
861 |
|
|
return; |
862 |
|
|
} |
863 |
|
|
|
864 |
|
|
if (parent->r == node) |
865 |
|
|
{ |
866 |
|
|
parent->r = child; |
867 |
|
|
} |
868 |
|
|
else |
869 |
|
|
{ |
870 |
|
|
assert(parent->l == node); |
871 |
|
|
parent->l = child; |
872 |
|
|
} |
873 |
michael |
5042 |
} |
874 |
|
|
|
875 |
|
|
/* { from demo.c */ |
876 |
|
|
patricia_node_t * |
877 |
michael |
7834 |
make_and_lookup(patricia_tree_t *tree, const char *string) |
878 |
michael |
5042 |
{ |
879 |
michael |
7834 |
prefix_t *prefix = ascii2prefix(0, string); |
880 |
michael |
5042 |
|
881 |
michael |
7834 |
if (prefix) |
882 |
|
|
{ |
883 |
|
|
patricia_node_t *node = patricia_lookup(tree, prefix); |
884 |
|
|
Deref_Prefix(prefix); |
885 |
|
|
return node; |
886 |
|
|
} |
887 |
|
|
|
888 |
|
|
return NULL; |
889 |
michael |
5042 |
} |
890 |
|
|
|
891 |
|
|
patricia_node_t * |
892 |
michael |
7834 |
try_search_exact(patricia_tree_t *tree, const char *string) |
893 |
michael |
5042 |
{ |
894 |
michael |
7834 |
prefix_t *prefix = ascii2prefix(0, string); |
895 |
michael |
7809 |
|
896 |
michael |
7834 |
if (prefix) |
897 |
|
|
{ |
898 |
|
|
patricia_node_t *node = patricia_search_exact(tree, prefix); |
899 |
|
|
Deref_Prefix(prefix); |
900 |
|
|
return node; |
901 |
|
|
} |
902 |
|
|
|
903 |
|
|
return NULL; |
904 |
michael |
5042 |
} |
905 |
|
|
|
906 |
|
|
void |
907 |
michael |
7834 |
lookup_then_remove(patricia_tree_t *tree, const char *string) |
908 |
michael |
5042 |
{ |
909 |
michael |
7834 |
patricia_node_t *node; |
910 |
michael |
5042 |
|
911 |
michael |
7834 |
if ((node = try_search_exact(tree, string))) |
912 |
|
|
patricia_remove(tree, node); |
913 |
michael |
5042 |
} |
914 |
|
|
|
915 |
|
|
patricia_node_t * |
916 |
michael |
7834 |
try_search_best(patricia_tree_t *tree, const char *string) |
917 |
michael |
5042 |
{ |
918 |
michael |
7834 |
prefix_t *prefix = ascii2prefix(0, string); |
919 |
michael |
5042 |
|
920 |
michael |
7834 |
if (prefix) |
921 |
|
|
{ |
922 |
|
|
patricia_node_t *node = patricia_search_best(tree, prefix); |
923 |
|
|
Deref_Prefix(prefix); |
924 |
|
|
return node; |
925 |
|
|
} |
926 |
|
|
|
927 |
|
|
return NULL; |
928 |
michael |
5042 |
} |
929 |
|
|
/* } */ |