Annotation of libaitio/src/patricia.c, revision 1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>