|
|
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.