|
|
1.1 ! root 1: /* pathalias -- by steve bellovin, as told to peter honeyman */ ! 2: #ifndef lint ! 3: static char *sccsid = "@(#)mapit.c 8.1 (down!honey) 86/01/19"; ! 4: #endif ! 5: ! 6: #include "def.h" ! 7: ! 8: /* privates */ ! 9: extern void reheap(), insert(), heapswap(); ! 10: extern link *min_node(), *rmlink(); ! 11: extern Cost costof(); ! 12: ! 13: static long Nheap; ! 14: static long Heaphighwater; ! 15: static link **Heap; ! 16: ! 17: ! 18: /* transform the graph to a shortest-path tree by marking tree edges */ ! 19: ! 20: mapit() ! 21: { ! 22: register node *n, *next; ! 23: register link *l; ! 24: link *lprev, *lnext; ! 25: Cost cost; ! 26: ! 27: /* ! 28: * re-use the hash table space for the heap. ! 29: */ ! 30: Heap = (link **) Table; ! 31: ! 32: pack(); /* remove holes in the Table */ ! 33: if (Linkout && *Linkout) /* dump cheapest links */ ! 34: showlinks(); ! 35: if (Graphout && *Graphout) /* dump the edge list */ ! 36: dumpgraph(); ! 37: ! 38: /* invent and insert a link for Home to get things started */ ! 39: l = newlink(); ! 40: l->l_to = Home; ! 41: (void) dehash(Home); ! 42: insert(l); ! 43: ! 44: /* main mapping loop */ ! 45: remap: ! 46: Heaphighwater = Nheap; ! 47: while ((l = min_node()) != 0) { ! 48: l->l_flag |= LTREE; ! 49: n = l->l_to; ! 50: n->n_flag |= MAPPED; ! 51: ! 52: /* add children to heap */ ! 53: lprev = 0; ! 54: for (l = n->n_link; l != 0; l = lnext) { ! 55: ! 56: next = l->l_to; /* neighboring node */ ! 57: if (next->n_flag & MAPPED) { ! 58: lnext = rmlink(l, lprev, n); ! 59: continue; ! 60: } ! 61: cost = costof(n, l); ! 62: ! 63: if (skiplink(l, n, cost)) { ! 64: lnext = rmlink(l, lprev, n); ! 65: continue; ! 66: } ! 67: ! 68: /* ! 69: * put this link in the heap, in a place where it may ! 70: * percolate up, but not down. if new, or if cost is ! 71: * being increased, move to end. otherwise, cost is ! 72: * same or less, so leave it where it is. unfortunately, ! 73: * freeing a link already in the heap is too costly at ! 74: * this point. ! 75: * ! 76: * TODO: avoid heaping aliases and network members. ! 77: */ ! 78: if (dehash(next) == 0) /* first time in heap */ ! 79: insert(l); /* insert at end */ ! 80: else { ! 81: /* replace heaped link by this one */ ! 82: if (cost > next->n_cost) { /* gateway */ ! 83: /* move old link to end of heap */ ! 84: heapswap((long) (next->n_tloc), Nheap); ! 85: next->n_tloc = Nheap; ! 86: } ! 87: Heap[next->n_tloc] = l; ! 88: } ! 89: ! 90: next->n_cost = cost; ! 91: next->n_parent = n; ! 92: reheap(l); /* restore heap property */ ! 93: ! 94: /* ! 95: * note whether we got here via a gatewayed net. ! 96: * domains are presumed to require gateways. ! 97: * aliases inherit parent's gateway status. ! 98: */ ! 99: next->n_flag &= ~GATEWAYIN; ! 100: if (l->l_flag & LALIAS) ! 101: next->n_flag |= (n->n_flag & GATEWAYIN); ! 102: else if (GATEWAYED(n)) ! 103: next->n_flag |= GATEWAYIN; ! 104: lprev = l; /* this link's a keeper */ ! 105: lnext = l->l_next; ! 106: } ! 107: ! 108: } ! 109: vprintf(stderr, "heap high water mark was %d\n", Heaphighwater); ! 110: ! 111: /* sanity check on implementation */ ! 112: if (Nheap != 0) { ! 113: fprintf(stderr, "%s: null entry found in heap\n", ProgName); ! 114: badmagic(1); ! 115: } ! 116: ! 117: if (Hashpart < Tabsize) { ! 118: /* ! 119: * add back links from unreachable hosts to reachable ! 120: * neighbors, then remap. asymptotically, this is ! 121: * quadratic. in practice, this is done exactly once. ! 122: */ ! 123: backlinks(); ! 124: if (Nheap) ! 125: goto remap; ! 126: } ! 127: if (Hashpart < Tabsize) { ! 128: fputs("You can't get there from here:\n", stderr); ! 129: for ( ; Hashpart < Tabsize; Hashpart++) { ! 130: fprintf(stderr, "\t%s", Table[Hashpart]->n_name); ! 131: if (Table[Hashpart]->n_flag & (ISPRIVATE|COLLISION)) ! 132: fputs(" (private)", stderr); ! 133: putc('\n', stderr); ! 134: } ! 135: } ! 136: } ! 137: ! 138: /* ! 139: * can this link be ignored? if yes, return 1, o.w. 0. ! 140: * a link can be skipped if it is not in the shortest path tree. ! 141: */ ! 142: STATIC int ! 143: skiplink(l, parent, cost) ! 144: link *l; /* new link to this node */ ! 145: node *parent; /* new parent of this node */ ! 146: Cost cost; /* new cost to this node */ ! 147: { ! 148: node *n; /* this node */ ! 149: link *lheap; /* existing link to this node */ ! 150: ! 151: n = l->l_to; ! 152: ! 153: /* first time we've reached this node? */ ! 154: if (n->n_tloc >= Hashpart) ! 155: return(0); ! 156: ! 157: lheap = Heap[n->n_tloc]; ! 158: ! 159: /* examine links to nets that require gateways */ ! 160: if (GATEWAYED(n)) { ! 161: /* if exactly one is a gateway, use it */ ! 162: if ((lheap->l_flag & LGATEWAY) && !(l->l_flag & LGATEWAY)) ! 163: return(1); /* old is gateway */ ! 164: if (!(lheap->l_flag & LGATEWAY) && (l->l_flag & LGATEWAY)) ! 165: return(0); /* new is gateway */ ! 166: ! 167: /* no gateway or both gateways; resolve in standard way ... */ ! 168: } ! 169: ! 170: /* examine dup link (sanity check) */ ! 171: if (n->n_parent == parent && ((lheap->l_flag & LDEAD) || (l->l_flag & LDEAD))) { ! 172: fprintf(stderr, "%s: dup dead link not eliminated: %s -> %s\n", ! 173: ProgName, parent->n_name, n->n_name); ! 174: badmagic(1); ! 175: } ! 176: ! 177: ! 178: /* examine cost */ ! 179: if (cost < n->n_cost) ! 180: return(0); ! 181: if (cost > n->n_cost) ! 182: return(1); ! 183: ! 184: /* all other things being equal, consult the oracle */ ! 185: return(tiebreaker(n, parent)); ! 186: } ! 187: ! 188: STATIC Cost ! 189: costof(prev, l) ! 190: register node *prev; ! 191: register link *l; ! 192: { ! 193: register node *next; ! 194: register Cost cost; ! 195: ! 196: next = l->l_to; ! 197: ! 198: if (l->l_flag & LALIAS) { ! 199: /* copy left/right bits */ ! 200: next->n_flag &= ~(HASLEFT|HASRIGHT); ! 201: next->n_flag |= (prev->n_flag & (HASLEFT|HASRIGHT)); ! 202: return(prev->n_cost); /* by definition */ ! 203: } ! 204: ! 205: ! 206: cost = prev->n_cost + l->l_cost; /* basic cost */ ! 207: ! 208: /* ! 209: * heuristics: ! 210: * charge for a dead link. ! 211: * charge for getting out of a dead host. ! 212: * charge for getting into a gatewayed net (except at a gateway). ! 213: * discourage mixing of left and right syntax when next is a host. ! 214: * charge for leaving a gatewayed net. ! 215: * ! 216: * life was simpler when pathalias computed true shortest paths. ! 217: */ ! 218: if (l->l_flag & LDEAD) /* dead link */ ! 219: cost += INF/2; ! 220: if (DEADHOST(prev)) /* dead host */ ! 221: cost += INF/2; ! 222: if (GATEWAYED(next) && !(l->l_flag & LGATEWAY)) /* not gateway */ ! 223: cost += INF/2; ! 224: if (!ISANET(next)) { ! 225: /* charge for mixed syntax here */ ! 226: if ((NETDIR(l) == LLEFT && (prev->n_flag & HASRIGHT)) ! 227: || (NETDIR(l) == LRIGHT && (prev->n_flag & HASLEFT))) ! 228: cost += DEFCOST; ! 229: } ! 230: /* ! 231: * if reached by a gatewayed net, discourage further links. ! 232: * this has some relevance to common carriers and the FCC ... ! 233: * the penalty inheres to hosts, not aliases, nets, or domains. ! 234: */ ! 235: if ((prev->n_flag & GATEWAYIN) && !ISADOMAIN(prev) && !(prev->n_flag & NNET)) ! 236: cost += INF/2; /* heavyweight, but appropriate */ ! 237: ! 238: /* set left/right bits */ ! 239: next->n_flag &= ~(HASLEFT|HASRIGHT); ! 240: if (NETDIR(l) == LLEFT || (prev->n_flag & HASLEFT)) ! 241: next->n_flag |= HASLEFT; ! 242: if (NETDIR(l) == LRIGHT || (prev->n_flag & HASRIGHT)) ! 243: next->n_flag |= HASRIGHT; ! 244: ! 245: return(cost); ! 246: } ! 247: ! 248: STATIC link * ! 249: rmlink(l, lprev, n) ! 250: link *l, *lprev; ! 251: node *n; ! 252: { ! 253: link *lnext; ! 254: ! 255: lnext = l->l_next; ! 256: if (lprev) ! 257: lprev->l_next = l->l_next; ! 258: else ! 259: n->n_link = l->l_next; ! 260: free((char *) l); ! 261: return(lnext); ! 262: } ! 263: ! 264: /* ! 265: * binary heap implementation of priority queue. ! 266: * TODO: make the heap smaller by giving inserting a placeholder ! 267: * for net members when the net is extracted. this requires storing the ! 268: * cost of a net in the net node itself -- yuck. is it worth it? ! 269: */ ! 270: ! 271: STATIC void ! 272: insert(l) ! 273: link *l; ! 274: { ! 275: register node *n; ! 276: ! 277: n = l->l_to; ! 278: Heap[n->n_tloc] = 0; ! 279: if (Heap[Nheap+1] != 0) { ! 280: fprintf(stderr, "%s: heap error in insert\n", ProgName); ! 281: badmagic(1); ! 282: } ! 283: if (Nheap++ == 0) { ! 284: Heap[1] = l; ! 285: n->n_tloc = 1; ! 286: return; ! 287: } ! 288: if (Vflag && Nheap > Heaphighwater) ! 289: Heaphighwater = Nheap; /* diagnostics */ ! 290: ! 291: /* insert at the end. caller must reheap(). */ ! 292: Heap[Nheap] = l; ! 293: n->n_tloc = Nheap; ! 294: } ! 295: ! 296: /* ! 297: * replace existing link in heap by this one, then ! 298: * "percolate" up the heap by exchanging with the parent ! 299: */ ! 300: STATIC void ! 301: reheap(l) ! 302: link *l; ! 303: { ! 304: register long loc, parent; ! 305: register Cost cost; ! 306: register node *n, *np; ! 307: ! 308: n = l->l_to; ! 309: ! 310: cost = n->n_cost; ! 311: for (loc = n->n_tloc; loc > 1; loc = parent) { ! 312: parent = loc / 2; ! 313: /* sanity check on implementation */ ! 314: if (Heap[parent] == 0) { ! 315: fprintf(stderr, "%s: heap error in insert\n", ProgName); ! 316: badmagic(1); ! 317: } ! 318: np = Heap[parent]->l_to; ! 319: if (cost > np->n_cost) ! 320: return; ! 321: /* move nets below hosts for output stability */ ! 322: if (cost == np->n_cost && ((n->n_flag & NNET) || !(np->n_flag & NNET))) ! 323: return; ! 324: heapswap(loc, parent); ! 325: } ! 326: } ! 327: ! 328: /* extract min (== Heap[1]) from heap */ ! 329: STATIC link * ! 330: min_node() ! 331: { ! 332: link *rval; ! 333: register link **regheap; ! 334: register long i, child; ! 335: ! 336: if (Nheap == 0) ! 337: return(0); ! 338: ! 339: regheap = Heap; /* in register -- heavily used */ ! 340: rval = regheap[1]; /* return this one */ ! 341: ! 342: /* move last entry into root, percolate down */ ! 343: regheap[1] = regheap[Nheap]; ! 344: regheap[1]->l_to->n_tloc = 1; ! 345: regheap[Nheap] = 0; ! 346: if (--Nheap == 0) ! 347: return(rval); ! 348: ! 349: i = 1; ! 350: for (;;) { ! 351: /* swap with smaller child down the tree */ ! 352: child = i * 2; /* lhs child is 2i, rhs is 2i+1. */ ! 353: if (child >= Nheap) ! 354: return(rval); ! 355: /* use rhs child if smaller than lhs child */ ! 356: if (regheap[child]->l_to->n_cost > regheap[child+1]->l_to->n_cost ! 357: || (regheap[child]->l_to->n_cost == regheap[child+1]->l_to->n_cost ! 358: && !ISANET(regheap[child+1]->l_to))) ! 359: child++; ! 360: ! 361: if (regheap[i]->l_to->n_cost < regheap[child]->l_to->n_cost) ! 362: return(rval); ! 363: /* move nets below hosts for output stability */ ! 364: if (regheap[i]->l_to->n_cost == regheap[child]->l_to->n_cost ! 365: && (!ISANET(regheap[i]->l_to) || ISANET(regheap[child]->l_to))) ! 366: return(rval); ! 367: heapswap(i, child); ! 368: i = child; ! 369: } ! 370: /*NOTREACHED*/ ! 371: } ! 372: ! 373: /* exchange Heap[i] and Heap[j] pointers */ ! 374: STATIC void ! 375: heapswap(i, j) ! 376: long i, j; ! 377: { ! 378: register link *temp, **regheap; ! 379: ! 380: regheap = Heap; /* heavily used -- put in register */ ! 381: temp = regheap[i]; ! 382: regheap[i] = regheap[j]; ! 383: regheap[j] = temp; ! 384: regheap[j]->l_to->n_tloc = j; ! 385: regheap[i]->l_to->n_tloc = i; ! 386: } ! 387: ! 388: /* return 1 if n is already de-hashed (n_tloc < Hashpart), 0 o.w. */ ! 389: dehash(n) ! 390: register node *n; ! 391: { ! 392: if (n->n_tloc < Hashpart) ! 393: return(1); ! 394: ! 395: /* swap with entry in Table[Hashpart] */ ! 396: Table[Hashpart]->n_tloc = n->n_tloc; ! 397: Table[n->n_tloc] = Table[Hashpart]; ! 398: Table[Hashpart] = n; ! 399: ! 400: n->n_tloc = Hashpart++; ! 401: return(0); ! 402: } ! 403: ! 404: backlinks() ! 405: { ! 406: link *l; ! 407: node *n, *parent, *nomap; ! 408: long i; ! 409: ! 410: for (i = Hashpart; i < Tabsize; i++) { ! 411: nomap = Table[i]; ! 412: parent = 0; ! 413: for (l = nomap->n_link; l; l = l->l_next) { ! 414: n = l->l_to; ! 415: if (!(n->n_flag & MAPPED)) ! 416: continue; ! 417: if (parent == 0) { ! 418: parent = n; ! 419: continue; ! 420: } ! 421: if (n->n_cost > parent->n_cost) ! 422: continue; ! 423: if (n->n_cost == parent->n_cost) { ! 424: nomap->n_parent = parent; ! 425: if (tiebreaker(nomap, n)) ! 426: continue; ! 427: } ! 428: parent = n; ! 429: } ! 430: if (parent == 0) ! 431: continue; ! 432: (void) dehash(nomap); ! 433: l = addlink(parent, nomap, INF, DEFNET, DEFDIR); ! 434: nomap->n_parent = parent; ! 435: nomap->n_cost = costof(parent, l); ! 436: insert(l); ! 437: reheap(l); ! 438: } ! 439: vprintf(stderr, "%d backlinks\n", Nheap); ! 440: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.