-- PilotCommUtilPup.mesa
  --  BLyon on March 17, 1981  4:29 PM
  --  HGM on March 14, 1981  10:07 PM

DIRECTORY
  BufferDefs USING [BufferAccessHandle, OisBuffer],
  CommUtilDefs USING [],
  Environment USING [Byte],
  EthernetOneFace USING [
    DeviceHandle, GetEthernet1Address, GetNextDevice, nullDeviceHandle],
  OISCP USING [
    GetFreeSendOisBufferFromPool, GetOisPacketTextLength,
    OiscpPackageMake, OiscpPackageDestroy, ReturnFreeOisBuffer,
    SetOisPacketTextLength],
  OISCPConstantsAdditions USING [pupAddressTranslation],
  OISCPTypesAdditions USING [pupAddrTransPacket],
  PilotMP USING [cFindPupAddress, cClient],
  ProcessorFace USING [SetMP],
  PupDefs USING [PupAddress],
  Socket USING [
    Abort, AssignNetworkAddress, Create, Delete, GetPacket, PutPacketToAllConnectedNets,
    SetWaitTime, TimeOut, TransferStatus],
  SocketInternal USING [GetBufferPool, SocketHandle],
  SpecialSystem USING [GetProcessorID, ProcessorID];

PilotCommUtilPup: MONITOR
  IMPORTS
    BufferDefs, EthernetOneFace, OISCP, ProcessorFace,
    Socket, SocketInternal, SpecialSystem
  EXPORTS CommUtilDefs, PupDefs, Socket
  SHARES BufferDefs =
  BEGIN

  -- EXPORTED TYPEs
  ChannelHandle: PUBLIC TYPE = SocketInternal.SocketHandle;

  translationRequest: CARDINAL = 1;
  translationResponse: CARDINAL = 2;
  translationError: CARDINAL = 3;

  myHostNumber: CARDINAL ← 0;

  SmashMyHostNumber: PUBLIC ENTRY PROCEDURE [new: CARDINAL] =
    BEGIN
    myHostNumber ← new;
    END;  -- SmashMyhostNumber

  GetEthernetHostNumber: PUBLIC ENTRY PROCEDURE RETURNS [CARDINAL] =
    BEGIN
    i: CARDINAL;
    cH: ChannelHandle;
    myBufferAccessHandle: BufferDefs.BufferAccessHandle;
    hit: BOOLEAN;
    b: BufferDefs.OisBuffer;
    status: Socket.TransferStatus;
    where: LONG POINTER TO SpecialSystem.ProcessorID;
    myID: SpecialSystem.ProcessorID;
    ether: EthernetOneFace.DeviceHandle;

    IF myHostNumber#0 THEN RETURN[myHostNumber];  -- easy known case

    -- if the machine has a real ethernetOne then get the address from the device
    ether ← EthernetOneFace.GetNextDevice[EthernetOneFace.nullDeviceHandle];
    IF ether#EthernetOneFace.nullDeviceHandle THEN
      BEGIN
      net, host: Environment.Byte;
      [net, host] ← EthernetOneFace.GetEthernet1Address[ether];
      RETURN[myHostNumber ← host];
      END;

    -- hard case: there is no ethernetOne, so probe for it.
    ProcessorFace.SetMP[PilotMP.cFindPupAddress];
    OISCP.OiscpPackageMake[];
    cH ← Socket.Create[Socket.AssignNetworkAddress[]];
    Socket.SetWaitTime[cH, 3000];
    myBufferAccessHandle ← SocketInternal.GetBufferPool[cH];
    myID ← SpecialSystem.GetProcessorID[];
    hit ← FALSE;
    UNTIL hit DO
      i ← i + 1;
      b ← OISCP.GetFreeSendOisBufferFromPool[myBufferAccessHandle];
      OISCP.SetOisPacketTextLength[b, 2*(3+SIZE[SpecialSystem.ProcessorID])];
      b.ois.transCntlAndPktTp.packetType ← OISCPTypesAdditions.pupAddrTransPacket;
      b.ois.destination.socket ← OISCPConstantsAdditions.pupAddressTranslation;
      b.ois.oisWords[0] ← b.ois.oisWords[1] ← i;
      b.ois.oisWords[2] ← translationRequest;
      where ← LOOPHOLE[@b.ois.oisWords[3]];
      where↑ ← myID;
      Socket.PutPacketToAllConnectedNets[cH, b];
      UNTIL hit DO
        b ← Socket.GetPacket[cH ! Socket.TimeOut => EXIT];
        status ← LOOPHOLE[b.status];
        IF (status = goodCompletion)
        AND (OISCP.GetOisPacketTextLength[b] >= 2*(3 + SIZE[PupDefs.PupAddress]))
        AND (b.ois.oisWords[2] = translationResponse) THEN
          BEGIN -- the response we were looking for
          myLoc: LONG POINTER TO PupDefs.PupAddress = LOOPHOLE[@b.ois.oisWords[3]];
          me: PupDefs.PupAddress ← myLoc↑;
          myHostNumber ← me.host;
          hit ← TRUE;
          END;
        OISCP.ReturnFreeOisBuffer[b];
        ENDLOOP;
      ENDLOOP;
    Socket.Abort[cH];
    Socket.Delete[cH];
    OISCP.OiscpPackageDestroy[];
    ProcessorFace.SetMP[PilotMP.cClient];
    RETURN[myHostNumber];

    END;  -- GetEthernetHostNumber

  END..