radix.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 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 
87 static char *addmask_key;
88 static unsigned char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xFF};
89 static 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 
150 struct squid_radix_node *
151 squid_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 
164 struct squid_radix_node *
165 squid_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 
179 int
180 squid_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 
205 struct squid_radix_node *
206 squid_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 
223 static int
224 rn_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 
243 struct 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;
289 on1:
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 
342 struct squid_radix_node *
343 squid_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 
356 struct squid_radix_node *
357 squid_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;
378 on1:
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 
412 struct squid_radix_node *
413 squid_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)
427  return (squid_mask_rnhead->rnh_nodes);
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;
441  return (squid_mask_rnhead->rnh_nodes);
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 
483 static int /* XXX: arbitrary ordering for non-contiguous masks */
484 rn_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 
497 static 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 
518 struct squid_radix_node *
519 squid_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  }
622 on2:
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 
663 struct squid_radix_node *
664 squid_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  }
727 on1:
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  }
810 out:
811  tt->rn_flags &= ~RNF_ACTIVE;
812  tt[1].rn_flags &= ~RNF_ACTIVE;
813  return (tt);
814 }
815 
816 int
817 squid_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 
852 int
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;
865  ttt = rnh->rnh_nodes + 2;
866  t->rn_r = ttt;
867  t->rn_p = t;
868  tt = t->rn_l;
869  tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
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 
882 void
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 
char rn_bmask
Definition: radix.h:57
#define squid_MKFree(m)
Definition: radix.c:111
#define RNF_NORMAL
Definition: radix.h:59
#define squid_MKGet(m)
Definition: radix.c:103
struct squid_radix_node * squid_rn_addmask(void *n_arg, int search, int skip)
Definition: radix.c:413
#define RNF_ACTIVE
Definition: radix.h:61
void error(char *format,...)
struct squid_radix_node * squid_rn_search(void *v_arg, struct squid_radix_node *head)
Definition: radix.c:151
short rn_b
Definition: radix.h:56
struct squid_radix_node_head * squid_mask_rnhead
Definition: radix.c:86
struct squid_radix_node * squid_rn_lookup(void *v_arg, void *m_arg, struct squid_radix_node_head *head)
Definition: radix.c:206
struct squid_radix_mask * squid_rn_mkfreelist
Definition: radix.c:85
int squid_rn_walktree(struct squid_radix_node_head *h, int(*f)(struct squid_radix_node *, void *), void *w)
Definition: radix.c:817
unsigned char rn_flags
Definition: radix.h:58
static char * rn_ones
Definition: radix.c:89
struct squid_radix_node * squid_rn_search_m(void *v_arg, struct squid_radix_node *head, void *m_arg)
Definition: radix.c:165
short rm_b
Definition: radix.h:90
unsigned char rm_flags
Definition: radix.h:92
struct squid_radix_node * rn_p
Definition: radix.h:55
struct squid_radix_mask * rm_mklist
Definition: radix.h:94
int squid_max_keylen
Definition: radix.c:84
#define NULL
Definition: types.h:145
struct squid_radix_node * rnh_matchaddr(void *v, struct squid_radix_node_head *head)
int squid_rn_refines(void *m_arg, void *n_arg)
Definition: radix.c:180
struct squid_radix_node * squid_rn_newpair(void *v, int b, struct squid_radix_node nodes[2])
Definition: radix.c:343
#define squid_Free(p)
Definition: radix.c:102
int squid_rn_inithead(struct squid_radix_node_head **head, int off)
Definition: radix.c:853
struct squid_radix_node * squid_rn_match(void *v_arg, struct squid_radix_node_head *head)
Definition: radix.c:244
static char * rn_zeros
Definition: radix.c:89
#define assert(EX)
Definition: assert.h:17
static int rn_lexobetter(void *m_arg, void *n_arg)
Definition: radix.c:484
#define RNF_ROOT
Definition: radix.h:60
struct squid_radix_node rnh_nodes[3]
Definition: radix.h:134
#define rn_masktop
Definition: radix.c:92
#define squid_R_Malloc(p, t, n)
Definition: radix.c:101
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 * addmask_key
Definition: radix.c:87
struct squid_radix_node * rnh_treetop
Definition: radix.h:105
void squid_rn_init(void)
Definition: radix.c:883
static struct squid_radix_mask * rn_new_radix_mask(struct squid_radix_node *tt, struct squid_radix_mask *next)
Definition: radix.c:498
squidaio_request_t * head
Definition: aiops.cc:127
struct squid_radix_node * rnh_addaddr(void *v, void *mask, struct squid_radix_node_head *head, struct squid_radix_node nodes[])
static int rn_satsifies_leaf(char *trial, register struct squid_radix_node *leaf, int skip)
Definition: radix.c:224
int rnh_walktree(struct squid_radix_node_head *head, int(*f)(struct squid_radix_node *, void *), void *w)
struct squid_radix_node * rnh_deladdr(void *v, void *mask, struct squid_radix_node_head *head)
#define min(x, y)
Definition: radix.c:114
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
struct squid_radix_node * rnh_lookup(void *v, void *mask, struct squid_radix_node_head *head)
static unsigned char normal_chars[]
Definition: radix.c:88
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
int unsigned int
Definition: stub_fd.cc:19
struct squid_radix_mask * rn_mklist
Definition: radix.h:53

 

Introduction

Documentation

Support

Miscellaneous