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 |
/* this allows imcomplete prefix */ |
65 |
int |
66 |
my_inet_pton (int af, const char *src, void *dst) |
67 |
{ |
68 |
if (af == AF_INET) { |
69 |
int i, c, val; |
70 |
u_char xp[sizeof(struct in_addr)] = {0, 0, 0, 0}; |
71 |
|
72 |
for (i = 0; ; i++) { |
73 |
c = *src++; |
74 |
if (!isdigit (c)) |
75 |
return (-1); |
76 |
val = 0; |
77 |
do { |
78 |
val = val * 10 + c - '0'; |
79 |
if (val > 255) |
80 |
return (0); |
81 |
c = *src++; |
82 |
} while (c && isdigit (c)); |
83 |
xp[i] = val; |
84 |
if (c == '\0') |
85 |
break; |
86 |
if (c != '.') |
87 |
return (0); |
88 |
if (i >= 3) |
89 |
return (0); |
90 |
} |
91 |
memcpy (dst, xp, sizeof(struct in_addr)); |
92 |
return (1); |
93 |
#ifdef HAVE_IPV6 |
94 |
} else if (af == AF_INET6) { |
95 |
return (inet_pton (af, src, dst)); |
96 |
#endif /* HAVE_IPV6 */ |
97 |
} else { |
98 |
#ifndef NT |
99 |
errno = EAFNOSUPPORT; |
100 |
#endif /* NT */ |
101 |
return -1; |
102 |
} |
103 |
} |
104 |
|
105 |
#define PATRICIA_MAX_THREADS 16 |
106 |
|
107 |
/* |
108 |
* convert prefix information to ascii string with length |
109 |
* thread safe and (almost) re-entrant implementation |
110 |
*/ |
111 |
char * |
112 |
prefix_toa2x (prefix_t *prefix, char *buff, int with_len) |
113 |
{ |
114 |
if (prefix == NULL) |
115 |
return ("(Null)"); |
116 |
assert (prefix->ref_count >= 0); |
117 |
if (buff == NULL) { |
118 |
|
119 |
struct buffer { |
120 |
char buffs[PATRICIA_MAX_THREADS][48+5]; |
121 |
u_int i; |
122 |
} *buffp; |
123 |
|
124 |
# if 0 |
125 |
THREAD_SPECIFIC_DATA (struct buffer, buffp, 1); |
126 |
# else |
127 |
{ /* for scope only */ |
128 |
static struct buffer local_buff; |
129 |
buffp = &local_buff; |
130 |
} |
131 |
# endif |
132 |
if (buffp == NULL) { |
133 |
/* XXX should we report an error? */ |
134 |
return (NULL); |
135 |
} |
136 |
|
137 |
buff = buffp->buffs[buffp->i++%PATRICIA_MAX_THREADS]; |
138 |
} |
139 |
if (prefix->family == AF_INET) { |
140 |
u_char *a; |
141 |
assert (prefix->bitlen <= sizeof(struct in_addr) * 8); |
142 |
a = prefix_touchar (prefix); |
143 |
if (with_len) { |
144 |
sprintf (buff, "%d.%d.%d.%d/%d", a[0], a[1], a[2], a[3], |
145 |
prefix->bitlen); |
146 |
} |
147 |
else { |
148 |
sprintf (buff, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); |
149 |
} |
150 |
return (buff); |
151 |
} |
152 |
#ifdef HAVE_IPV6 |
153 |
else if (prefix->family == AF_INET6) { |
154 |
char *r; |
155 |
r = (char *) inet_ntop (AF_INET6, &prefix->add.sin6, buff, 48 /* a guess value */ ); |
156 |
if (r && with_len) { |
157 |
assert (prefix->bitlen <= sizeof(struct in6_addr) * 8); |
158 |
sprintf (buff + strlen (buff), "/%d", prefix->bitlen); |
159 |
} |
160 |
return (buff); |
161 |
} |
162 |
#endif /* HAVE_IPV6 */ |
163 |
else |
164 |
return (NULL); |
165 |
} |
166 |
|
167 |
/* prefix_toa2 |
168 |
* convert prefix information to ascii string |
169 |
*/ |
170 |
char * |
171 |
prefix_toa2 (prefix_t *prefix, char *buff) |
172 |
{ |
173 |
return (prefix_toa2x (prefix, buff, 0)); |
174 |
} |
175 |
|
176 |
/* prefix_toa |
177 |
*/ |
178 |
char * |
179 |
prefix_toa (prefix_t * prefix) |
180 |
{ |
181 |
return (prefix_toa2 (prefix, (char *) NULL)); |
182 |
} |
183 |
|
184 |
prefix_t * |
185 |
New_Prefix2 (int family, void *dest, int bitlen, prefix_t *prefix) |
186 |
{ |
187 |
int dynamic_allocated = 0; |
188 |
int default_bitlen = sizeof(struct in_addr) * 8; |
189 |
|
190 |
#ifdef HAVE_IPV6 |
191 |
if (family == AF_INET6) { |
192 |
default_bitlen = sizeof(struct in6_addr) * 8; |
193 |
if (prefix == NULL) { |
194 |
prefix = calloc(1, sizeof (prefix_t)); |
195 |
dynamic_allocated++; |
196 |
} |
197 |
memcpy (&prefix->add.sin6, dest, sizeof(struct in6_addr)); |
198 |
} |
199 |
else |
200 |
#endif /* HAVE_IPV6 */ |
201 |
if (family == AF_INET) { |
202 |
if (prefix == NULL) { |
203 |
#ifndef NT |
204 |
prefix = calloc(1, sizeof (prefix4_t)); |
205 |
#else |
206 |
//for some reason, compiler is getting |
207 |
//prefix4_t size incorrect on NT |
208 |
prefix = calloc(1, sizeof (prefix_t)); |
209 |
#endif /* NT */ |
210 |
|
211 |
dynamic_allocated++; |
212 |
} |
213 |
memcpy (&prefix->add.sin, dest, sizeof(struct in_addr)); |
214 |
} |
215 |
else { |
216 |
return (NULL); |
217 |
} |
218 |
|
219 |
prefix->bitlen = (bitlen >= 0)? bitlen: default_bitlen; |
220 |
prefix->family = family; |
221 |
prefix->ref_count = 0; |
222 |
if (dynamic_allocated) { |
223 |
prefix->ref_count++; |
224 |
} |
225 |
/* fprintf(stderr, "[C %s, %d]\n", prefix_toa (prefix), prefix->ref_count); */ |
226 |
return (prefix); |
227 |
} |
228 |
|
229 |
prefix_t * |
230 |
New_Prefix (int family, void *dest, int bitlen) |
231 |
{ |
232 |
return (New_Prefix2 (family, dest, bitlen, NULL)); |
233 |
} |
234 |
|
235 |
/* ascii2prefix |
236 |
*/ |
237 |
prefix_t * |
238 |
ascii2prefix (int family, char *string) |
239 |
{ |
240 |
u_long bitlen, maxbitlen = 0; |
241 |
char *cp; |
242 |
struct in_addr sin; |
243 |
#ifdef HAVE_IPV6 |
244 |
struct in6_addr sin6; |
245 |
#endif /* HAVE_IPV6 */ |
246 |
int result; |
247 |
char save[MAXLINE]; |
248 |
|
249 |
if (string == NULL) |
250 |
return (NULL); |
251 |
|
252 |
/* easy way to handle both families */ |
253 |
if (family == 0) { |
254 |
family = AF_INET; |
255 |
#ifdef HAVE_IPV6 |
256 |
if (strchr (string, ':')) family = AF_INET6; |
257 |
#endif /* HAVE_IPV6 */ |
258 |
} |
259 |
|
260 |
if (family == AF_INET) { |
261 |
maxbitlen = sizeof(struct in_addr) * 8; |
262 |
} |
263 |
#ifdef HAVE_IPV6 |
264 |
else if (family == AF_INET6) { |
265 |
maxbitlen = sizeof(struct in6_addr) * 8; |
266 |
} |
267 |
#endif /* HAVE_IPV6 */ |
268 |
|
269 |
if ((cp = strchr (string, '/')) != NULL) { |
270 |
bitlen = atol (cp + 1); |
271 |
/* *cp = '\0'; */ |
272 |
/* copy the string to save. Avoid destroying the string */ |
273 |
assert (cp - string < MAXLINE); |
274 |
memcpy (save, string, cp - string); |
275 |
save[cp - string] = '\0'; |
276 |
string = save; |
277 |
if (bitlen < 0 || bitlen > maxbitlen) |
278 |
bitlen = maxbitlen; |
279 |
} |
280 |
else { |
281 |
bitlen = maxbitlen; |
282 |
} |
283 |
|
284 |
if (family == AF_INET) { |
285 |
if ((result = my_inet_pton (AF_INET, string, &sin)) <= 0) |
286 |
return (NULL); |
287 |
return (New_Prefix (AF_INET, &sin, bitlen)); |
288 |
} |
289 |
|
290 |
#ifdef HAVE_IPV6 |
291 |
else if (family == AF_INET6) { |
292 |
// Get rid of this with next IPv6 upgrade |
293 |
#if defined(NT) && !defined(HAVE_INET_NTOP) |
294 |
inet6_addr(string, &sin6); |
295 |
return (New_Prefix (AF_INET6, &sin6, bitlen)); |
296 |
#else |
297 |
if ((result = inet_pton (AF_INET6, string, &sin6)) <= 0) |
298 |
return (NULL); |
299 |
#endif /* NT */ |
300 |
return (New_Prefix (AF_INET6, &sin6, bitlen)); |
301 |
} |
302 |
#endif /* HAVE_IPV6 */ |
303 |
else |
304 |
return (NULL); |
305 |
} |
306 |
|
307 |
prefix_t * |
308 |
Ref_Prefix (prefix_t * prefix) |
309 |
{ |
310 |
if (prefix == NULL) |
311 |
return (NULL); |
312 |
if (prefix->ref_count == 0) { |
313 |
/* make a copy in case of a static prefix */ |
314 |
return (New_Prefix2 (prefix->family, &prefix->add, prefix->bitlen, NULL)); |
315 |
} |
316 |
prefix->ref_count++; |
317 |
/* fprintf(stderr, "[A %s, %d]\n", prefix_toa (prefix), prefix->ref_count); */ |
318 |
return (prefix); |
319 |
} |
320 |
|
321 |
void |
322 |
Deref_Prefix (prefix_t * prefix) |
323 |
{ |
324 |
if (prefix == NULL) |
325 |
return; |
326 |
/* for secure programming, raise an assert. no static prefix can call this */ |
327 |
assert (prefix->ref_count > 0); |
328 |
|
329 |
prefix->ref_count--; |
330 |
assert (prefix->ref_count >= 0); |
331 |
if (prefix->ref_count <= 0) { |
332 |
Delete (prefix); |
333 |
return; |
334 |
} |
335 |
} |
336 |
|
337 |
/* } */ |
338 |
|
339 |
/* #define PATRICIA_DEBUG 1 */ |
340 |
|
341 |
static int num_active_patricia = 0; |
342 |
|
343 |
/* these routines support continuous mask only */ |
344 |
|
345 |
patricia_tree_t * |
346 |
New_Patricia (int maxbits) |
347 |
{ |
348 |
patricia_tree_t *patricia = calloc(1, sizeof *patricia); |
349 |
|
350 |
patricia->maxbits = maxbits; |
351 |
patricia->head = NULL; |
352 |
patricia->num_active_node = 0; |
353 |
assert (maxbits <= PATRICIA_MAXBITS); /* XXX */ |
354 |
num_active_patricia++; |
355 |
return (patricia); |
356 |
} |
357 |
|
358 |
|
359 |
/* |
360 |
* if func is supplied, it will be called as func(node->data) |
361 |
* before deleting the node |
362 |
*/ |
363 |
|
364 |
void |
365 |
Clear_Patricia (patricia_tree_t *patricia, void_fn_t func) |
366 |
{ |
367 |
assert (patricia); |
368 |
if (patricia->head) { |
369 |
|
370 |
patricia_node_t *Xstack[PATRICIA_MAXBITS+1]; |
371 |
patricia_node_t **Xsp = Xstack; |
372 |
patricia_node_t *Xrn = patricia->head; |
373 |
|
374 |
while (Xrn) { |
375 |
patricia_node_t *l = Xrn->l; |
376 |
patricia_node_t *r = Xrn->r; |
377 |
|
378 |
if (Xrn->prefix) { |
379 |
Deref_Prefix (Xrn->prefix); |
380 |
if (Xrn->data && func) |
381 |
func (Xrn->data); |
382 |
} |
383 |
else { |
384 |
assert (Xrn->data == NULL); |
385 |
} |
386 |
Delete (Xrn); |
387 |
patricia->num_active_node--; |
388 |
|
389 |
if (l) { |
390 |
if (r) { |
391 |
*Xsp++ = r; |
392 |
} |
393 |
Xrn = l; |
394 |
} else if (r) { |
395 |
Xrn = r; |
396 |
} else if (Xsp != Xstack) { |
397 |
Xrn = *(--Xsp); |
398 |
} else { |
399 |
Xrn = NULL; |
400 |
} |
401 |
} |
402 |
} |
403 |
assert (patricia->num_active_node == 0); |
404 |
/* Delete (patricia); */ |
405 |
} |
406 |
|
407 |
|
408 |
void |
409 |
Destroy_Patricia (patricia_tree_t *patricia, void_fn_t func) |
410 |
{ |
411 |
Clear_Patricia (patricia, func); |
412 |
Delete (patricia); |
413 |
num_active_patricia--; |
414 |
} |
415 |
|
416 |
|
417 |
/* |
418 |
* if func is supplied, it will be called as func(node->prefix, node->data) |
419 |
*/ |
420 |
|
421 |
void |
422 |
patricia_process (patricia_tree_t *patricia, void_fn_t func) |
423 |
{ |
424 |
patricia_node_t *node; |
425 |
assert (func); |
426 |
|
427 |
PATRICIA_WALK (patricia->head, node) { |
428 |
func (node->prefix, node->data); |
429 |
} PATRICIA_WALK_END; |
430 |
} |
431 |
|
432 |
size_t |
433 |
patricia_walk_inorder(patricia_node_t *node, void_fn_t func) |
434 |
{ |
435 |
size_t n = 0; |
436 |
assert(func); |
437 |
|
438 |
if (node->l) { |
439 |
n += patricia_walk_inorder(node->l, func); |
440 |
} |
441 |
|
442 |
if (node->prefix) { |
443 |
func(node->prefix, node->data); |
444 |
n++; |
445 |
} |
446 |
|
447 |
if (node->r) { |
448 |
n += patricia_walk_inorder(node->r, func); |
449 |
} |
450 |
|
451 |
return n; |
452 |
} |
453 |
|
454 |
|
455 |
patricia_node_t * |
456 |
patricia_search_exact (patricia_tree_t *patricia, prefix_t *prefix) |
457 |
{ |
458 |
patricia_node_t *node; |
459 |
u_char *addr; |
460 |
u_int bitlen; |
461 |
|
462 |
assert (patricia); |
463 |
assert (prefix); |
464 |
assert (prefix->bitlen <= patricia->maxbits); |
465 |
|
466 |
if (patricia->head == NULL) |
467 |
return (NULL); |
468 |
|
469 |
node = patricia->head; |
470 |
addr = prefix_touchar (prefix); |
471 |
bitlen = prefix->bitlen; |
472 |
|
473 |
while (node->bit < bitlen) { |
474 |
|
475 |
if (BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { |
476 |
#ifdef PATRICIA_DEBUG |
477 |
if (node->prefix) |
478 |
fprintf (stderr, "patricia_search_exact: take right %s/%d\n", |
479 |
prefix_toa (node->prefix), node->prefix->bitlen); |
480 |
else |
481 |
fprintf (stderr, "patricia_search_exact: take right at %u\n", |
482 |
node->bit); |
483 |
#endif /* PATRICIA_DEBUG */ |
484 |
node = node->r; |
485 |
} |
486 |
else { |
487 |
#ifdef PATRICIA_DEBUG |
488 |
if (node->prefix) |
489 |
fprintf (stderr, "patricia_search_exact: take left %s/%d\n", |
490 |
prefix_toa (node->prefix), node->prefix->bitlen); |
491 |
else |
492 |
fprintf (stderr, "patricia_search_exact: take left at %u\n", |
493 |
node->bit); |
494 |
#endif /* PATRICIA_DEBUG */ |
495 |
node = node->l; |
496 |
} |
497 |
|
498 |
if (node == NULL) |
499 |
return (NULL); |
500 |
} |
501 |
|
502 |
#ifdef PATRICIA_DEBUG |
503 |
if (node->prefix) |
504 |
fprintf (stderr, "patricia_search_exact: stop at %s/%d\n", |
505 |
prefix_toa (node->prefix), node->prefix->bitlen); |
506 |
else |
507 |
fprintf (stderr, "patricia_search_exact: stop at %u\n", node->bit); |
508 |
#endif /* PATRICIA_DEBUG */ |
509 |
if (node->bit > bitlen || node->prefix == NULL) |
510 |
return (NULL); |
511 |
assert (node->bit == bitlen); |
512 |
assert (node->bit == node->prefix->bitlen); |
513 |
if (comp_with_mask (prefix_tochar (node->prefix), prefix_tochar (prefix), |
514 |
bitlen)) { |
515 |
#ifdef PATRICIA_DEBUG |
516 |
fprintf (stderr, "patricia_search_exact: found %s/%d\n", |
517 |
prefix_toa (node->prefix), node->prefix->bitlen); |
518 |
#endif /* PATRICIA_DEBUG */ |
519 |
return (node); |
520 |
} |
521 |
return (NULL); |
522 |
} |
523 |
|
524 |
|
525 |
/* if inclusive != 0, "best" may be the given prefix itself */ |
526 |
patricia_node_t * |
527 |
patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, int inclusive) |
528 |
{ |
529 |
patricia_node_t *node; |
530 |
patricia_node_t *stack[PATRICIA_MAXBITS + 1]; |
531 |
u_char *addr; |
532 |
u_int bitlen; |
533 |
int cnt = 0; |
534 |
|
535 |
assert (patricia); |
536 |
assert (prefix); |
537 |
assert (prefix->bitlen <= patricia->maxbits); |
538 |
|
539 |
if (patricia->head == NULL) |
540 |
return (NULL); |
541 |
|
542 |
node = patricia->head; |
543 |
addr = prefix_touchar (prefix); |
544 |
bitlen = prefix->bitlen; |
545 |
|
546 |
while (node->bit < bitlen) { |
547 |
|
548 |
if (node->prefix) { |
549 |
#ifdef PATRICIA_DEBUG |
550 |
fprintf (stderr, "patricia_search_best: push %s/%d\n", |
551 |
prefix_toa (node->prefix), node->prefix->bitlen); |
552 |
#endif /* PATRICIA_DEBUG */ |
553 |
stack[cnt++] = node; |
554 |
} |
555 |
|
556 |
if (BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { |
557 |
#ifdef PATRICIA_DEBUG |
558 |
if (node->prefix) |
559 |
fprintf (stderr, "patricia_search_best: take right %s/%d\n", |
560 |
prefix_toa (node->prefix), node->prefix->bitlen); |
561 |
else |
562 |
fprintf (stderr, "patricia_search_best: take right at %u\n", |
563 |
node->bit); |
564 |
#endif /* PATRICIA_DEBUG */ |
565 |
node = node->r; |
566 |
} |
567 |
else { |
568 |
#ifdef PATRICIA_DEBUG |
569 |
if (node->prefix) |
570 |
fprintf (stderr, "patricia_search_best: take left %s/%d\n", |
571 |
prefix_toa (node->prefix), node->prefix->bitlen); |
572 |
else |
573 |
fprintf (stderr, "patricia_search_best: take left at %u\n", |
574 |
node->bit); |
575 |
#endif /* PATRICIA_DEBUG */ |
576 |
node = node->l; |
577 |
} |
578 |
|
579 |
if (node == NULL) |
580 |
break; |
581 |
} |
582 |
|
583 |
if (inclusive && node && node->prefix) |
584 |
stack[cnt++] = node; |
585 |
|
586 |
#ifdef PATRICIA_DEBUG |
587 |
if (node == NULL) |
588 |
fprintf (stderr, "patricia_search_best: stop at null\n"); |
589 |
else if (node->prefix) |
590 |
fprintf (stderr, "patricia_search_best: stop at %s/%d\n", |
591 |
prefix_toa (node->prefix), node->prefix->bitlen); |
592 |
else |
593 |
fprintf (stderr, "patricia_search_best: stop at %u\n", node->bit); |
594 |
#endif /* PATRICIA_DEBUG */ |
595 |
|
596 |
if (cnt <= 0) |
597 |
return (NULL); |
598 |
|
599 |
while (--cnt >= 0) { |
600 |
node = stack[cnt]; |
601 |
#ifdef PATRICIA_DEBUG |
602 |
fprintf (stderr, "patricia_search_best: pop %s/%d\n", |
603 |
prefix_toa (node->prefix), node->prefix->bitlen); |
604 |
#endif /* PATRICIA_DEBUG */ |
605 |
if (comp_with_mask (prefix_tochar (node->prefix), |
606 |
prefix_tochar (prefix), |
607 |
node->prefix->bitlen) && node->prefix->bitlen <= bitlen) { |
608 |
#ifdef PATRICIA_DEBUG |
609 |
fprintf (stderr, "patricia_search_best: found %s/%d\n", |
610 |
prefix_toa (node->prefix), node->prefix->bitlen); |
611 |
#endif /* PATRICIA_DEBUG */ |
612 |
return (node); |
613 |
} |
614 |
} |
615 |
return (NULL); |
616 |
} |
617 |
|
618 |
|
619 |
patricia_node_t * |
620 |
patricia_search_best (patricia_tree_t *patricia, prefix_t *prefix) |
621 |
{ |
622 |
return (patricia_search_best2 (patricia, prefix, 1)); |
623 |
} |
624 |
|
625 |
|
626 |
patricia_node_t * |
627 |
patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix) |
628 |
{ |
629 |
patricia_node_t *node, *new_node, *parent, *glue; |
630 |
u_char *addr, *test_addr; |
631 |
u_int bitlen, check_bit, differ_bit; |
632 |
int i, j, r; |
633 |
|
634 |
assert (patricia); |
635 |
assert (prefix); |
636 |
assert (prefix->bitlen <= patricia->maxbits); |
637 |
|
638 |
if (patricia->head == NULL) { |
639 |
node = calloc(1, sizeof *node); |
640 |
node->bit = prefix->bitlen; |
641 |
node->prefix = Ref_Prefix (prefix); |
642 |
node->parent = NULL; |
643 |
node->l = node->r = NULL; |
644 |
node->data = NULL; |
645 |
patricia->head = node; |
646 |
#ifdef PATRICIA_DEBUG |
647 |
fprintf (stderr, "patricia_lookup: new_node #0 %s/%d (head)\n", |
648 |
prefix_toa (prefix), prefix->bitlen); |
649 |
#endif /* PATRICIA_DEBUG */ |
650 |
patricia->num_active_node++; |
651 |
return (node); |
652 |
} |
653 |
|
654 |
addr = prefix_touchar (prefix); |
655 |
bitlen = prefix->bitlen; |
656 |
node = patricia->head; |
657 |
|
658 |
while (node->bit < bitlen || node->prefix == NULL) { |
659 |
|
660 |
if (node->bit < patricia->maxbits && |
661 |
BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { |
662 |
if (node->r == NULL) |
663 |
break; |
664 |
#ifdef PATRICIA_DEBUG |
665 |
if (node->prefix) |
666 |
fprintf (stderr, "patricia_lookup: take right %s/%d\n", |
667 |
prefix_toa (node->prefix), node->prefix->bitlen); |
668 |
else |
669 |
fprintf (stderr, "patricia_lookup: take right at %u\n", node->bit); |
670 |
#endif /* PATRICIA_DEBUG */ |
671 |
node = node->r; |
672 |
} |
673 |
else { |
674 |
if (node->l == NULL) |
675 |
break; |
676 |
#ifdef PATRICIA_DEBUG |
677 |
if (node->prefix) |
678 |
fprintf (stderr, "patricia_lookup: take left %s/%d\n", |
679 |
prefix_toa (node->prefix), node->prefix->bitlen); |
680 |
else |
681 |
fprintf (stderr, "patricia_lookup: take left at %u\n", node->bit); |
682 |
#endif /* PATRICIA_DEBUG */ |
683 |
node = node->l; |
684 |
} |
685 |
|
686 |
assert (node); |
687 |
} |
688 |
|
689 |
assert (node->prefix); |
690 |
#ifdef PATRICIA_DEBUG |
691 |
fprintf (stderr, "patricia_lookup: stop at %s/%d\n", |
692 |
prefix_toa (node->prefix), node->prefix->bitlen); |
693 |
#endif /* PATRICIA_DEBUG */ |
694 |
|
695 |
test_addr = prefix_touchar (node->prefix); |
696 |
/* find the first bit different */ |
697 |
check_bit = (node->bit < bitlen)? node->bit: bitlen; |
698 |
differ_bit = 0; |
699 |
for (i = 0; i*8 < check_bit; i++) { |
700 |
if ((r = (addr[i] ^ test_addr[i])) == 0) { |
701 |
differ_bit = (i + 1) * 8; |
702 |
continue; |
703 |
} |
704 |
/* I know the better way, but for now */ |
705 |
for (j = 0; j < 8; j++) { |
706 |
if (BIT_TEST (r, (0x80 >> j))) |
707 |
break; |
708 |
} |
709 |
/* must be found */ |
710 |
assert (j < 8); |
711 |
differ_bit = i * 8 + j; |
712 |
break; |
713 |
} |
714 |
if (differ_bit > check_bit) |
715 |
differ_bit = check_bit; |
716 |
#ifdef PATRICIA_DEBUG |
717 |
fprintf (stderr, "patricia_lookup: differ_bit %d\n", differ_bit); |
718 |
#endif /* PATRICIA_DEBUG */ |
719 |
|
720 |
parent = node->parent; |
721 |
while (parent && parent->bit >= differ_bit) { |
722 |
node = parent; |
723 |
parent = node->parent; |
724 |
#ifdef PATRICIA_DEBUG |
725 |
if (node->prefix) |
726 |
fprintf (stderr, "patricia_lookup: up to %s/%d\n", |
727 |
prefix_toa (node->prefix), node->prefix->bitlen); |
728 |
else |
729 |
fprintf (stderr, "patricia_lookup: up to %u\n", node->bit); |
730 |
#endif /* PATRICIA_DEBUG */ |
731 |
} |
732 |
|
733 |
if (differ_bit == bitlen && node->bit == bitlen) { |
734 |
if (node->prefix) { |
735 |
#ifdef PATRICIA_DEBUG |
736 |
fprintf (stderr, "patricia_lookup: found %s/%d\n", |
737 |
prefix_toa (node->prefix), node->prefix->bitlen); |
738 |
#endif /* PATRICIA_DEBUG */ |
739 |
return (node); |
740 |
} |
741 |
node->prefix = Ref_Prefix (prefix); |
742 |
#ifdef PATRICIA_DEBUG |
743 |
fprintf (stderr, "patricia_lookup: new node #1 %s/%d (glue mod)\n", |
744 |
prefix_toa (prefix), prefix->bitlen); |
745 |
#endif /* PATRICIA_DEBUG */ |
746 |
assert (node->data == NULL); |
747 |
return (node); |
748 |
} |
749 |
|
750 |
new_node = calloc(1, sizeof *new_node); |
751 |
new_node->bit = prefix->bitlen; |
752 |
new_node->prefix = Ref_Prefix (prefix); |
753 |
new_node->parent = NULL; |
754 |
new_node->l = new_node->r = NULL; |
755 |
new_node->data = NULL; |
756 |
patricia->num_active_node++; |
757 |
|
758 |
if (node->bit == differ_bit) { |
759 |
new_node->parent = node; |
760 |
if (node->bit < patricia->maxbits && |
761 |
BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { |
762 |
assert (node->r == NULL); |
763 |
node->r = new_node; |
764 |
} |
765 |
else { |
766 |
assert (node->l == NULL); |
767 |
node->l = new_node; |
768 |
} |
769 |
#ifdef PATRICIA_DEBUG |
770 |
fprintf (stderr, "patricia_lookup: new_node #2 %s/%d (child)\n", |
771 |
prefix_toa (prefix), prefix->bitlen); |
772 |
#endif /* PATRICIA_DEBUG */ |
773 |
return (new_node); |
774 |
} |
775 |
|
776 |
if (bitlen == differ_bit) { |
777 |
if (bitlen < patricia->maxbits && |
778 |
BIT_TEST (test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07))) { |
779 |
new_node->r = node; |
780 |
} |
781 |
else { |
782 |
new_node->l = node; |
783 |
} |
784 |
new_node->parent = node->parent; |
785 |
if (node->parent == NULL) { |
786 |
assert (patricia->head == node); |
787 |
patricia->head = new_node; |
788 |
} |
789 |
else if (node->parent->r == node) { |
790 |
node->parent->r = new_node; |
791 |
} |
792 |
else { |
793 |
node->parent->l = new_node; |
794 |
} |
795 |
node->parent = new_node; |
796 |
#ifdef PATRICIA_DEBUG |
797 |
fprintf (stderr, "patricia_lookup: new_node #3 %s/%d (parent)\n", |
798 |
prefix_toa (prefix), prefix->bitlen); |
799 |
#endif /* PATRICIA_DEBUG */ |
800 |
} |
801 |
else { |
802 |
glue = calloc(1, sizeof *glue); |
803 |
glue->bit = differ_bit; |
804 |
glue->prefix = NULL; |
805 |
glue->parent = node->parent; |
806 |
glue->data = NULL; |
807 |
patricia->num_active_node++; |
808 |
if (differ_bit < patricia->maxbits && |
809 |
BIT_TEST (addr[differ_bit >> 3], 0x80 >> (differ_bit & 0x07))) { |
810 |
glue->r = new_node; |
811 |
glue->l = node; |
812 |
} |
813 |
else { |
814 |
glue->r = node; |
815 |
glue->l = new_node; |
816 |
} |
817 |
new_node->parent = glue; |
818 |
|
819 |
if (node->parent == NULL) { |
820 |
assert (patricia->head == node); |
821 |
patricia->head = glue; |
822 |
} |
823 |
else if (node->parent->r == node) { |
824 |
node->parent->r = glue; |
825 |
} |
826 |
else { |
827 |
node->parent->l = glue; |
828 |
} |
829 |
node->parent = glue; |
830 |
#ifdef PATRICIA_DEBUG |
831 |
fprintf (stderr, "patricia_lookup: new_node #4 %s/%d (glue+node)\n", |
832 |
prefix_toa (prefix), prefix->bitlen); |
833 |
#endif /* PATRICIA_DEBUG */ |
834 |
} |
835 |
return (new_node); |
836 |
} |
837 |
|
838 |
|
839 |
void |
840 |
patricia_remove (patricia_tree_t *patricia, patricia_node_t *node) |
841 |
{ |
842 |
patricia_node_t *parent, *child; |
843 |
|
844 |
assert (patricia); |
845 |
assert (node); |
846 |
|
847 |
if (node->r && node->l) { |
848 |
#ifdef PATRICIA_DEBUG |
849 |
fprintf (stderr, "patricia_remove: #0 %s/%d (r & l)\n", |
850 |
prefix_toa (node->prefix), node->prefix->bitlen); |
851 |
#endif /* PATRICIA_DEBUG */ |
852 |
|
853 |
/* this might be a placeholder node -- have to check and make sure |
854 |
* there is a prefix aossciated with it ! */ |
855 |
if (node->prefix != NULL) |
856 |
Deref_Prefix (node->prefix); |
857 |
node->prefix = NULL; |
858 |
/* Also I needed to clear data pointer -- masaki */ |
859 |
node->data = NULL; |
860 |
return; |
861 |
} |
862 |
|
863 |
if (node->r == NULL && node->l == NULL) { |
864 |
#ifdef PATRICIA_DEBUG |
865 |
fprintf (stderr, "patricia_remove: #1 %s/%d (!r & !l)\n", |
866 |
prefix_toa (node->prefix), node->prefix->bitlen); |
867 |
#endif /* PATRICIA_DEBUG */ |
868 |
parent = node->parent; |
869 |
Deref_Prefix (node->prefix); |
870 |
Delete (node); |
871 |
patricia->num_active_node--; |
872 |
|
873 |
if (parent == NULL) { |
874 |
assert (patricia->head == node); |
875 |
patricia->head = NULL; |
876 |
return; |
877 |
} |
878 |
|
879 |
if (parent->r == node) { |
880 |
parent->r = NULL; |
881 |
child = parent->l; |
882 |
} |
883 |
else { |
884 |
assert (parent->l == node); |
885 |
parent->l = NULL; |
886 |
child = parent->r; |
887 |
} |
888 |
|
889 |
if (parent->prefix) |
890 |
return; |
891 |
|
892 |
/* we need to remove parent too */ |
893 |
|
894 |
if (parent->parent == NULL) { |
895 |
assert (patricia->head == parent); |
896 |
patricia->head = child; |
897 |
} |
898 |
else if (parent->parent->r == parent) { |
899 |
parent->parent->r = child; |
900 |
} |
901 |
else { |
902 |
assert (parent->parent->l == parent); |
903 |
parent->parent->l = child; |
904 |
} |
905 |
child->parent = parent->parent; |
906 |
Delete (parent); |
907 |
patricia->num_active_node--; |
908 |
return; |
909 |
} |
910 |
|
911 |
#ifdef PATRICIA_DEBUG |
912 |
fprintf (stderr, "patricia_remove: #2 %s/%d (r ^ l)\n", |
913 |
prefix_toa (node->prefix), node->prefix->bitlen); |
914 |
#endif /* PATRICIA_DEBUG */ |
915 |
if (node->r) { |
916 |
child = node->r; |
917 |
} |
918 |
else { |
919 |
assert (node->l); |
920 |
child = node->l; |
921 |
} |
922 |
parent = node->parent; |
923 |
child->parent = parent; |
924 |
|
925 |
Deref_Prefix (node->prefix); |
926 |
Delete (node); |
927 |
patricia->num_active_node--; |
928 |
|
929 |
if (parent == NULL) { |
930 |
assert (patricia->head == node); |
931 |
patricia->head = child; |
932 |
return; |
933 |
} |
934 |
|
935 |
if (parent->r == node) { |
936 |
parent->r = child; |
937 |
} |
938 |
else { |
939 |
assert (parent->l == node); |
940 |
parent->l = child; |
941 |
} |
942 |
} |
943 |
|
944 |
/* { from demo.c */ |
945 |
|
946 |
patricia_node_t * |
947 |
make_and_lookup (patricia_tree_t *tree, char *string) |
948 |
{ |
949 |
prefix_t *prefix; |
950 |
patricia_node_t *node; |
951 |
|
952 |
prefix = ascii2prefix (AF_INET, string); |
953 |
printf ("make_and_lookup: %s/%d\n", prefix_toa (prefix), prefix->bitlen); |
954 |
node = patricia_lookup (tree, prefix); |
955 |
Deref_Prefix (prefix); |
956 |
return (node); |
957 |
} |
958 |
|
959 |
patricia_node_t * |
960 |
try_search_exact (patricia_tree_t *tree, char *string) |
961 |
{ |
962 |
prefix_t *prefix; |
963 |
patricia_node_t *node; |
964 |
|
965 |
prefix = ascii2prefix (AF_INET, string); |
966 |
printf ("try_search_exact: %s/%d\n", prefix_toa (prefix), prefix->bitlen); |
967 |
if ((node = patricia_search_exact (tree, prefix)) == NULL) { |
968 |
printf ("try_search_exact: not found\n"); |
969 |
} |
970 |
else { |
971 |
printf ("try_search_exact: %s/%d found\n", |
972 |
prefix_toa (node->prefix), node->prefix->bitlen); |
973 |
} |
974 |
Deref_Prefix (prefix); |
975 |
return (node); |
976 |
} |
977 |
|
978 |
void |
979 |
lookup_then_remove (patricia_tree_t *tree, char *string) |
980 |
{ |
981 |
patricia_node_t *node; |
982 |
|
983 |
if ((node = try_search_exact (tree, string))) |
984 |
patricia_remove (tree, node); |
985 |
} |
986 |
|
987 |
patricia_node_t * |
988 |
try_search_best (patricia_tree_t *tree, char *string) |
989 |
{ |
990 |
prefix_t *prefix; |
991 |
patricia_node_t *node; |
992 |
|
993 |
prefix = ascii2prefix (AF_INET, string); |
994 |
printf ("try_search_best: %s/%d\n", prefix_toa (prefix), prefix->bitlen); |
995 |
if ((node = patricia_search_best (tree, prefix)) == NULL) |
996 |
printf ("try_search_best: not found\n"); |
997 |
else |
998 |
printf ("try_search_best: %s/%d found\n", |
999 |
prefix_toa (node->prefix), node->prefix->bitlen); |
1000 |
Deref_Prefix (prefix); |
1001 |
return (node); |
1002 |
} |
1003 |
|
1004 |
/* } */ |