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: }

Defined functions

backlinks defined in line 404; used 1 times
costof defined in line 188; used 3 times
dehash defined in line 389; used 3 times
heapswap defined in line 374; used 4 times
insert defined in line 271; used 4 times
mapit defined in line 20; used 1 times
min_node defined in line 329; used 2 times
reheap defined in line 300; used 3 times
rmlink defined in line 248; used 3 times
skiplink defined in line 142; used 1 times
  • in line 63

Defined variables

Heap defined in line 15; used 11 times
Heaphighwater defined in line 14; used 4 times
Nheap defined in line 13; used 17 times
STATIC defined in line 374; never used
sccsid defined in line 3; never used
Last modified: 1986-02-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1807
Valid CSS Valid XHTML 1.0 Strict