ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/patricia.c
Revision: 5042
Committed: Sat Dec 13 18:19:17 2014 UTC (10 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 24820 byte(s)
Log Message:
- Added latest patricia.c, patricia.h from Net-Patricia-1.22 for later use

File Contents

# Content
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 /* } */