-- File: PupRouterCool.Mesa,  Last Edit:
--   HGM  July 15, 1979  9:35 PM
--   Taft  May 10, 1983  2:43 PM
-- This section of code is mostly used when creating/destroying sockets

-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  CommUtilDefs: FROM "CommUtilDefs" USING [InitializeCondition, GetTicks],
  PupRouterDefs: FROM "PupRouterDefs" USING [
    routerLock, maxHop, BeSurePupIsOn,
    IfMissing, PupRoutingTableEntry, RoutingCacheEntry, GetRoutingCacheEntry,
    firstSocket, PupRouterSocket],
  DriverDefs: FROM "DriverDefs" USING [doDebug, Network, GetDeviceChain],
  PupDefs: FROM "PupDefs", -- EXPORTS
  BufferDefs: FROM "BufferDefs" USING [QueueInitialize, QueueCleanup],
  PupTypes: FROM "PupTypes" USING [
    fillInNetID, fillInHostID, fillInSocketID,
    PupAddress, PupNetID, PupSocketID, Pair];

PupRouterCool: MONITOR LOCKS PupRouterDefs.routerLock
  IMPORTS CommUtilDefs, DriverDefs, PupRouterDefs, BufferDefs
  EXPORTS PupDefs, PupRouterDefs =
PUBLIC BEGIN OPEN PupTypes, PupRouterDefs;

spareSocket: CARDINAL ← 1000B;
nextConnectionID: CARDINAL ← 1000;

UniqueLocalPupSocketID: PUBLIC ENTRY PROCEDURE RETURNS [socket: PupSocketID] =
  BEGIN
  IF (spareSocket←spareSocket+1)=0 THEN spareSocket←1000B;
  socket ← [CommUtilDefs.GetTicks[],spareSocket];
  END;

UniqueLocalPupAddress: PUBLIC PROCEDURE [him: POINTER TO PupAddress]  RETURNS [me: PupAddress] =
  BEGIN
  RETURN[GetLocalPupAddress[PupTypes.fillInSocketID,him]];
  END;

NextPupConnectionID: PUBLIC ENTRY PROCEDURE RETURNS [p: PupTypes.Pair] =
  BEGIN
  p.a ← CommUtilDefs.GetTicks[];
  p.b ← nextConnectionID ← nextConnectionID+1;
  END;

GetLocalPupAddress: PUBLIC PROCEDURE [local: PupSocketID, remote: POINTER TO PupAddress] RETURNS [me: PupAddress] =
  BEGIN
  destNet: CARDINAL ← 0;
  network: DriverDefs.Network ← NIL;
  -- Don't get fancy here unless this machine actually has multiple net addresses.
  -- Aspects of this logic are still moderately buggy....
  IF DriverDefs.GetDeviceChain[].next#NIL THEN
    BEGIN
    IF remote#NIL THEN
      BEGIN OPEN PupTypes;
      destNet ← remote.net;
      -- Maybe we should scan for the right net if he specifies a host?
      IF remote.net=fillInNetID OR remote.host=fillInHostID THEN destNet ← 0;
      END;
    network ← GetPupRoutingTableEntry[net: [destNet]].network;
    END;
  IF network=NIL THEN network ← DriverDefs.GetDeviceChain[];
  me.net ← [network.netNumber];
  me.host ← [network.hostNumber];
  me.socket ← IF local#PupTypes.fillInSocketID THEN local ELSE UniqueLocalPupSocketID[];
  IF remote#NIL THEN
    BEGIN OPEN PupTypes;
    IF remote.net=fillInNetID THEN remote.net ← me.net;
    IF remote.host=fillInHostID THEN remote.host ← me.host;
    IF remote.socket=fillInSocketID THEN remote.socket ← me.socket;
    END;
  END;

PupRouterKnowAboutSocket: PUBLIC ENTRY PROCEDURE [so: PupRouterSocket] =
  BEGIN
  IF DriverDefs.doDebug THEN BeSurePupIsOn[];
  CommUtilDefs.InitializeCondition[@so.ready,0];
  BufferDefs.QueueInitialize[@so.input];
  so.next ← firstSocket;
  firstSocket ← so;
  END;

PupRouterForgetAboutSocket: PUBLIC ENTRY PROCEDURE [so: PupRouterSocket] =
  BEGIN
  previous: PupRouterSocket;
  IF DriverDefs.doDebug THEN BeSurePupIsOn[];
  IF firstSocket=so THEN firstSocket ← so.next
  ELSE FOR previous←firstSocket,previous.next UNTIL previous=NIL DO
    IF previous.next=so THEN
      BEGIN previous.next ← so.next; EXIT; END;
    ENDLOOP;
  BufferDefs.QueueCleanup[@so.input];
  END;

GetFirstPupSocket: PROCEDURE RETURNS [PupRouterSocket] =
  BEGIN
  BeSurePupIsOn[];
  RETURN[firstSocket];
  END;

GetHopsToNetwork: PROCEDURE [net: PupTypes.PupNetID] RETURNS [CARDINAL] =
  BEGIN
  BeSurePupIsOn[];
  RETURN[GetPupRoutingTableEntry[net: net].hop];
  END;

GetPupRoutingTableEntry: ENTRY PROCEDURE [
  net: PupNetID, ifMissing: IfMissing ← probeAndWait, promote: BOOLEAN ← TRUE]
  RETURNS [PupRoutingTableEntry] =
  BEGIN
  rte: POINTER TO RoutingCacheEntry ← GetRoutingCacheEntry[
    net: net, ifMissing: ifMissing, promote: promote];
  RETURN [IF rte#NIL THEN rte.entry
    ELSE [hop: maxHop+1, time: 0, route: [0], network: NIL]];
  END;

END.