ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/patricia.c
Revision: 7824
Committed: Thu Oct 20 17:54:54 2016 UTC (9 years, 9 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/src/patricia.c
File size: 23654 byte(s)
Log Message:
- patricia.h, patricia.c: cleanup prefix_toa() to fit our needs; make it use snprintf()

File Contents

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

Properties

Name Value
svn:eol-style native
svn:keywords Id