-- 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.