-- File: OthelloPup.mesa - last edit:
-- AOF 5-Feb-88 18:42:55
-- WIrish 3-Jun-86 12:55:53
-- ?? 25-Nov-81 13:22:47
-- Fay 17-Dec-81 14:22:18
-- HGM 13-May-86 1:52:17
-- Fay/BLyon August 21, 1980 3:42 PM
-- BLyon August 29, 1980 9:21 AM
-- HGM May 22, 1979 10:35 PM
-- Copyright (C) 1981, 1984, 1985, 1988 by Xerox Corporation. All rights reserved.
DIRECTORY
Buffer USING [],
Inline USING [LongCOPY],
Process USING [
Detach, GetPriority, Pause, Priority, priorityBackground, SetPriority, Yield],
Driver USING [GetDeviceChain, Device],
OthelloDefs,
Protocol1 USING [GetContext],
PupDefs USING [
AppendPupAddress, Body, Buffer, DataWordsPerPupBuffer, GetPupAddress,
GetPupContentsBytes, PupBuffer, PupNameTrouble,
PupPackageDestroy, PupPackageMake, PupSocket, PupSocketDestroy,
PupSocketMake, SecondsToTocks, SetPupContentsBytes,
AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer],
PupRouterDefs USING [GetRoutingTable, NetworkContext, RoutingTableEntry, RoutingTableObject],
PupTypes USING [echoSoc, fillInSocketID, PupAddress];
OthelloPup: MONITOR
IMPORTS Inline, Process, Driver, Protocol1, PupDefs, PupRouterDefs, OthelloDefs
EXPORTS Buffer =
BEGIN OPEN OthelloDefs;
Device: PUBLIC TYPE = Driver.Device;
PrintErrorPup: PROCEDURE [b: PupDefs.Buffer] =
BEGIN
body: PupDefs.Body = b.pup;
source: PupTypes.PupAddress ← body.source;
NewLine[];
IF body.pupType = error THEN
BEGIN
len: CARDINAL = PupDefs.GetPupContentsBytes[b];
WriteString["[Error Pup, code="L];
WriteOctal[LOOPHOLE[body.errorCode]];
WriteString[", from: "L];
PrintPupAddress[@source];
WriteString["] "L];
FOR i: CARDINAL IN [0..len - 2*(10 + 1 + 1)) DO
WriteChar[body.errorText[i]] ENDLOOP;
END
ELSE
BEGIN
WriteString[" ***** "L];
WriteString["Funny PupType = "L];
WriteOctal[LOOPHOLE[body.pupType]];
WriteString[" ***** "L];
END;
NewLine[];
END;
EchoUser: PROCEDURE =
BEGIN OPEN PupDefs, PupTypes;
bytesPerBuffer: CARDINAL;
funny, late: LONG CARDINAL ← 0;
recv, sent: LONG CARDINAL ← 0;
wrong: LONG CARDINAL ← 0;
me, where: PupAddress ← [, , echoSoc];
mySoc: PupSocket;
pool: PupDefs.AccessHandle;
packetNumber: CARDINAL ← 0;
routing: PupRouterDefs.RoutingTableEntry;
pleaseStop: BOOLEAN ← FALSE;
Watch: PROCEDURE =
BEGIN
[] ← ReadChar[ ! ABORTED => CONTINUE];
pleaseStop ← TRUE;
END;
GetName["Echo to: "L, @echoName];
GetPupAddress[
@where, echoName ! PupNameTrouble => AbortingCommand[e]];
routing ← @PupRouterDefs.GetRoutingTable[][where.net];
IF routing=NIL OR routing.context = NIL THEN AbortingCommand["Can't reach that network"L];
mySoc ← PupSocketMake[fillInSocketID, where, SecondsToTocks[5]];
pool ← PupDefs.MakePool[send: 3, receive: 5];
me ← mySoc.getLocalAddress[];
PrintPupAddress[@me];
WriteString[" => "L];
IF routing.hop # 0 THEN {
WriteOctal[routing.context.pupNetNumber];
WriteChar['#];
WriteOctal[routing.route];
WriteChar['#];
WriteString[" => "L]; };
PrintPupAddress[@where];
NewLine[];
Process.Detach[FORK Watch[]];
bytesPerBuffer ← 2*MIN[DataWordsPerPupBuffer[], newMaxDataWordsPerGatewayPup];
UNTIL pleaseStop DO
FOR len: CARDINAL IN [0..bytesPerBuffer] UNTIL pleaseStop DO
b: PupBuffer;
body: PupDefs.Body;
body ← (b ← PupDefs.GetBuffer[pool, send]).pup;
body.pupID.a ← body.pupID.b ← (packetNumber ← packetNumber + 1);
body.pupType ← echoMe;
SetPupContentsBytes[b, len];
Inline.LongCOPY[to: @body.pupBytes, from: @packet, nwords: (len+1)/2];
mySoc.put[b];
sent ← sent + 1;
Process.Yield[]; -- be sure we don't hog machine
UNTIL (b ← mySoc.get[]) = NIL DO
body ← b.pup;
SELECT TRUE FROM
(body.pupType # iAmEcho) => {funny ← funny + 1; PrintErrorPup[b]};
((body.pupID.a # packetNumber) OR (body.pupID.b # packetNumber)
OR (len # GetPupContentsBytes[b])) => {
WriteChar['#]; late ← late + 1};
ENDCASE => {
FOR i: CARDINAL IN [0..len) DO
IF body.pupBytes[i] # (i MOD 400B) THEN {
wrong ← wrong + 1; WriteChar['~]; GOTO Wrong};
ENDLOOP;
WriteChar['!];
recv ← recv + 1;
EXIT};
PupDefs.ReturnBuffer[b];
REPEAT Wrong => NULL;
ENDLOOP;
IF b # NIL THEN PupDefs.ReturnBuffer[b] ELSE WriteChar['?];
ENDLOOP;
NewLine[];
ENDLOOP;
WriteLine["."L];
WriteString["Out: "L];
WriteLongNumber[sent];
WriteString[", In: "L];
WriteLongNumber[recv];
IF sent # 0 THEN {
WriteString[" ("L];
WriteLongNumber[(recv*100)/sent];
WriteLine["%)"L];
IF late # 0 THEN {
WriteString["Late: "L];
WriteLongNumber[late];
WriteString[" ("L];
WriteLongNumber[(late*100)/sent];
WriteLine["%)"L]; }; };
IF funny # 0 THEN {
WriteLongNumber[funny];
WriteLine[" funny"L]; };
IF wrong # 0 THEN {
WriteLongNumber[wrong];
WriteLine[" wrong data"L]; };
PupDefs.DestroyPool[pool];
PupSocketDestroy[mySoc];
END;
buffersInFlight: CARDINAL = 3;
PupSender: PROCEDURE =
BEGIN OPEN PupDefs, PupTypes;
bytesPerBuffer: CARDINAL ← 2*MIN[DataWordsPerPupBuffer[], newMaxDataWordsPerGatewayPup];
where, me: PupTypes.PupAddress ← [, , echoSoc];
mySoc: PupSocket;
sent, wait, echo, full, other: LONG CARDINAL ← 0;
pleaseStop: BOOLEAN ← FALSE;
snarfer: PROCESS;
pool: PupDefs.AccessHandle;
priority: Process.Priority = Process.GetPriority[];
routing: PupRouterDefs.RoutingTableEntry;
pause: CONDITION;
Kick: ENTRY PROCEDURE = { NOTIFY pause; };
Wait: ENTRY PROCEDURE = { WAIT pause; };
Watch: PROCEDURE =
BEGIN
[] ← ReadChar[ ! ABORTED => CONTINUE];
pleaseStop ← TRUE;
Kick[];
END;
Snarf: PROCEDURE =
BEGIN
UNTIL pleaseStop DO
body: PupDefs.Body;
b: PupBuffer ← mySoc.get[];
IF b = NIL THEN { wait ← sent; Kick[]; LOOP; };
body ← b.pup;
IF body.pupType = iAmEcho THEN
BEGIN
wait ← LOOPHOLE[body.pupID];
echo ← echo + 1;
Kick[];
IF (echo MOD 100) = 0 THEN WriteChar['r];
END
ELSE
BEGIN
IF body.pupType = error AND body.errorCode # resourceLimitsPupErrorCode THEN
BEGIN
other ← other + 1;
PrintErrorPup[b];
END
ELSE full ← full + 1;
END;
PupDefs.ReturnBuffer[b];
ENDLOOP;
Kick[];
END;
GetName["Send to: "L, @echoName];
GetPupAddress[
@where, echoName ! PupNameTrouble => AbortingCommand[e]];
routing ← @PupRouterDefs.GetRoutingTable[][where.net];
IF routing=NIL OR routing.context = NIL THEN AbortingCommand["Can't reach that network"L];
mySoc ← PupSocketMake[fillInSocketID, where, PupDefs.SecondsToTocks[1]];
pool ← PupDefs.MakePool[send: buffersInFlight, receive: 2*buffersInFlight];
me ← mySoc.getLocalAddress[];
PrintPupAddress[@me];
WriteString[" => "L];
IF routing.hop # 0 THEN
BEGIN
WriteOctal[routing.context.pupNetNumber];
WriteChar['#];
WriteOctal[routing.route];
WriteChar['#];
WriteString[" => "L];
END;
PrintPupAddress[@where];
NewLine[];
Process.SetPriority[Process.priorityBackground];
Process.Detach[FORK Watch[]];
snarfer ← FORK Snarf[];
UNTIL pleaseStop DO
b: PupBuffer ← PupDefs.GetBuffer[pool, send];
body: PupDefs.Body ← b.pup;
body.pupID ← LOOPHOLE[sent];
body.pupType ← echoMe;
Inline.LongCOPY[to: @body.pupBytes, from: @packet, nwords: (bytesPerBuffer+1)/2];
SetPupContentsBytes[b, bytesPerBuffer];
mySoc.put[b];
sent ← sent + 1;
IF (sent-wait) >= buffersInFlight THEN Wait[];
IF (sent MOD 100) = 0 THEN {
WriteChar['s];
Process.Pause[2]; };
ENDLOOP;
NewLine[];
WriteString["Sent "L];
WriteLongNumber[sent];
WriteString[", Echoed "L];
WriteLongNumber[echo];
IF sent # 0 THEN {
WriteString[" ("L];
WriteLongNumber[(echo*100)/sent];
WriteString["%)"L]; };
IF full # 0 THEN
BEGIN
WriteString[", BufferFull "L];
WriteLongNumber[full];
END;
IF other # 0 THEN
BEGIN
WriteString[", Other "L];
WriteLongNumber[other];
END;
WriteLine["."L];
JOIN snarfer;
PupDefs.DestroyPool[pool];
PupSocketDestroy[mySoc];
Process.SetPriority[priority];
END;
PupPhoneSender: PROCEDURE [network: Device] =
BEGIN OPEN PupDefs, PupTypes;
bytesPerBuffer: CARDINAL;
where, me: PupTypes.PupAddress;
mySoc: PupSocket;
sent, wait, echo, full, other: LONG CARDINAL ← 0;
pleaseStop: BOOLEAN ← FALSE;
snarfer: PROCESS;
pup: PupRouterDefs.NetworkContext;
seconds: CARDINAL;
pool: PupDefs.AccessHandle;
priority: Process.Priority = Process.GetPriority[];
pause: CONDITION;
Kick: ENTRY PROCEDURE = { NOTIFY pause; };
Wait: ENTRY PROCEDURE = { WAIT pause; };
Watch: PROCEDURE [network: Device] =
BEGIN
PupPhoneSender[network];
pleaseStop ← TRUE;
Kick[];
END;
Snarf: PROCEDURE =
BEGIN
UNTIL pleaseStop DO
body: PupDefs.Body;
b: PupBuffer ← mySoc.get[];
IF b = NIL THEN { wait ← sent; Kick[]; LOOP; };
body ← b.pup;
IF body.pupType = iAmEcho THEN
BEGIN
wait ← LOOPHOLE[body.pupID];
echo ← echo + 1;
Kick[];
IF (echo MOD 100) = 0 THEN WriteChar['r];
END
ELSE
BEGIN
IF body.pupType = error AND body.errorCode # resourceLimitsPupErrorCode THEN
BEGIN
other ← other + 1;
PrintErrorPup[b];
END
ELSE full ← full + 1;
END;
PupDefs.ReturnBuffer[b];
ENDLOOP;
Kick[];
END;
DO
IF network = NIL THEN {
-- No more phone lines. Wait for typein.
[] ← ReadChar[ ! ABORTED => CONTINUE];
RETURN; };
IF network.device = phonenet THEN {
pup ← Protocol1.GetContext[network, pup];
IF pup.pupNetNumber # 0 THEN EXIT; };
network ← network.next;
ENDLOOP;
SELECT network.lineSpeed FROM -- Packet makes 4 trips: out, back, echo out, echo back
0 => seconds ← 2; -- Argh: Kluger's phone driver. Guess!
1 => seconds ← 20; -- Yetch. Where did this come from?
2, 3 => seconds ← 12; -- 2400, dial up (2 seconds per packet)
4, 5, 6 => seconds ← 8;
7, 8 => seconds ← 4;
9 => seconds ← 2; -- 9600 is 1/2 second per packet
ENDCASE => seconds ← 1;
where ← [[pup.pupNetNumber], [pup.pupHostNumber], PupTypes.echoSoc];
mySoc ← PupSocketMake[fillInSocketID, where, PupDefs.SecondsToTocks[seconds]];
pool ← PupDefs.MakePool[send: buffersInFlight, receive: 2*buffersInFlight];
me ← mySoc.getLocalAddress[];
WriteString["Line "L];
OthelloDefs.WriteLongNumber[network.lineNumber];
WriteString[": "L];
PrintPupAddress[@me];
WriteString[" to "L];
PrintPupAddress[@where];
NewLine[];
Process.SetPriority[Process.priorityBackground];
Process.Detach[FORK Watch[network.next]];
snarfer ← FORK Snarf[];
bytesPerBuffer ← (2*MIN[DataWordsPerPupBuffer[], newMaxDataWordsPerGatewayPup]) - network.lineNumber;
UNTIL pleaseStop DO
b: PupBuffer ← PupDefs.GetBuffer[pool, send];
body: PupDefs.Body ← b.pup;
body.pupID ← LOOPHOLE[sent];
body.pupType ← echoMe;
Inline.LongCOPY[to: @body.pupBytes, from: @packet, nwords: (bytesPerBuffer+1)/2];
SetPupContentsBytes[b, bytesPerBuffer];
mySoc.put[b];
sent ← sent + 1;
IF (sent-wait) >= buffersInFlight THEN Wait[];
IF (sent MOD 100) = 0 THEN {
WriteChar['s];
Process.Pause[2]; };
ENDLOOP;
NewLine[];
WriteString["Line "L];
OthelloDefs.WriteLongNumber[network.lineNumber];
WriteString[": "L];
WriteString["Sent "L];
WriteLongNumber[sent];
WriteString[", Echoed "L];
WriteLongNumber[echo];
IF sent # 0 THEN {
WriteString[" ("L];
WriteLongNumber[(echo*100)/sent];
WriteString["%)"L]; };
IF full # 0 THEN
BEGIN
WriteString[", BufferFull "L];
WriteLongNumber[full];
END;
IF other # 0 THEN
BEGIN
WriteString[", Other "L];
WriteLongNumber[other];
END;
WriteLine["."L];
JOIN snarfer;
PupDefs.DestroyPool[pool];
PupSocketDestroy[mySoc];
Process.SetPriority[priority];
END;
PupBlaster: PROCEDURE =
BEGIN OPEN PupDefs, PupTypes;
bytesPerBuffer: CARDINAL;
me, where: PupAddress ← [, , echoSoc];
mySoc: PupSocket;
pool: PupDefs.AccessHandle;
sent, echo, full, other: LONG CARDINAL ← 0;
routing: PupRouterDefs.RoutingTableEntry;
pleaseStop: BOOLEAN ← FALSE;
snarfer: PROCESS;
Watch: PROCEDURE =
BEGIN
[] ← ReadChar[ ! ABORTED => CONTINUE];
pleaseStop ← TRUE;
END;
Snarf: PROCEDURE =
BEGIN
UNTIL pleaseStop DO
body: PupDefs.Body;
b: PupBuffer ← mySoc.get[];
IF b = NIL THEN LOOP;
body ← b.pup;
IF body.pupType = iAmEcho THEN
BEGIN
echo ← echo + 1;
IF (echo MOD 100) = 0 THEN WriteChar['r];
END
ELSE
BEGIN
IF body.pupType = error AND body.errorCode # resourceLimitsPupErrorCode THEN
BEGIN
other ← other + 1;
PrintErrorPup[b];
END
ELSE full ← full + 1;
END;
PupDefs.ReturnBuffer[b];
ENDLOOP;
END;
GetName["Blast to: "L, @echoName];
GetPupAddress[
@where, echoName ! PupNameTrouble => AbortingCommand[e]];
routing ← @PupRouterDefs.GetRoutingTable[][where.net];
IF routing=NIL OR routing.context = NIL THEN AbortingCommand["Can't reach that network"L];
mySoc ← PupSocketMake[fillInSocketID, where, PupDefs.SecondsToTocks[1]];
pool ← PupDefs.MakePool[send: 3, receive: 5];
me ← mySoc.getLocalAddress[];
PrintPupAddress[@me];
WriteString[" => "L];
IF routing.hop # 0 THEN
BEGIN
WriteOctal[routing.context.pupNetNumber];
WriteChar['#];
WriteOctal[routing.route];
WriteChar['#];
WriteString[" => "L];
END;
PrintPupAddress[@where];
NewLine[];
Process.Detach[FORK Watch[]];
snarfer ← FORK Snarf[];
bytesPerBuffer ← 100;
UNTIL pleaseStop DO
b: PupBuffer;
body: PupDefs.Body;
FOR i: CARDINAL IN [0..3) DO
body ← (b ← PupDefs.GetBuffer[pool, send]).pup;
body.pupID.a ← body.pupID.b ← i;
body.pupType ← echoMe;
Inline.LongCOPY[to: @body.pupBytes, from: @packet, nwords: (bytesPerBuffer+1)/2];
SetPupContentsBytes[b, bytesPerBuffer];
mySoc.put[b];
sent ← sent + 1;
IF (sent MOD 100) = 0 THEN BEGIN WriteChar['s]; Process.Pause[1]; END;
ENDLOOP;
Process.Yield[]; -- be sure we don't hog machine
ENDLOOP;
NewLine[];
WriteString["Sent: "L];
WriteLongNumber[sent];
WriteString[", Echoed: "L];
WriteLongNumber[echo];
IF sent # 0 THEN {
WriteString[" ("L];
WriteLongNumber[(echo*100)/sent];
WriteString["%)"L]; };
IF full # 0 THEN
BEGIN
WriteString[", BufferFull: "L];
WriteLongNumber[full];
END;
IF other # 0 THEN
BEGIN
WriteString[", Other: "L];
WriteLongNumber[other];
END;
WriteLine["."L];
JOIN snarfer;
PupDefs.DestroyPool[pool];
PupSocketDestroy[mySoc];
END;
PrintLocalPupRoutingTable: PROCEDURE =
BEGIN
pupRt: LONG DESCRIPTOR FOR ARRAY OF PupRouterDefs.RoutingTableObject;
k: CARDINAL ← 0;
WriteLine["| Net Via Hops | Net Via Hops | Net Via Hops | Net Via Hops |"L];
WriteLine["|-----------------|-----------------|-----------------|-----------------|"L];
pupRt ← PupRouterDefs.GetRoutingTable[];
FOR i: CARDINAL IN [0..LENGTH[pupRt]) DO
D3: PROC [n: CARDINAL] = INLINE {WriteFixedWidthNumber[n, 3, 10]};
O4: PROC [n: CARDINAL] = INLINE {WriteFixedWidthNumber[n, 4, 8]};
O3Z: PROC [n: CARDINAL] = {
n ← n MOD 1000B;
THROUGH [0..3) DO WriteChar['0 + (n/100B) MOD 10B]; n ← n*10B ENDLOOP};
rte: PupRouterDefs.RoutingTableEntry = @pupRt[i];
context: PupRouterDefs.NetworkContext = rte.context;
OthelloDefs.CheckUserAbort[! ABORTED => EXIT];
IF context = NIL THEN LOOP;
IF k = 0 THEN WriteChar['|];
O4[i];
O4[context.pupNetNumber];
WriteChar['#];
O3Z[IF rte.hop # 0 THEN rte.route ELSE context.pupHostNumber];
WriteChar['#];
D3[rte.hop];
WriteString[" |"L];
IF (k ← k + 1) = 4 THEN BEGIN NewLine[]; k ← 0; Process.Yield[]; END;
ENDLOOP;
IF k # 0 THEN NewLine[];
END;
PrintPupAddress: PROC [a: POINTER TO PupTypes.PupAddress] = {
buffer: STRING ← [50];
PupDefs.AppendPupAddress[buffer, a↑]; WriteString[buffer]};
echoName: LONG STRING ← NIL;
Commands: PROC [index: CARDINAL] =
BEGIN
SELECT index FROM
0 => {
MyNameIs[myNameIs: "Pup Blaster"L, myHelpIs: "Send lots of echo Pups (no wait)"L];
[] ← PupDefs.PupPackageMake[];
PupBlaster[! UNWIND => PupDefs.PupPackageDestroy[]]};
1 => {
MyNameIs[myNameIs: "Pup Echo User"L, myHelpIs: "Pup echo user (one at a time)"L];
[] ← PupDefs.PupPackageMake[];
EchoUser[! UNWIND => PupDefs.PupPackageDestroy[]]};
2 => {
MyNameIs[myNameIs: "Pup PhoneLine Sender"L, myHelpIs: "Send Echo Pups on all Phone lines"L];
[] ← PupDefs.PupPackageMake[];
PupPhoneSender[Driver.GetDeviceChain[] ! UNWIND => PupDefs.PupPackageDestroy[]]};
3 => {
MyNameIs[myNameIs: "Pup Sender"L, myHelpIs: "Send echo Pups (3 in flight at once)"L];
[] ← PupDefs.PupPackageMake[];
PupSender[! UNWIND => PupDefs.PupPackageDestroy[]]};
4 => {
MyNameIs[
myNameIs: "Pup Routing Tables"L,
myHelpIs: "Show pup network routing tables"L];
[] ← PupDefs.PupPackageMake[];
PrintLocalPupRoutingTable[! UNWIND => PupDefs.PupPackageDestroy[]]};
ENDCASE => IndexTooLarge;
PupDefs.PupPackageDestroy[];
END;
newMaxBytesPerPacket: CARDINAL = 1478;
newMaxDataWordsPerGatewayPup: CARDINAL = newMaxBytesPerPacket/2;
packet: PACKED ARRAY [0..newMaxBytesPerPacket) OF [0..256);
commandProcessor: CommandProcessor ← [Commands];
RegisterCommandProc[@commandProcessor];
FOR i: CARDINAL IN [0..newMaxBytesPerPacket) DO
packet[i] ← i;
ENDLOOP;
END.....