-- File: OthelloPup.mesa,  Last Edit: HGM  May 22, 1979  10:35 PM
-- File: OthelloPup.mesa,  Last Edit: Forrest July 26, 1980  8:10 PM
-- File: OthelloPup.mesa,  Last Edit: Fay/BLyon August 21, 1980  3:42 PM
-- File: OthelloPup.mesa,  Last Edit: BLyon August 29, 1980  9:21 AM
DIRECTORY
  DriverDefs USING [Network],
  OthelloDefs,
  Process USING [Detach, Yield],
  PupDefs USING [
    AppendPupAddress, DataWordsPerPupBuffer, GetFreePupBuffer,
    GetPupAddress, GetPupContentsBytes, ReturnFreePupBuffer,
    PupBuffer, PupNameTrouble, PupPackageDestroy, PupPackageMake,
    PupSocket, PupSocketDestroy, PupSocketMake, SecondsToTocks,
    SetPupContentsBytes],
  PupRouterDefs USING [GetRoutingTable, RoutingTableEntry, RoutingTableObject],
  PupTypes USING [
    echoSoc, fillInSocketID, maxDataWordsPerGatewayPup, PupAddress];
OthelloPup: PROGRAM
  IMPORTS Process, PupDefs, PupRouterDefs, OthelloDefs
  EXPORTS OthelloDefs =
BEGIN OPEN OthelloDefs;
EchoUser: PUBLIC PROC =
  BEGIN OPEN PupDefs, PupTypes;
  bytesPerBuffer: CARDINAL;
  funny, late, recv, sent, wrong: LONG CARDINAL ← 0;
  me, where: PupAddress ← [,,echoSoc];
  mySoc: PupSocket;
  name: STRING = [40];
  packetNumber: CARDINAL ← 0;
  pleaseStop: BOOLEAN ← FALSE;
  routing: PupRouterDefs.RoutingTableEntry;
  Watch: PROC = { [] ← ReadChar[]; pleaseStop ← TRUE };
  PupPackageMake[];
  GetName["Echo to: "L, name];
  GetPupAddress[@where, name
    ! PupNameTrouble =>
      { WriteString[" ***** "L]; WriteLine[e]; GOTO out }];
  mySoc ← PupSocketMake[fillInSocketID, where, SecondsToTocks[2]];
  me ← mySoc.getLocalAddress[];
  WriteString[".   ["L];
  PrintPupAddress[@me];
  WriteString["] => ["L];
  routing ← @PupRouterDefs.GetRoutingTable[][where.net];
  IF routing.hop#0 THEN
    BEGIN -- UGH
    WriteOctal[routing.network.netNumber.b];
    WriteChar[’#];
    WriteOctal[routing.route];
    WriteChar[’#];
    WriteString["] => ["L];
    END;
  PrintPupAddress[@where];
  WriteChar[’]];
  NewLine[];
  Process.Detach[FORK Watch[]];
  bytesPerBuffer ←
    2*MIN[DataWordsPerPupBuffer[], maxDataWordsPerGatewayPup];
  UNTIL pleaseStop DO
    FOR len: CARDINAL IN [0..bytesPerBuffer] UNTIL pleaseStop DO
      b: PupBuffer ← GetFreePupBuffer[];
      b.pupID.a ← b.pupID.b ← (packetNumber←packetNumber+1);
      b.pupType ← echoMe;
      SetPupContentsBytes[b,len];
      FOR i: CARDINAL IN [0..len) DO b.pupBytes[i] ← i; ENDLOOP;
      mySoc.put[b];
      sent ← sent+1;
      Process.Yield[];  -- be sure we don’t hog machine
      UNTIL (b←mySoc.get[])=NIL DO
        SELECT TRUE FROM
          (b.pupType#iAmEcho) =>
            { funny ← funny+1; PrintErrorPup[b] };
          ((b.pupID.a#packetNumber)
           OR (b.pupID.b#packetNumber)
           OR (len#GetPupContentsBytes[b])) =>
            { WriteChar[’#]; late ← late+1 };
          ENDCASE =>
            BEGIN
            FOR i: CARDINAL IN [0..len) DO
              IF b.pupBytes[i]#(i MOD 400B) THEN
                { wrong ← wrong+1; WriteChar[’~]; GOTO Wrong };
              ENDLOOP;
            WriteChar[’!];
            recv ← recv+1;
            EXIT;
            END;
        ReturnFreePupBuffer[b];
        REPEAT Wrong => NULL;
        ENDLOOP;
      IF b#NIL THEN ReturnFreePupBuffer[b] ELSE WriteChar[’?];
      ENDLOOP;
    NewLine[];
    ENDLOOP;
  PupSocketDestroy[mySoc];
  WriteString["Out: "L];
  WriteLongNumber[sent];
  WriteString[", In: "L];
  WriteLongNumber[recv];
  WriteString[" ("L];
  WriteLongNumber[(recv*100)/sent];
  WriteLine["%)"L];
  IF late#0 THEN
    BEGIN
    WriteString["Late: "L];
    WriteLongNumber[late];
    WriteString[" ("L];
    WriteLongNumber[(late*100)/sent];
    WriteLine["%)"L];
    END;
  IF funny#0 THEN { WriteLongNumber[funny]; WriteLine[" funny"L] };
  IF wrong#0 THEN
    { WriteLongNumber[wrong]; WriteLine[" wrong data"L]  };
  GOTO out
  EXITS out => PupDefs.PupPackageDestroy[];
  END;
PrintLocalPupRoutingTable: PUBLIC PROC =
  BEGIN
  pupRt: DESCRIPTOR FOR ARRAY OF
    PupRouterDefs.RoutingTableObject;
  k: CARDINAL;
  PupDefs.PupPackageMake[];
  WriteLine["\r|  Net   Via   Hops |  Net   Via   Hops |  Net   Via   Hops |"L];
  WriteLine["|-------------------|-------------------|-------------------|"L];
  k ← 0;
  pupRt ← PupRouterDefs.GetRoutingTable[];
  FOR i: CARDINAL IN [0..LENGTH[pupRt]) DO
    r: PupRouterDefs.RoutingTableEntry=@pupRt[i];
    network: DriverDefs.Network = r.network;
    IF network=NIL THEN LOOP;
    IF k=0 THEN WriteChar[’|];
    O4[i]; O4[network.netNumber.b];
    WriteChar[’#];
    O3Z[IF r.hop#0 THEN r.route ELSE network.hostNumber];
    WriteChar[’#];
    O4[r.hop];
    WriteString["  |"L];
    IF (k←k+1)=3 THEN { NewLine[]; k←0 };
    ENDLOOP;
  IF k#0 THEN NewLine[];
  PupDefs.PupPackageDestroy[];
  END;
PrintErrorPup: PROC [b: PupDefs.PupBuffer] =
  BEGIN
  source: PupTypes.PupAddress ← b.source;
  NewLine[];
  IF b.pupType=error THEN
    BEGIN
    len: CARDINAL = PupDefs.GetPupContentsBytes[b];
    WriteString["[Error Pup, code="L];
    WriteOctal[LOOPHOLE[b.errorCode]];
    WriteString[", from: "L];
    PrintPupAddress[@source];
    WriteString["] "L];
    FOR i: CARDINAL IN [0..len-2*(10+1+1)) DO
      WriteChar[b.errorText[i]]; ENDLOOP;
    END
  ELSE
    BEGIN
    WriteString[" ***** "L];
    WriteString["Funny PupType = "L];
    WriteOctal[LOOPHOLE[b.pupType]];
    WriteString[" ***** "L];
    END;
  NewLine[];
  END;
PrintPupAddress: PROC [a: POINTER TO PupTypes.PupAddress] =
  BEGIN
  buffer: STRING ← [50];
  PupDefs.AppendPupAddress[buffer, a↑];
  WriteString[buffer];
  END;
-- prints 4 chars, octal, no trailing B
O4: PROC [n: CARDINAL] = { WriteFixedWidthNumber[n, 4, 8] };
-- prints 3 chars, octal, leading zeros
O3Z: PROC [n: CARDINAL] =
  BEGIN
  n ← n MOD 1000B;
  THROUGH [0..3) DO
    WriteChar[’0 + (n/100B) MOD 10B]; n ← n * 10B; ENDLOOP;
  END;
-- initialization
END.