ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/patricia.c
Revision: 5044
Committed: Sat Dec 13 18:53:23 2014 UTC (11 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 24038 byte(s)
Log Message:
- patricia.c, patricia.h: ipv6 is mandatory

File Contents

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