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