|
|
1.1 root 1: /* pathalias -- by steve bellovin, as told to peter honeyman */
2: #ifndef lint
3: static char *sccsid = "@(#)addnode.c 8.1 (down!honey) 86/01/19";
4: #endif
5:
6: #include "def.h"
7:
8: extern void lowercase(), rehash();
9: extern node *isprivate();
10: extern long hash();
11:
12: /*
13: * these numbers are chosen because:
14: * -> they are prime,
15: * -> they are monotonic increasing,
16: * -> each is a tad smaller than a multiple of 1024,
17: * -> they form a fibonacci sequence (almost).
18: * the first point yields good hash functions, the second is used for the
19: * standard re-hashing implementation of open addressing, the third
20: * optimizes for quirks in some mallocs i have seen, and the fourth simply
21: * appeals to me.
22: */
23: static int Primes[] = {
24: #ifndef SQUANDER
25: 1021, 2039, 3067, 5113, 8179,
26: #endif
27: 13309, 21499, 0
28: };
29:
30: static int Tabindex = -1;
31: static int Collision; /* mark host name collisions in hash() */
32:
33: node *
34: addnode(name)
35: register char *name;
36: {
37: register long i;
38: register node *n;
39:
40: if (Iflag)
41: lowercase(name);
42:
43: /* is it a private host? */
44: n = isprivate(name);
45: if (n)
46: return(n);
47:
48: i = hash(name, 0);
49: if (Table[i])
50: return(Table[i]);
51:
52: n = newnode();
53: n->n_name = strsave(name);
54: Table[i] = n;
55: n->n_tloc = i; /* essentially a back link to the table */
56: if (Collision)
57: n->n_flag |= COLLISION; /* name collision with private host */
58:
59: return(n);
60: }
61:
62: alias(n1, n2)
63: node *n1, *n2;
64: {
65: link *l;
66: extern link *addlink();
67:
68: l = addlink(n1, n2, (Cost) 0, DEFNET, DEFDIR);
69: l->l_flag |= LALIAS;
70: l = addlink(n2, n1, (Cost) 0, DEFNET, DEFDIR);
71: l->l_flag |= LALIAS;
72: if (Tflag)
73: atrace(n1, n2);
74: }
75:
76: /*
77: * fold a string into a long int. this algorithm ignores all but the last
78: * eight bytes, which affects < 15% of all host names, many of which have
79: * common prefixes anyway.
80: */
81: STATIC long
82: fold(str)
83: register char *str;
84: {
85: register long sum;
86:
87: sum = *str++;
88: while (*str) {
89: sum <<= 4;
90: sum += *str++;
91: }
92: if (sum < 0)
93: sum = -sum;
94: return(sum);
95: }
96:
97: #define HASH1(n) ((n) % Tabsize);
98: #define HASH2(n) (Tabsize - 2 - ((n) % (Tabsize-2))) /* princeton!rs */
99:
100: /*
101: * with a 0.75 high water mark, probes per access should be 1.84.
102: * use long constant to force promotion.
103: */
104: #define HIGHWATER 75L
105: #define isfull(n, size) ((n) > ((size) * HIGHWATER) / 100)
106:
107: STATIC long
108: hash(name, unique)
109: char *name;
110: {
111: register long probe, hash2;
112: register node *n;
113:
114: if (Tabindex < 0) { /* first time */
115: Tabindex = 0;
116: Tabsize = Primes[0];
117: Table = newtable(Tabsize);
118: } else if (isfull(Ncount, Tabsize))
119: rehash(); /* more, more! */
120:
121: probe = fold(name);
122: /* don't change the order of the next two lines */
123: hash2 = HASH2(probe);
124: probe = HASH1(probe);
125: /* thank you! */
126:
127: /*
128: * probe the hash table.
129: * if unique is set, we require a fresh slot.
130: * otherwise, use double hashing to find either
131: * (1) an empty slot, or
132: * (2) a non-private copy of this host name
133: *
134: * as a side effect, if we notice a collision with a private host
135: * we mark the other so that it is skipped at output time.
136: */
137: Collision = 0;
138: while ((n = Table[probe]) != 0) {
139: if (strcmp(n->n_name, name) == 0) {
140: if (unique)
141: n->n_flag |= COLLISION;
142: else if (n->n_flag & ISPRIVATE)
143: Collision++;
144: else
145: break; /* this is it! */
146: }
147: probe -= hash2;
148: if (probe < 0)
149: probe += Tabsize;
150: }
151: return(probe);
152: }
153:
154: STATIC void
155: rehash()
156: {
157: register node **otable, **optr;
158: register long probe;
159: long osize;
160:
161: #ifdef DEBUG
162: hashanalyze();
163: #endif
164: optr = Table + Tabsize - 1; /* ptr to last */
165: otable = Table;
166: osize = Tabsize;
167: Tabsize = Primes[++Tabindex];
168: if (Tabsize == 0) { /* need more prime numbers */
169: fprintf(stderr, "%s: > %d hosts\n", ProgName, Primes[Tabindex-1]);
170: badmagic(1);
171: }
172: vprintf(stderr, "rehash into %d\n", Tabsize);
173: Table = newtable(Tabsize);
174:
175: do {
176: if (*optr == 0)
177: continue; /* empty slot in old table */
178: probe = hash((*optr)->n_name, (*optr)->n_flag & ISPRIVATE);
179: if (Table[probe] != 0) {
180: fprintf(stderr, "%s: rehash error\n", ProgName);
181: badmagic(1);
182: }
183: Table[probe] = *optr;
184: (*optr)->n_tloc = probe;
185: } while (optr-- > otable);
186: freetable(otable, osize);
187: }
188:
189: hashanalyze()
190: {
191: long probe, hash2;
192: int count, i, collision[8];
193: int longest = 0, total = 0, slots = 0;
194: int nslots = sizeof(collision)/sizeof(collision[0]);
195:
196: if (!Vflag)
197: return;
198:
199: strclear((char *) collision, sizeof(collision));
200: for (i = 0; i < Tabsize; i++) {
201: if (Table[i] == 0)
202: continue;
203: /* private hosts too hard to account for ... */
204: if (Table[i]->n_flag & ISPRIVATE)
205: continue;
206: count = 1;
207: probe = fold(Table[i]->n_name);
208: /* don't change the order of the next two lines */
209: hash2 = HASH2(probe);
210: probe = HASH1(probe);
211: /* thank you! */
212: while (Table[probe] != 0
213: && strcmp(Table[probe]->n_name, Table[i]->n_name) != 0) {
214: count++;
215: probe -= hash2;
216: if (probe < 0)
217: probe += Tabsize;
218: }
219: if (Table[probe] == 0) {
220: fprintf(stderr, "%s: impossible hash error for %s\n",
221: ProgName, Table[i]->n_name);
222: badmagic(1);
223: }
224:
225: total += count;
226: slots++;
227: if (count > longest)
228: longest = count;
229: if (count >= nslots)
230: count = 0;
231: collision[count]++;
232: }
233: for (i = 1; i < nslots; i++)
234: if (collision[i])
235: fprintf(stderr, "%d chains: %d (%ld%%)\n",
236: i, collision[i], (collision[i] * 100L)/ slots);
237: if (collision[0])
238: fprintf(stderr, "> %d chains: %d (%ld%%)\n",
239: nslots - 1, collision[0],
240: (collision[0] * 100L)/ slots);
241: fprintf(stderr, "%2.2f probes per access, longest chain: %d\n",
242: (double) total / slots, longest);
243: }
244:
245: STATIC void
246: lowercase(s)
247: register char *s;
248: {
249: do {
250: if (isupper(*s))
251: *s -= 'A' - 'a'; /* assumes ASCII */
252: } while (*s++);
253: }
254:
255: /*
256: * this might have to be recoded for performance if privates catch on
257: */
258: STATIC node *
259: isprivate(name)
260: register char *name;
261: {
262: register node *n;
263:
264: for (n = Private; n != 0; n = n->n_private)
265: if (strcmp(name, n->n_name) == 0)
266: return(n);
267: return(0);
268: }
269:
270: fixprivate()
271: {
272: register node *n, *next;
273: register long i;
274:
275: for (n = Private; n != 0; n = next) {
276: n->n_flag |= ISPRIVATE; /* overkill, but safe */
277: i = hash(n->n_name, 1);
278: if (Table[i] != 0) {
279: fprintf(stderr, "%s: impossible private node error on %s\n",
280: ProgName, n->n_name);
281: badmagic(1);
282: }
283:
284: Table[i] = n;
285: n->n_tloc = i; /* essentially a back link to the table */
286: next = n->n_private;
287: n->n_private = 0; /* clear for later use */
288: }
289: Private = 0;
290: }
291:
292: node *
293: addprivate(name)
294: register char *name;
295: {
296: register node *n;
297:
298: if (Iflag)
299: lowercase(name);
300: if ((n = isprivate(name)) != 0)
301: return(n);
302:
303: n = newnode();
304: n->n_name = strsave(name);
305: n->n_private = Private;
306: Private = n;
307: return(n);
308: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.