radix.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/*
10 * Copyright (c) 1988, 1989, 1993
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)radix.c 8.4 (Berkeley) 11/2/94
38 */
39
40/*
41 * DEBUG: section 53 Radix Tree data structure implementation
42 */
43
44#include "squid.h"
45#include "radix.h"
46#include "util.h"
47
48#if HAVE_UNISTD_H
49#include <unistd.h>
50#endif
51#if HAVE_STDLIB_H
52#include <stdlib.h>
53#endif
54#if HAVE_SYS_TYPES_H
55#include <sys/types.h>
56#endif
57#if HAVE_CTYPE_H
58#include <ctype.h>
59#endif
60#if HAVE_ERRNO_H
61#include <errno.h>
62#endif
63#if HAVE_FCNTL_H
64#include <fcntl.h>
65#endif
66#if HAVE_GRP_H
67#include <grp.h>
68#endif
69#if HAVE_GNUMALLOC_H
70#include <gnumalloc.h>
71#elif HAVE_MALLOC_H
72#include <malloc.h>
73#endif
74#if HAVE_MEMORY_H
75#include <memory.h>
76#endif
77#if HAVE_SYS_PARAM_H
78#include <sys/param.h>
79#endif
80#if HAVE_ASSERT_H
81#include <assert.h>
82#endif
83
87static char *addmask_key;
88static unsigned char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xFF};
89static char *rn_zeros, *rn_ones;
90
91/* aliases */
92#define rn_masktop (squid_mask_rnhead->rnh_treetop)
93#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey
94#define rn_off rn_u.rn_node.rn_Off
95#define rn_l rn_u.rn_node.rn_L
96#define rn_r rn_u.rn_node.rn_R
97#define rm_mask rm_rmu.rmu_mask
98#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */
99
100/* Helper macros */
101#define squid_R_Malloc(p, t, n) (p = (t) xmalloc((unsigned int)(n)))
102#define squid_Free(p) xfree((char *)p)
103#define squid_MKGet(m) {\
104 if (squid_rn_mkfreelist) {\
105 m = squid_rn_mkfreelist; \
106 squid_rn_mkfreelist = (m)->rm_mklist; \
107 } else \
108 squid_R_Malloc(m, struct squid_radix_mask *, sizeof (*(m)));\
109 }
110
111#define squid_MKFree(m) { (m)->rm_mklist = squid_rn_mkfreelist; squid_rn_mkfreelist = (m);}
112
113#ifndef min
114#define min(x,y) ((x)<(y)? (x) : (y))
115#endif
116/*
117 * The data structure for the keys is a radix tree with one way
118 * branching removed. The index rn_b at an internal node n represents a bit
119 * position to be tested. The tree is arranged so that all descendants
120 * of a node n have keys whose bits all agree up to position rn_b - 1.
121 * (We say the index of n is rn_b.)
122 *
123 * There is at least one descendant which has a one bit at position rn_b,
124 * and at least one with a zero there.
125 *
126 * A route is determined by a pair of key and mask. We require that the
127 * bit-wise logical and of the key and mask to be the key.
128 * We define the index of a route to associated with the mask to be
129 * the first bit number in the mask where 0 occurs (with bit number 0
130 * representing the highest order bit).
131 *
132 * We say a mask is normal if every bit is 0, past the index of the mask.
133 * If a node n has a descendant (k, m) with index(m) == index(n) == rn_b,
134 * and m is a normal mask, then the route applies to every descendant of n.
135 * If the index(m) < rn_b, this implies the trailing last few bits of k
136 * before bit b are all 0, (and hence consequently true of every descendant
137 * of n), so the route applies to all descendants of the node as well.
138 *
139 * Similar logic shows that a non-normal mask m such that
140 * index(m) <= index(n) could potentially apply to many children of n.
141 * Thus, for each non-host route, we attach its mask to a list at an internal
142 * node as high in the tree as we can go.
143 *
144 * The present version of the code makes use of normal routes in short-
145 * circuiting an explicit mask and compare operation when testing whether
146 * a key satisfies a normal route, and also in remembering the unique leaf
147 * that governs a subtree.
148 */
149
150struct squid_radix_node *
151squid_rn_search(void *v_arg, struct squid_radix_node *head) {
152 register struct squid_radix_node *x;
153 register char *v;
154
155 for (x = head, v = v_arg; x->rn_b >= 0;) {
156 if (x->rn_bmask & v[x->rn_off])
157 x = x->rn_r;
158 else
159 x = x->rn_l;
160 }
161 return (x);
162}
163
164struct squid_radix_node *
165squid_rn_search_m(void *v_arg, struct squid_radix_node *head, void *m_arg) {
166 register struct squid_radix_node *x;
167 register char *v = v_arg, *m = m_arg;
168
169 for (x = head; x->rn_b >= 0;) {
170 if ((x->rn_bmask & m[x->rn_off]) &&
171 (x->rn_bmask & v[x->rn_off]))
172 x = x->rn_r;
173 else
174 x = x->rn_l;
175 }
176 return x;
177}
178
179int
180squid_rn_refines(void *m_arg, void *n_arg)
181{
182 register char *m = m_arg, *n = n_arg;
183 register char *lim, *lim2 = lim = n + *(u_char *) n;
184 int longer = (*(u_char *) n++) - (int) (*(u_char *) m++);
185 int masks_are_equal = 1;
186
187 if (longer > 0)
188 lim -= longer;
189 while (n < lim) {
190 if (*n & ~(*m))
191 return 0;
192 if (*n++ != *m++)
193 masks_are_equal = 0;
194 }
195 while (n < lim2)
196 if (*n++)
197 return 0;
198 if (masks_are_equal && (longer < 0))
199 for (lim2 = m - longer; m < lim2;)
200 if (*m++)
201 return 1;
202 return (!masks_are_equal);
203}
204
205struct squid_radix_node *
206squid_rn_lookup(void *v_arg, void *m_arg, struct squid_radix_node_head *head) {
207 register struct squid_radix_node *x;
208 char *netmask = NULL;
209
210 if (m_arg) {
211 if ((x = squid_rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0)
212 return (0);
213 netmask = x->rn_key;
214 }
215 x = squid_rn_match(v_arg, head);
216 if (x && netmask) {
217 while (x && x->rn_mask != netmask)
218 x = x->rn_dupedkey;
219 }
220 return x;
221}
222
223static int
224rn_satsifies_leaf(char *trial, register struct squid_radix_node *leaf, int skip)
225{
226 register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
227 char *cplim;
228 int length = min(*(u_char *) cp, *(u_char *) cp2);
229
230 if (cp3 == 0)
231 cp3 = rn_ones;
232 else
233 length = min(length, *(u_char *) cp3);
234 cplim = cp + length;
235 cp3 += skip;
236 cp2 += skip;
237 for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
238 if ((*cp ^ *cp2) & *cp3)
239 return 0;
240 return 1;
241}
242
243struct squid_radix_node *
245 char *v = v_arg;
246 register struct squid_radix_node *t = head->rnh_treetop, *x;
247 register char *cp = v, *cp2;
248 char *cplim;
249 struct squid_radix_node *saved_t, *top = t;
250 int off = t->rn_off, vlen = *(u_char *) cp, matched_off;
251 register int test, b, rn_b;
252
253 /*
254 * Open code squid_rn_search(v, top) to avoid overhead of extra
255 * subroutine call.
256 */
257 for (; t->rn_b >= 0;) {
258 if (t->rn_bmask & cp[t->rn_off])
259 t = t->rn_r;
260 else
261 t = t->rn_l;
262 }
263 /*
264 * See if we match exactly as a host destination
265 * or at least learn how many bits match, for normal mask finesse.
266 *
267 * It doesn't hurt us to limit how many bytes to check
268 * to the length of the mask, since if it matches we had a genuine
269 * match and the leaf we have is the most specific one anyway;
270 * if it didn't match with a shorter length it would fail
271 * with a long one. This wins big for class B&C netmasks which
272 * are probably the most common case...
273 */
274 if (t->rn_mask)
275 vlen = *(u_char *) t->rn_mask;
276 cp += off;
277 cp2 = t->rn_key + off;
278 cplim = v + vlen;
279 for (; cp < cplim; cp++, cp2++)
280 if (*cp != *cp2)
281 goto on1;
282 /*
283 * This extra grot is in case we are explicitly asked
284 * to look up the default. Ugh!
285 */
286 if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey)
287 t = t->rn_dupedkey;
288 return t;
289on1:
290 test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */
291 for (b = 7; (test >>= 1) > 0;)
292 b--;
293 matched_off = cp - v;
294 b += matched_off << 3;
295 rn_b = -1 - b;
296 /*
297 * If there is a host route in a duped-key chain, it will be first.
298 */
299 if ((saved_t = t)->rn_mask == 0)
300 t = t->rn_dupedkey;
301 for (; t; t = t->rn_dupedkey)
302 /*
303 * Even if we don't match exactly as a host,
304 * we may match if the leaf we wound up at is
305 * a route to a net.
306 */
307 if (t->rn_flags & RNF_NORMAL) {
308 if (rn_b <= t->rn_b)
309 return t;
310 } else if (rn_satsifies_leaf(v, t, matched_off))
311 return t;
312 t = saved_t;
313 /* start searching up the tree */
314 do {
315 register struct squid_radix_mask *m;
316 t = t->rn_p;
317 if ((m = t->rn_mklist)) {
318 /*
319 * If non-contiguous masks ever become important
320 * we can restore the masking and open coding of
321 * the search and satisfaction test and put the
322 * calculation of "off" back before the "do".
323 */
324 do {
325 if (m->rm_flags & RNF_NORMAL) {
326 if (rn_b <= m->rm_b)
327 return (m->rm_leaf);
328 } else {
329 off = min(t->rn_off, matched_off);
330 x = squid_rn_search_m(v, t, m->rm_mask);
331 while (x && x->rn_mask != m->rm_mask)
332 x = x->rn_dupedkey;
333 if (x && rn_satsifies_leaf(v, x, off))
334 return x;
335 }
336 } while ((m = m->rm_mklist));
337 }
338 } while (t != top);
339 return 0;
340}
341
342struct squid_radix_node *
343squid_rn_newpair(void *v, int b, struct squid_radix_node nodes[2]) {
344 register struct squid_radix_node *tt = nodes, *t = tt + 1;
345 t->rn_b = b;
346 t->rn_bmask = 0x80 >> (b & 7);
347 t->rn_l = tt;
348 t->rn_off = b >> 3;
349 tt->rn_b = -1;
350 tt->rn_key = (char *) v;
351 tt->rn_p = t;
352 tt->rn_flags = t->rn_flags = RNF_ACTIVE;
353 return t;
354}
355
356struct squid_radix_node *
357squid_rn_insert(void *v_arg, struct squid_radix_node_head *head, int *dupentry, struct squid_radix_node nodes[2]) {
358 char *v = v_arg;
359 struct squid_radix_node *top = head->rnh_treetop;
360 int head_off = top->rn_off, vlen = (int) *((u_char *) v);
361 register struct squid_radix_node *t = squid_rn_search(v_arg, top);
362 register char *cp = v + head_off;
363 register int b;
364 struct squid_radix_node *tt;
365 /*
366 * Find first bit at which v and t->rn_key differ
367 */
368 {
369 register char *cp2 = t->rn_key + head_off;
370 register int cmp_res;
371 char *cplim = v + vlen;
372
373 while (cp < cplim)
374 if (*cp2++ != *cp++)
375 goto on1;
376 *dupentry = 1;
377 return t;
378on1:
379 *dupentry = 0;
380 cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
381 for (b = (cp - v) << 3; cmp_res; b--)
382 cmp_res >>= 1;
383 }
384 {
385 register struct squid_radix_node *p, *x = top;
386 cp = v;
387 do {
388 p = x;
389 if (cp[x->rn_off] & x->rn_bmask)
390 x = x->rn_r;
391 else
392 x = x->rn_l;
393 } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */
394 t = squid_rn_newpair(v_arg, b, nodes);
395 tt = t->rn_l;
396 if ((cp[p->rn_off] & p->rn_bmask) == 0)
397 p->rn_l = t;
398 else
399 p->rn_r = t;
400 x->rn_p = t;
401 t->rn_p = p; /* frees x, p as temp vars below */
402 if ((cp[t->rn_off] & t->rn_bmask) == 0) {
403 t->rn_r = x;
404 } else {
405 t->rn_r = tt;
406 t->rn_l = x;
407 }
408 }
409 return (tt);
410}
411
412struct squid_radix_node *
413squid_rn_addmask(void *n_arg, int search, int skip) {
414 char *netmask = (char *) n_arg;
415 register struct squid_radix_node *x;
416 register char *cp, *cplim;
417 register int b = 0, mlen, j;
418 int maskduplicated, m0, isnormal;
419 struct squid_radix_node *saved_x;
420 static int last_zeroed = 0;
421
422 if ((mlen = *(u_char *) netmask) > squid_max_keylen)
423 mlen = squid_max_keylen;
424 if (skip == 0)
425 skip = 1;
426 if (mlen <= skip)
428 if (skip > 1)
429 memcpy(addmask_key + 1, rn_ones + 1, skip - 1);
430 if ((m0 = mlen) > skip)
431 memcpy(addmask_key + skip, netmask + skip, mlen - skip);
432 /*
433 * Trim trailing zeroes.
434 */
435 for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;)
436 cp--;
437 mlen = cp - addmask_key;
438 if (mlen <= skip) {
439 if (m0 >= last_zeroed)
440 last_zeroed = mlen;
442 }
443 if (m0 < last_zeroed)
444 memset(addmask_key + m0, '\0', last_zeroed - m0);
445 *addmask_key = last_zeroed = mlen;
447 if (memcmp(addmask_key, x->rn_key, mlen) != 0)
448 x = 0;
449 if (x || search)
450 return (x);
451 squid_R_Malloc(x, struct squid_radix_node *, squid_max_keylen + 2 * sizeof(*x));
452 if ((saved_x = x) == 0)
453 return (0);
454 memset(x, '\0', squid_max_keylen + 2 * sizeof(*x));
455 netmask = cp = (char *) (x + 2);
456 memcpy(cp, addmask_key, mlen);
457 x = squid_rn_insert(cp, squid_mask_rnhead, &maskduplicated, x);
458 if (maskduplicated) {
459 fprintf(stderr, "squid_rn_addmask: mask impossibly already in tree");
460 squid_Free(saved_x);
461 return (x);
462 }
463 /*
464 * Calculate index of mask, and check for normalcy.
465 */
466 cplim = netmask + mlen;
467 isnormal = 1;
468 for (cp = netmask + skip; (cp < cplim) && *(u_char *) cp == 0xff;)
469 cp++;
470 if (cp != cplim) {
471 for (j = 0x80; (j & *cp) != 0; j >>= 1)
472 b++;
473 if (*cp != normal_chars[b] || cp != (cplim - 1))
474 isnormal = 0;
475 }
476 b += (cp - netmask) << 3;
477 x->rn_b = -1 - b;
478 if (isnormal)
479 x->rn_flags |= RNF_NORMAL;
480 return (x);
481}
482
483static int /* XXX: arbitrary ordering for non-contiguous masks */
484rn_lexobetter(void *m_arg, void *n_arg)
485{
486 register u_char *mp = m_arg, *np = n_arg, *lim;
487
488 if (*mp > *np)
489 return 1; /* not really, but need to check longer one first */
490 if (*mp == *np)
491 for (lim = mp + *mp; mp < lim;)
492 if (*mp++ > *np++)
493 return 1;
494 return 0;
495}
496
497static struct squid_radix_mask *
499 register struct squid_radix_mask *m;
500
501 squid_MKGet(m);
502 if (m == 0) {
503 fprintf(stderr, "Mask for route not entered\n");
504 return (0);
505 }
506 memset(m, '\0', sizeof *m);
507 m->rm_b = tt->rn_b;
508 m->rm_flags = tt->rn_flags;
509 if (tt->rn_flags & RNF_NORMAL)
510 m->rm_leaf = tt;
511 else
512 m->rm_mask = tt->rn_mask;
513 m->rm_mklist = next;
514 tt->rn_mklist = m;
515 return m;
516}
517
518struct squid_radix_node *
519squid_rn_addroute(void *v_arg, void *n_arg, struct squid_radix_node_head *head, struct squid_radix_node treenodes[2]) {
520 char *v = (char *) v_arg, *netmask = (char *) n_arg;
521 register struct squid_radix_node *t, *x = NULL, *tt;
522 struct squid_radix_node *saved_tt, *top = head->rnh_treetop;
523 short b = 0, b_leaf = 0;
524 int keyduplicated;
525 char *mmask;
526 struct squid_radix_mask *m, **mp;
527
528 /*
529 * In dealing with non-contiguous masks, there may be
530 * many different routes which have the same mask.
531 * We will find it useful to have a unique pointer to
532 * the mask to speed avoiding duplicate references at
533 * nodes and possibly save time in calculating indices.
534 */
535 if (netmask) {
536 if ((x = squid_rn_addmask(netmask, 0, top->rn_off)) == 0)
537 return (0);
538 b_leaf = x->rn_b;
539 b = -1 - x->rn_b;
540 netmask = x->rn_key;
541 }
542 /*
543 * Deal with duplicated keys: attach node to previous instance
544 */
545 saved_tt = tt = squid_rn_insert(v, head, &keyduplicated, treenodes);
546 if (keyduplicated) {
547 for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
548 if (tt->rn_mask == netmask)
549 return (0);
550 if (netmask == 0 ||
551 (tt->rn_mask &&
552 ((b_leaf < tt->rn_b) || /* index(netmask) > node */
553 squid_rn_refines(netmask, tt->rn_mask) ||
554 rn_lexobetter(netmask, tt->rn_mask))))
555 break;
556 }
557 /*
558 * If the mask is not duplicated, we wouldn't
559 * find it among possible duplicate key entries
560 * anyway, so the above test doesn't hurt.
561 *
562 * We sort the masks for a duplicated key the same way as
563 * in a masklist -- most specific to least specific.
564 * This may require the unfortunate nuisance of relocating
565 * the head of the list.
566 */
567 if (tt == saved_tt) {
568 struct squid_radix_node *xx = x;
569 /* link in at head of list */
570 tt = treenodes;
571 tt->rn_dupedkey = t;
572 tt->rn_flags = t->rn_flags;
573 tt->rn_p = x = t->rn_p;
574 if (x->rn_l == t)
575 x->rn_l = tt;
576 else
577 x->rn_r = tt;
578 saved_tt = tt;
579 x = xx;
580 } else {
581 tt = treenodes;
582 tt->rn_dupedkey = t->rn_dupedkey;
583 t->rn_dupedkey = tt;
584 }
585 tt->rn_key = (char *) v;
586 tt->rn_b = -1;
587 tt->rn_flags = RNF_ACTIVE;
588 }
589 /*
590 * Put mask in tree.
591 */
592 if (netmask) {
593 tt->rn_mask = netmask;
594 tt->rn_b = x->rn_b;
595 tt->rn_flags |= x->rn_flags & RNF_NORMAL;
596 }
597 t = saved_tt->rn_p;
598 if (keyduplicated)
599 goto on2;
600 b_leaf = -1 - t->rn_b;
601 if (t->rn_r == saved_tt)
602 x = t->rn_l;
603 else
604 x = t->rn_r;
605 /* Promote general routes from below */
606 if (x->rn_b < 0) {
607 for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
608 if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) {
609 if ((*mp = m = rn_new_radix_mask(x, 0)))
610 mp = &m->rm_mklist;
611 }
612 } else if (x->rn_mklist) {
613 /*
614 * Skip over masks whose index is > that of new node
615 */
616 for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
617 if (m->rm_b >= b_leaf)
618 break;
619 t->rn_mklist = m;
620 *mp = 0;
621 }
622on2:
623 /* Add new route to highest possible ancestor's list */
624 if ((netmask == 0) || (b > t->rn_b))
625 return tt; /* can't lift at all */
626 b_leaf = tt->rn_b;
627 do {
628 x = t;
629 t = t->rn_p;
630 } while (b <= t->rn_b && x != top);
631 /*
632 * Search through routes associated with node to
633 * insert new route according to index.
634 * Need same criteria as when sorting dupedkeys to avoid
635 * double loop on deletion.
636 */
637 for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) {
638 if (m->rm_b < b_leaf)
639 continue;
640 if (m->rm_b > b_leaf)
641 break;
642 if (m->rm_flags & RNF_NORMAL) {
643 mmask = m->rm_leaf->rn_mask;
644 if (tt->rn_flags & RNF_NORMAL) {
645 fprintf(stderr,
646 "Non-unique normal route, mask not entered");
647 return tt;
648 }
649 } else
650 mmask = m->rm_mask;
651 if (mmask == netmask) {
652 m->rm_refs++;
653 tt->rn_mklist = m;
654 return tt;
655 }
656 if (squid_rn_refines(netmask, mmask) || rn_lexobetter(netmask, mmask))
657 break;
658 }
659 *mp = rn_new_radix_mask(tt, *mp);
660 return tt;
661}
662
663struct squid_radix_node *
664squid_rn_delete(void *v_arg, void *netmask_arg, struct squid_radix_node_head *head) {
665 register struct squid_radix_node *t, *p, *x, *tt;
666 struct squid_radix_mask *m, *saved_m, **mp;
667 struct squid_radix_node *dupedkey, *saved_tt, *top;
668 char *v, *netmask;
669 int b, head_off, vlen;
670
671 v = v_arg;
672 netmask = netmask_arg;
673 x = head->rnh_treetop;
674 tt = squid_rn_search(v, x);
675 head_off = x->rn_off;
676 vlen = *(u_char *) v;
677 saved_tt = tt;
678 top = x;
679 if (tt == 0 ||
680 memcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
681 return (0);
682 /*
683 * Delete our route from mask lists.
684 */
685 if (netmask) {
686 if ((x = squid_rn_addmask(netmask, 1, head_off)) == 0)
687 return (0);
688 netmask = x->rn_key;
689 while (tt->rn_mask != netmask)
690 if ((tt = tt->rn_dupedkey) == 0)
691 return (0);
692 }
693 if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
694 goto on1;
695 if (tt->rn_flags & RNF_NORMAL) {
696 if (m->rm_leaf != tt || m->rm_refs > 0) {
697 fprintf(stderr, "squid_rn_delete: inconsistent annotation\n");
698 return 0; /* dangling ref could cause disaster */
699 }
700 } else {
701 if (m->rm_mask != tt->rn_mask) {
702 fprintf(stderr, "squid_rn_delete: inconsistent annotation\n");
703 goto on1;
704 }
705 if (--m->rm_refs >= 0)
706 goto on1;
707 }
708 b = -1 - tt->rn_b;
709 t = saved_tt->rn_p;
710 if (b > t->rn_b)
711 goto on1; /* Wasn't lifted at all */
712 do {
713 x = t;
714 t = t->rn_p;
715 } while (b <= t->rn_b && x != top);
716 for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
717 if (m == saved_m) {
718 *mp = m->rm_mklist;
719 squid_MKFree(m);
720 break;
721 }
722 if (m == 0) {
723 fprintf(stderr, "squid_rn_delete: couldn't find our annotation\n");
724 if (tt->rn_flags & RNF_NORMAL)
725 return (0); /* Dangling ref to us */
726 }
727on1:
728 /*
729 * Eliminate us from tree
730 */
731 if (tt->rn_flags & RNF_ROOT)
732 return (0);
733 t = tt->rn_p;
734 if ((dupedkey = saved_tt->rn_dupedkey)) {
735 if (tt == saved_tt) {
736 x = dupedkey;
737 x->rn_p = t;
738 if (t->rn_l == tt)
739 t->rn_l = x;
740 else
741 t->rn_r = x;
742 } else {
743 for (x = p = saved_tt; p && p->rn_dupedkey != tt;)
744 p = p->rn_dupedkey;
745 if (p)
746 p->rn_dupedkey = tt->rn_dupedkey;
747 else
748 fprintf(stderr, "squid_rn_delete: couldn't find us\n");
749 }
750 t = tt + 1;
751 if (t->rn_flags & RNF_ACTIVE) {
752 *++x = *t;
753 p = t->rn_p;
754 if (p->rn_l == t)
755 p->rn_l = x;
756 else
757 p->rn_r = x;
758 x->rn_l->rn_p = x;
759 x->rn_r->rn_p = x;
760 }
761 goto out;
762 }
763 if (t->rn_l == tt)
764 x = t->rn_r;
765 else
766 x = t->rn_l;
767 p = t->rn_p;
768 if (p->rn_r == t)
769 p->rn_r = x;
770 else
771 p->rn_l = x;
772 x->rn_p = p;
773 /*
774 * Demote routes attached to us.
775 */
776 if (t->rn_mklist) {
777 if (x->rn_b >= 0) {
778 for (mp = &x->rn_mklist; (m = *mp);)
779 mp = &m->rm_mklist;
780 *mp = t->rn_mklist;
781 } else {
782 /* If there are any key,mask pairs in a sibling
783 * duped-key chain, some subset will appear sorted
784 * in the same order attached to our mklist */
785 for (m = t->rn_mklist; m && x; x = x->rn_dupedkey)
786 if (m == x->rn_mklist) {
787 struct squid_radix_mask *mm = m->rm_mklist;
788 x->rn_mklist = 0;
789 if (--(m->rm_refs) < 0)
790 squid_MKFree(m);
791 m = mm;
792 }
793 assert(m == NULL);
794 }
795 }
796 /*
797 * We may be holding an active internal node in the tree.
798 */
799 x = tt + 1;
800 if (t != x) {
801 *t = *x;
802 t->rn_l->rn_p = t;
803 t->rn_r->rn_p = t;
804 p = x->rn_p;
805 if (p->rn_l == x)
806 p->rn_l = t;
807 else
808 p->rn_r = t;
809 }
810out:
811 tt->rn_flags &= ~RNF_ACTIVE;
812 tt[1].rn_flags &= ~RNF_ACTIVE;
813 return (tt);
814}
815
816int
817squid_rn_walktree(struct squid_radix_node_head *h, int (*f) (struct squid_radix_node *, void *), void *w)
818{
819 int error;
820 struct squid_radix_node *base, *next;
821 register struct squid_radix_node *rn = h->rnh_treetop;
822 /*
823 * This gets complicated because we may delete the node
824 * while applying the function f to it, so we need to calculate
825 * the successor node in advance.
826 */
827 /* First time through node, go left */
828 while (rn->rn_b >= 0)
829 rn = rn->rn_l;
830 for (;;) {
831 base = rn;
832 /* If at right child go back up, otherwise, go right */
833 while (rn->rn_p->rn_r == rn && (rn->rn_flags & RNF_ROOT) == 0)
834 rn = rn->rn_p;
835 /* Find the next *leaf* since next node might vanish, too */
836 for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;)
837 rn = rn->rn_l;
838 next = rn;
839 /* Process leaves */
840 while ((rn = base)) {
841 base = rn->rn_dupedkey;
842 if (!(rn->rn_flags & RNF_ROOT) && (error = (*f) (rn, w)))
843 return (error);
844 }
845 rn = next;
846 if (rn->rn_flags & RNF_ROOT)
847 return (0);
848 }
849 /* NOTREACHED */
850}
851
852int
854{
855 register struct squid_radix_node_head *rnh;
856 register struct squid_radix_node *t, *tt, *ttt;
857 if (*head)
858 return (1);
859 squid_R_Malloc(rnh, struct squid_radix_node_head *, sizeof(*rnh));
860 if (rnh == 0)
861 return (0);
862 memset(rnh, '\0', sizeof(*rnh));
863 *head = rnh;
864 t = squid_rn_newpair(rn_zeros, off, rnh->rnh_nodes);
865 ttt = rnh->rnh_nodes + 2;
866 t->rn_r = ttt;
867 t->rn_p = t;
868 tt = t->rn_l;
870 tt->rn_b = -1 - off;
871 *ttt = *tt;
872 ttt->rn_key = rn_ones;
878 rnh->rnh_treetop = t;
879 return (1);
880}
881
882void
884{
885 char *cp, *cplim;
886#ifdef KERNEL
887 struct domain *dom;
888
889 for (dom = domains; dom; dom = dom->dom_next)
890 if (dom->dom_maxrtkey > squid_max_keylen)
891 squid_max_keylen = dom->dom_maxrtkey;
892#endif
893 if (squid_max_keylen == 0) {
894 fprintf(stderr,
895 "squid_rn_init: radix functions require squid_max_keylen be set\n");
896 return;
897 }
899 if (rn_zeros == NULL) {
900 fprintf(stderr, "squid_rn_init failed.\n");
901 exit(-1);
902 }
903 memset(rn_zeros, '\0', 3 * squid_max_keylen);
906 while (cp < cplim)
907 *cp++ = -1;
908 if (squid_rn_inithead(&squid_mask_rnhead, 0) == 0) {
909 fprintf(stderr, "rn_init2 failed.\n");
910 exit(-1);
911 }
912}
913
void error(char *format,...)
squidaio_request_t * head
Definition: aiops.cc:127
#define assert(EX)
Definition: assert.h:17
int squid_rn_walktree(struct squid_radix_node_head *h, int(*f)(struct squid_radix_node *, void *), void *w)
Definition: radix.c:817
struct squid_radix_node * squid_rn_addroute(void *v_arg, void *n_arg, struct squid_radix_node_head *head, struct squid_radix_node treenodes[2])
Definition: radix.c:519
#define rn_masktop
Definition: radix.c:92
struct squid_radix_node_head * squid_mask_rnhead
Definition: radix.c:86
#define squid_MKGet(m)
Definition: radix.c:103
int squid_rn_refines(void *m_arg, void *n_arg)
Definition: radix.c:180
struct squid_radix_node * squid_rn_lookup(void *v_arg, void *m_arg, struct squid_radix_node_head *head)
Definition: radix.c:206
static struct squid_radix_mask * rn_new_radix_mask(struct squid_radix_node *tt, struct squid_radix_mask *next)
Definition: radix.c:498
static unsigned char normal_chars[]
Definition: radix.c:88
int squid_rn_inithead(struct squid_radix_node_head **head, int off)
Definition: radix.c:853
struct squid_radix_mask * squid_rn_mkfreelist
Definition: radix.c:85
static int rn_lexobetter(void *m_arg, void *n_arg)
Definition: radix.c:484
#define squid_R_Malloc(p, t, n)
Definition: radix.c:101
static char * addmask_key
Definition: radix.c:87
int squid_max_keylen
Definition: radix.c:84
struct squid_radix_node * squid_rn_newpair(void *v, int b, struct squid_radix_node nodes[2])
Definition: radix.c:343
void squid_rn_init(void)
Definition: radix.c:883
struct squid_radix_node * squid_rn_addmask(void *n_arg, int search, int skip)
Definition: radix.c:413
struct squid_radix_node * squid_rn_search_m(void *v_arg, struct squid_radix_node *head, void *m_arg)
Definition: radix.c:165
#define min(x, y)
Definition: radix.c:114
struct squid_radix_node * squid_rn_search(void *v_arg, struct squid_radix_node *head)
Definition: radix.c:151
struct squid_radix_node * squid_rn_insert(void *v_arg, struct squid_radix_node_head *head, int *dupentry, struct squid_radix_node nodes[2])
Definition: radix.c:357
struct squid_radix_node * squid_rn_match(void *v_arg, struct squid_radix_node_head *head)
Definition: radix.c:244
#define squid_Free(p)
Definition: radix.c:102
struct squid_radix_node * squid_rn_delete(void *v_arg, void *netmask_arg, struct squid_radix_node_head *head)
Definition: radix.c:664
static char * rn_zeros
Definition: radix.c:89
static char * rn_ones
Definition: radix.c:89
#define squid_MKFree(m)
Definition: radix.c:111
static int rn_satsifies_leaf(char *trial, register struct squid_radix_node *leaf, int skip)
Definition: radix.c:224
#define RNF_NORMAL
Definition: radix.h:59
#define RNF_ACTIVE
Definition: radix.h:61
#define RNF_ROOT
Definition: radix.h:60
unsigned char rm_flags
Definition: radix.h:92
short rm_b
Definition: radix.h:90
struct squid_radix_mask * rm_mklist
Definition: radix.h:94
struct squid_radix_node * rnh_deladdr(void *v, void *mask, struct squid_radix_node_head *head)
struct squid_radix_node * rnh_lookup(void *v, void *mask, struct squid_radix_node_head *head)
struct squid_radix_node * rnh_matchaddr(void *v, struct squid_radix_node_head *head)
int rnh_walktree(struct squid_radix_node_head *head, int(*f)(struct squid_radix_node *, void *), void *w)
struct squid_radix_node * rnh_treetop
Definition: radix.h:105
struct squid_radix_node * rnh_addaddr(void *v, void *mask, struct squid_radix_node_head *head, struct squid_radix_node nodes[])
struct squid_radix_node rnh_nodes[3]
Definition: radix.h:134
struct squid_radix_node * rn_p
Definition: radix.h:55
short rn_b
Definition: radix.h:56
char rn_bmask
Definition: radix.h:57
struct squid_radix_mask * rn_mklist
Definition: radix.h:53
unsigned char rn_flags
Definition: radix.h:58
int unsigned int
Definition: stub_fd.cc:19
#define NULL
Definition: types.h:145

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors