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