-- Copyright (C) 1981, 1984, 1985 by Xerox Corporation. All rights reserved. -- OthelloPup.mesa, HGM, 13-May-86 1:52:17 -- File: OthelloPup.mesa, Last Edit: HGM May 22, 1979 10:35 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 -- File: OthelloPup.mesa, Last Edit: ?? 25-Nov-81 13:22:47 -- File: OthelloPup.mesa, Last Edit: Fay 17-Dec-81 14:22:18 DIRECTORY Inline USING [LongCOPY], Process USING [Detach, GetPriority, Pause, Priority, priorityBackground, SetPriority, Yield], Buffer USING [AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer], Driver USING [GetDeviceChain, Network], OthelloDefs, PhoneNetFriends USING [PhoneNetInfo, StatsPtrToStats], Protocol1 USING [GetContext], PupDefs USING [ AppendPupAddress, DataWordsPerPupBuffer, GetPupAddress, GetPupContentsBytes, PupBuffer, PupNameTrouble, PupPackageDestroy, PupPackageMake, PupSocket, PupSocketDestroy, PupSocketMake, SecondsToTocks, SetPupContentsBytes], PupRouterDefs USING [GetRoutingTable, NetworkContext, RoutingTableEntry, RoutingTableObject], PupTypes USING [echoSoc, fillInSocketID, maxDataWordsPerGatewayPup, PupAddress]; OthelloPup: MONITOR IMPORTS Inline, Process, Buffer, Driver, PhoneNetFriends, Protocol1, PupDefs, PupRouterDefs, OthelloDefs EXPORTS Buffer = BEGIN OPEN OthelloDefs; Network: PUBLIC TYPE = Driver.Network; PrintErrorPup: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN source: PupTypes.PupAddress ← b.pup.source; NewLine[]; IF b.pup.pupType = error THEN BEGIN len: CARDINAL = PupDefs.GetPupContentsBytes[b]; WriteString["[Error Pup, code="L]; WriteOctal[LOOPHOLE[b.pup.errorCode]]; WriteString[", from: "L]; PrintPupAddress[@source]; WriteString["] "L]; FOR i: CARDINAL IN [0..len - 2*(10 + 1 + 1)) DO WriteChar[b.pup.errorText[i]] ENDLOOP; END ELSE BEGIN WriteString[" ***** "L]; WriteString["Funny PupType = "L]; WriteOctal[LOOPHOLE[b.pup.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: Buffer.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 ← Buffer.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[], maxDataWordsPerGatewayPup]; UNTIL pleaseStop DO FOR len: CARDINAL IN [0..bytesPerBuffer] UNTIL pleaseStop DO b: PupBuffer; b ← Buffer.GetBuffer[pup, pool, send, fullBuffer]; b.pup.pupID.a ← b.pup.pupID.b ← (packetNumber ← packetNumber + 1); b.pup.pupType ← echoMe; SetPupContentsBytes[b, len]; Inline.LongCOPY[to: @b.pup.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 SELECT TRUE FROM (b.pup.pupType # iAmEcho) => {funny ← funny + 1; PrintErrorPup[b]}; ((b.pup.pupID.a # packetNumber) OR (b.pup.pupID.b # packetNumber) OR (len # GetPupContentsBytes[b])) => { WriteChar['#]; late ← late + 1}; ENDCASE => { FOR i: CARDINAL IN [0..len) DO IF b.pup.pupBytes[i] # (i MOD 400B) THEN { wrong ← wrong + 1; WriteChar['~]; GOTO Wrong}; ENDLOOP; WriteChar['!]; recv ← recv + 1; EXIT}; Buffer.ReturnBuffer[b]; REPEAT Wrong => NULL; ENDLOOP; IF b # NIL THEN Buffer.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]; }; Buffer.DestroyPool[pool]; PupSocketDestroy[mySoc]; END; buffersInFlight: CARDINAL = 3; PupSender: PROCEDURE = BEGIN OPEN PupDefs, PupTypes; bytesPerBuffer: CARDINAL ← 2*PupTypes.maxDataWordsPerGatewayPup; where, me: PupTypes.PupAddress ← [, , echoSoc]; mySoc: PupSocket; sent, wait, echo, full, other: LONG CARDINAL ← 0; pleaseStop: BOOLEAN ← FALSE; snarfer: PROCESS; pool: Buffer.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 b: PupBuffer ← mySoc.get[]; IF b = NIL THEN { wait ← sent; Kick[]; LOOP; }; IF b.pup.pupType = iAmEcho THEN BEGIN wait ← LOOPHOLE[b.pup.pupID]; echo ← echo + 1; Kick[]; IF (echo MOD 100) = 0 THEN WriteChar['r]; END ELSE BEGIN IF b.pup.pupType = error AND b.pup.errorCode # resourceLimitsPupErrorCode THEN BEGIN other ← other + 1; PrintErrorPup[b]; END ELSE full ← full + 1; END; Buffer.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 ← Buffer.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 ← Buffer.GetBuffer[pup, pool, send, fullBuffer]; b.pup.pupID ← LOOPHOLE[sent]; b.pup.pupType ← echoMe; Inline.LongCOPY[to: @b.pup.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; Buffer.DestroyPool[pool]; PupSocketDestroy[mySoc]; Process.SetPriority[priority]; END; PupPhoneSender: PROCEDURE [network: Driver.Network] = 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; stats: PhoneNetFriends.PhoneNetInfo; seconds: CARDINAL; pool: Buffer.AccessHandle; priority: Process.Priority = Process.GetPriority[]; pause: CONDITION; Kick: ENTRY PROCEDURE = { NOTIFY pause; }; Wait: ENTRY PROCEDURE = { WAIT pause; }; Watch: PROCEDURE [network: Driver.Network] = BEGIN PupPhoneSender[network]; pleaseStop ← TRUE; Kick[]; END; Snarf: PROCEDURE = BEGIN UNTIL pleaseStop DO b: PupBuffer ← mySoc.get[]; IF b = NIL THEN { wait ← sent; Kick[]; LOOP; }; IF b.pup.pupType = iAmEcho THEN BEGIN wait ← LOOPHOLE[b.pup.pupID]; echo ← echo + 1; Kick[]; IF (echo MOD 100) = 0 THEN WriteChar['r]; END ELSE BEGIN IF b.pup.pupType = error AND b.pup.errorCode # resourceLimitsPupErrorCode THEN BEGIN other ← other + 1; PrintErrorPup[b]; END ELSE full ← full + 1; END; Buffer.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; stats ← PhoneNetFriends.StatsPtrToStats[network.stats]; SELECT stats.speed 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 ← Buffer.MakePool[send: buffersInFlight, receive: 2*buffersInFlight]; me ← mySoc.getLocalAddress[]; WriteString["Line "L]; OthelloDefs.WriteLongNumber[stats.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 ← PupTypes.maxDataWordsPerGatewayPup - stats.lineNumber; UNTIL pleaseStop DO b: PupBuffer ← Buffer.GetBuffer[pup, pool, send, fullBuffer]; b.pup.pupID ← LOOPHOLE[sent]; b.pup.pupType ← echoMe; Inline.LongCOPY[to: @b.pup.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[stats.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; Buffer.DestroyPool[pool]; PupSocketDestroy[mySoc]; Process.SetPriority[priority]; END; PupBlaster: PROCEDURE = BEGIN OPEN PupDefs, PupTypes; bytesPerBuffer: CARDINAL; me, where: PupAddress ← [, , echoSoc]; mySoc: PupSocket; pool: Buffer.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 b: PupBuffer ← mySoc.get[]; IF b = NIL THEN LOOP; IF b.pup.pupType = iAmEcho THEN BEGIN echo ← echo + 1; IF (echo MOD 100) = 0 THEN WriteChar['r]; END ELSE BEGIN IF b.pup.pupType = error AND b.pup.errorCode # resourceLimitsPupErrorCode THEN BEGIN other ← other + 1; PrintErrorPup[b]; END ELSE full ← full + 1; END; Buffer.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 ← Buffer.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; FOR i: CARDINAL IN [0..3) DO b ← Buffer.GetBuffer[pup, pool, send, fullBuffer]; b.pup.pupID.a ← b.pup.pupID.b ← i; b.pup.pupType ← echoMe; Inline.LongCOPY[to: @b.pup.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; Buffer.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; packet: PACKED ARRAY [0..PupTypes.maxDataWordsPerGatewayPup) OF [0..256); commandProcessor: CommandProcessor ← [Commands]; RegisterCommandProc[@commandProcessor]; FOR i: CARDINAL IN [0..PupTypes.maxDataWordsPerGatewayPup) DO packet[i] ← i; ENDLOOP; END.....