-- Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved. -- OthelloNS.mesa, HGM, 5-Oct-85 13:14:24 DIRECTORY Format USING [HostNumber, NetworkAddress, NetworkNumber, NetFormat, StringProc], OthelloDefs USING [ AbortingCommand, CheckUserAbort, CommandProcessor, IndexTooLarge, MyNameIs, NewLine, ReadChar, RegisterCommandProc, WriteChar, WriteLine, WriteLongNumber, WriteString], OthelloForgot USING [GetNameWithSpaces], Process USING [Detach, Yield], Runtime USING [UnboundProcedure], String USING [AppendChar, AppendNumber, AppendString], System USING [ HostNumber, localHostNumber, NetworkAddress, NetworkNumber, nullHostNumber, nullNetworkNumber, nullSocketNumber, SocketNumber], Unformat USING [Error, NetworkAddress], AddressTranslation USING [Error, PrintError, StringToNetworkAddress], Buffer USING [NSBuffer], Driver USING [GetDeviceChain, Network], EthernetDriverFriends USING [EtherStatsInfo], InrFriends USING [DriverDetails, GetRouteInfo], NS3MBit USING [GetInfo], NSConstants USING [echoerSocket], NSTypes USING [maxIDPDataWords], PhoneNetFriends USING [PhoneNetInfo, StatsPtrToStats], PhoneNetExtras USING [ leafBytesSend, leafDupsFiltered, leafPktsSend, nsBytesSend, nsCongestion, nsDupsFiltered, nsTooGreedy, pupBytesSend, pupCongestion, pupDupsFiltered, pupTooGreedy], Protocol1 USING [GetContext], Pup10MBit USING [EnumerateTranslation], PupTypes USING [PupHostID], PupRouterDefs USING [NetworkContext], Router USING [ endEnumeration, EnumerateRoutingTable, infinity, NoTableEntryForNet, startEnumeration], RoutingTable USING [NetworkContext], Socket USING [ ChannelHandle, Create, Delete, GetAssignedAddress, GetPacket, GetPacketBytes, GetSendBuffer, PutPacket, ReturnBuffer, SetDestination, SetPacketWords, SetWaitTime, TimeOut]; OthelloNS: PROGRAM IMPORTS Format, NS3MBit, OthelloDefs, OthelloForgot, Process, Runtime, String, System, Unformat, AddressTranslation, Driver, InrFriends, PhoneNetFriends, Protocol1, Pup10MBit, Router, Socket EXPORTS Buffer = BEGIN Network: PUBLIC TYPE = Driver.Network; EchoUser: PROCEDURE = BEGIN funny, late, missed: LONG CARDINAL ← 0; recv, sent: LONG CARDINAL ← 0; wrong: LONG CARDINAL ← 0; him: System.NetworkAddress; soc: Socket.ChannelHandle; packetNumber: CARDINAL ← 0; b: Buffer.NSBuffer; pktBody: LONG POINTER TO ARRAY [0..0) OF WORD; pleaseStop: BOOLEAN ← FALSE; Watch: PROCEDURE = BEGIN [] ← OthelloDefs.ReadChar[ ! ABORTED => CONTINUE]; pleaseStop ← TRUE; END; OthelloForgot.GetNameWithSpaces["Echo to: "L, @echoName]; him ← GetAddress[echoName, NSConstants.echoerSocket ! Trouble => OthelloDefs.AbortingCommand[reason]]; soc ← Socket.Create[System.nullSocketNumber]; Socket.SetWaitTime[soc, 5000]; WriteAddresses[Socket.GetAssignedAddress[soc]]; OthelloDefs.WriteString[" => "L]; WriteAddresses[him]; OthelloDefs.NewLine[]; Process.Detach[FORK Watch[]]; UNTIL pleaseStop DO cycle: CARDINAL; IF (((packetNumber ← packetNumber + 1) MOD 5) = 0) THEN Process.Yield[]; cycle ← packetNumber MOD NSTypes.maxIDPDataWords; IF cycle = 0 THEN OthelloDefs.WriteLine[""L]; b ← Socket.GetSendBuffer[soc]; Socket.SetDestination[b, him]; Socket.SetPacketWords[b, cycle + 1]; b.ns.packetType ← echo; b.ns.echoType ← echoRequest; pktBody ← @b.ns.nsWords; FOR k: CARDINAL IN [0..cycle) DO pktBody[k + 1] ← (k*400B + packetNumber); ENDLOOP; Socket.PutPacket[soc, b]; sent ← sent + 1; -- now receive the echo or any back logged echos DO b ← Socket.GetPacket[soc ! Socket.TimeOut => BEGIN missed ← missed + 1; OthelloDefs.WriteChar['?]; EXIT; END]; pktBody ← @b.ns.nsWords; SELECT TRUE FROM (Socket.GetPacketBytes[b] # 2*(cycle + 1)) OR (b.ns.echoType # echoResponse) OR ((cycle # 0) AND (pktBody[0 + 1] # (0*400B + packetNumber))) => BEGIN -- probably a late packet, but could be trash, or error late ← late + 1; OthelloDefs.WriteChar['#]; Socket.ReturnBuffer[b]; LOOP; END; ENDCASE => BEGIN -- the echo we were looking for FOR k: CARDINAL IN [0..cycle) DO IF pktBody[k + 1] # (k*400B + packetNumber) THEN BEGIN wrong ← wrong + 1; OthelloDefs.WriteChar['~]; GOTO Wrong; END; ENDLOOP; OthelloDefs.WriteChar['!]; recv ← recv + 1; Socket.ReturnBuffer[b]; EXIT; EXITS Wrong => EXIT; END; ENDLOOP; ENDLOOP; Socket.Delete[soc]; OthelloDefs.NewLine[]; OthelloDefs.WriteString["Out: "L]; OthelloDefs.WriteLongNumber[sent]; OthelloDefs.WriteString[", In: "L]; OthelloDefs.WriteLongNumber[recv]; IF sent # 0 THEN { OthelloDefs.WriteString[" ("L]; OthelloDefs.WriteLongNumber[(recv*100)/sent]; OthelloDefs.WriteLine["%)"L]; IF late # 0 THEN { OthelloDefs.WriteString["Late: "L]; OthelloDefs.WriteLongNumber[late]; OthelloDefs.WriteString[" ("L]; OthelloDefs.WriteLongNumber[(late*100)/sent]; OthelloDefs.WriteLine["%)"L]; }; IF missed # 0 THEN { OthelloDefs.WriteString["Missing: "L]; OthelloDefs.WriteLongNumber[missed]; OthelloDefs.WriteString[" ("L]; OthelloDefs.WriteLongNumber[(missed*100)/sent]; OthelloDefs.WriteLine["%)"L]; }; }; IF funny # 0 THEN { OthelloDefs.WriteLongNumber[funny]; OthelloDefs.WriteLine[" funny"L]; }; IF wrong # 0 THEN { OthelloDefs.WriteLongNumber[wrong]; OthelloDefs.WriteLine[" wrong data"L]; }; END; PrintRoutingTable: PROCEDURE = BEGIN PrintOne: PROCEDURE [net: System.NetworkNumber, delay: CARDINAL] = BEGIN hickup: BOOLEAN ← FALSE; delay2: CARDINAL; details: InrFriends.DriverDetails; [delay2, details] ← InrFriends.GetRouteInfo[net ! Runtime.UnboundProcedure, Router.NoTableEntryForNet => BEGIN hickup ← TRUE; CONTINUE; END]; IF hickup THEN duds ← duds + 1 ELSE nets ← nets + 1; IF k = 0 THEN OthelloDefs.WriteChar['|]; WriteProductNetNumber[net]; WriteNetNumber[net]; OthelloDefs.WriteChar[' ]; SELECT TRUE FROM hickup => OthelloDefs.WriteString[" ????? "]; ENDCASE => WriteNetAndHost[details.driverNetwork, details.via.host]; D4[delay]; IF delay # delay2 THEN OthelloDefs.WriteChar['?] ELSE OthelloDefs.WriteChar[' ]; OthelloDefs.WriteString["|"L]; IF (k ← k + 1) = 2 THEN BEGIN OthelloDefs.NewLine[]; k ← 0; Process.Yield[]; END; END; k, nets, duds: CARDINAL ← 0; OthelloDefs.NewLine[]; OthelloDefs.WriteLine[" Local NS Routing Table."L]; OthelloDefs.WriteString["| Net Via Dly "L]; OthelloDefs.WriteLine[ "| Net Via Dly |"L]; OthelloDefs.WriteString["|-------------------------------------------"L]; OthelloDefs.WriteLine[ "|-------------------------------------------|"L]; BEGIN PrintOne[System.nullNetworkNumber, 0]; -- Enumeration skips net 0 FOR delay: CARDINAL IN [0..Router.infinity) DO net: System.NetworkNumber ← Router.startEnumeration; DO net ← Router.EnumerateRoutingTable[net, delay]; IF net = Router.endEnumeration THEN EXIT; PrintOne[net, delay]; OthelloDefs.CheckUserAbort[! ABORTED => GOTO Exit]; ENDLOOP; REPEAT Exit => NULL; ENDLOOP; END; IF k # 0 THEN OthelloDefs.NewLine[]; IF nets > 1 THEN BEGIN OthelloDefs.WriteString["There are "L]; WriteDecimal[nets - 1]; OthelloDefs.WriteLine[" active networks."L]; END; IF duds > 0 THEN BEGIN OthelloDefs.WriteString["There are "L]; WriteDecimal[duds]; OthelloDefs.WriteLine[" dead slots."L]; END; END; PrintDeviceStats: PROCEDURE = BEGIN firstNetwork: Driver.Network ← Driver.GetDeviceChain[]; FOR network: Driver.Network ← firstNetwork, network.next UNTIL network = NIL DO OthelloDefs.CheckUserAbort[ ! ABORTED => EXIT]; SELECT network.device FROM ethernet, ethernetOne => BEGIN pup: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup]; ns: RoutingTable.NetworkContext ← Protocol1.GetContext[network, ns]; stats: LONG POINTER TO EthernetDriverFriends.EtherStatsInfo ← network.stats; OthelloDefs.WriteString["Ethernet"L]; IF network.device = ethernetOne THEN OthelloDefs.WriteString["One"L]; OthelloDefs.WriteString[" Statistics for Pup "L]; WriteNumber[pup.pupNetNumber, 8, 0]; OthelloDefs.WriteString["#"L]; WriteNumber[pup.pupHostNumber, 8, 0]; OthelloDefs.WriteString["#, NS net "L]; WriteNetNumbers[ns.netNumber]; OthelloDefs.WriteLine["."L]; IF stats = NIL THEN BEGIN OthelloDefs.WriteLine["*** NO DRIVER STATS ***"L]; LOOP; END; OthelloDefs.WriteString[" Rcv: pkts "L]; OthelloDefs.WriteLongNumber[stats.packetsRecv]; OthelloDefs.WriteString[", words "L]; OthelloDefs.WriteLongNumber[stats.wordsRecv]; OthelloDefs.WriteString[", bad "L]; OthelloDefs.WriteLongNumber[stats.badRecvStatus]; OthelloDefs.WriteString[", missed "L]; OthelloDefs.WriteLongNumber[stats.packetsMissed]; IF stats.idleInput # 0 THEN BEGIN OthelloDefs.WriteString[", idle "L]; OthelloDefs.WriteLongNumber[stats.idleInput]; END; OthelloDefs.NewLine[]; IF stats.badRecvStatus # 0 OR stats.okButDribble # 0 THEN BEGIN OthelloDefs.WriteString[" crc "L]; OthelloDefs.WriteLongNumber[stats.badCrc]; OthelloDefs.WriteString[", bad alignment but ok crc "L]; OthelloDefs.WriteLongNumber[stats.badAlignmentButOkCrc]; OthelloDefs.WriteString[", crc and bad alignment "L]; OthelloDefs.WriteLongNumber[stats.crcAndBadAlignment]; OthelloDefs.NewLine[]; OthelloDefs.WriteString[" ok but dribble "L]; OthelloDefs.WriteLongNumber[stats.okButDribble]; OthelloDefs.WriteString[", too long "L]; OthelloDefs.WriteLongNumber[stats.packetTooLong]; OthelloDefs.WriteString[", overrun "L]; OthelloDefs.WriteLongNumber[stats.overrun]; OthelloDefs.NewLine[]; END; OthelloDefs.WriteString[" Xmit: pkts "L]; OthelloDefs.WriteLongNumber[stats.packetsSent]; OthelloDefs.WriteString[", words "L]; OthelloDefs.WriteLongNumber[stats.wordsSent]; OthelloDefs.WriteString[", bad "L]; OthelloDefs.WriteLongNumber[stats.badSendStatus]; OthelloDefs.NewLine[]; IF stats.stuckOutput # 0 OR stats.badSendStatus # 0 OR stats.tooManyCollisions # 0 THEN BEGIN OthelloDefs.WriteString[" underrun "L]; OthelloDefs.WriteLongNumber[stats.underrun]; OthelloDefs.WriteString[", stuck "L]; OthelloDefs.WriteLongNumber[stats.stuckOutput]; OthelloDefs.WriteString[", too many collisions "L]; OthelloDefs.WriteLongNumber[stats.tooManyCollisions]; OthelloDefs.NewLine[]; END; OthelloDefs.WriteString[" Lds:"L]; FOR i: CARDINAL IN [0..16) DO OthelloDefs.WriteChar[' ]; OthelloDefs.WriteLongNumber[stats.loadTable[i]]; ENDLOOP; OthelloDefs.NewLine[]; END; phonenet => BEGIN pup: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup]; ns: RoutingTable.NetworkContext ← Protocol1.GetContext[network, ns]; stats: PhoneNetFriends.PhoneNetInfo = PhoneNetFriends.StatsPtrToStats[network.stats]; OthelloDefs.WriteString["PhoneNet Statistics for Pup "L]; WriteNumber[pup.pupNetNumber, 8, 0]; OthelloDefs.WriteString["#"L]; WriteNumber[pup.pupHostNumber, 8, 0]; OthelloDefs.WriteString["#, NS net "L]; WriteNetNumbers[ns.netNumber]; OthelloDefs.WriteString[", Line "L]; OthelloDefs.WriteLongNumber[stats.lineNumber]; OthelloDefs.WriteString[", "L]; OthelloDefs.WriteLongNumber[stats.speed]; OthelloDefs.WriteString["KB"L]; SELECT stats.remoteHostNumber FROM System.nullHostNumber => OthelloDefs.WriteString[", Down"L]; System.localHostNumber => OthelloDefs.WriteString[", Looped"L]; ENDCASE => { OthelloDefs.NewLine[]; OthelloDefs.WriteString[" Up to "L]; WriteHostNumbers[stats.remoteHostNumber]; }; OthelloDefs.NewLine[]; OthelloDefs.WriteString[" Recv: pkts "L]; OthelloDefs.WriteLongNumber[stats.stats[pktsReceived]]; OthelloDefs.WriteString[", bytes "L]; OthelloDefs.WriteLongNumber[stats.stats[bytesReceived]]; OthelloDefs.WriteString[", rejected "L]; OthelloDefs.WriteLongNumber[stats.stats[pktsRejected]]; OthelloDefs.WriteString[", missed "L]; OthelloDefs.WriteLongNumber[stats.stats[rcvErrorNoGet]]; OthelloDefs.WriteString[", idle "L]; OthelloDefs.WriteLongNumber[stats.stats[tooLongSinceLastReceive]]; OthelloDefs.NewLine[]; OthelloDefs.WriteString[" Bad crc "L]; OthelloDefs.WriteLongNumber[stats.stats[rcvErrorCRC]]; OthelloDefs.WriteString[", data lost "L]; OthelloDefs.WriteLongNumber[stats.stats[rcvErrorDataLost]]; OthelloDefs.WriteString[", device error "L]; OthelloDefs.WriteLongNumber[stats.stats[rcvDeviceError]]; OthelloDefs.WriteString[", timeout "L]; OthelloDefs.WriteLongNumber[stats.stats[rcvErrorFrameTimeout]]; OthelloDefs.WriteString[", other error "L]; OthelloDefs.WriteLongNumber[stats.stats[rcvErrorUnknown]]; OthelloDefs.NewLine[]; OthelloDefs.WriteString[" Send: pkts "L]; OthelloDefs.WriteLongNumber[stats.stats[pktsSent]]; OthelloDefs.WriteString[", bytes "L]; OthelloDefs.WriteLongNumber[stats.stats[bytesSent]]; OthelloDefs.NewLine[]; OthelloDefs.WriteString[" NS "L]; OthelloDefs.WriteLongNumber[stats.stats[nsSent]]; OthelloDefs.WriteString[" "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.nsBytesSend]]; OthelloDefs.WriteString[", Pups "L]; OthelloDefs.WriteLongNumber[stats.stats[pupSent]]; OthelloDefs.WriteString[" "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.pupBytesSend]]; OthelloDefs.WriteString[", Leaf "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.leafPktsSend]]; OthelloDefs.WriteString[" "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.leafBytesSend]]; OthelloDefs.NewLine[]; IF stats.stats[sendErrorBadStatus] # 0 OR stats.stats[queueTooOld] # 0 THEN { OthelloDefs.WriteString[" Bad "L]; OthelloDefs.WriteLongNumber[stats.stats[sendErrorBadStatus]]; OthelloDefs.WriteString[", stuck "L]; OthelloDefs.WriteLongNumber[stats.stats[queueTooOld]]; OthelloDefs.NewLine[]; }; OthelloDefs.WriteString[" Queue too long "L]; OthelloDefs.WriteLongNumber[stats.stats[congestion]]; OthelloDefs.WriteString[", NS "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.nsCongestion]]; OthelloDefs.WriteString[", Pup "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.pupCongestion]]; OthelloDefs.NewLine[]; OthelloDefs.WriteString[" Conn too greedy "L]; OthelloDefs.WriteLongNumber[stats.stats[connTooGreedy]]; OthelloDefs.WriteString[", NS "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.nsTooGreedy]]; OthelloDefs.WriteString[", Pup "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.pupTooGreedy]]; OthelloDefs.NewLine[]; IF stats.stats[PhoneNetExtras.nsDupsFiltered] # 0 THEN { OthelloDefs.WriteString[" NS duplicates discarded: "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.nsDupsFiltered]]; OthelloDefs.NewLine[]; }; IF stats.stats[PhoneNetExtras.pupDupsFiltered] # 0 THEN { OthelloDefs.WriteString[" BSP probes/duplicates discarded: "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.pupDupsFiltered]]; OthelloDefs.NewLine[]; }; IF stats.stats[PhoneNetExtras.leafDupsFiltered] # 0 THEN { OthelloDefs.WriteString[" Leaf duplicates discarded: "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.leafDupsFiltered]]; OthelloDefs.NewLine[]; }; END; ENDCASE => NULL; ENDLOOP; END; PrintTranslationCache: PROCEDURE = BEGIN firstNetwork: Driver.Network ← Driver.GetDeviceChain[]; FOR network: Driver.Network ← firstNetwork, network.next UNTIL network = NIL DO OthelloDefs.CheckUserAbort[ ! ABORTED => EXIT]; SELECT network.device FROM ethernet => BEGIN pup: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup]; ns: RoutingTable.NetworkContext ← Protocol1.GetContext[network, ns]; stats: LONG POINTER TO EthernetDriverFriends.EtherStatsInfo ← network.stats; OthelloDefs.WriteString["8=>48 Translation Cache for Pup "L]; WriteNumber[pup.pupNetNumber, 8, 0]; OthelloDefs.WriteString["#"L]; WriteNumber[pup.pupHostNumber, 8, 0]; OthelloDefs.WriteString["#, NS net "L]; WriteNetNumbers[ns.netNumber]; OthelloDefs.WriteLine["."L]; FOR i: NAT IN [0..377B] DO pup: PupTypes.PupHostID ← [i]; ns: System.HostNumber ← Pup10MBit.EnumerateTranslation[pup, network].translation; IF ns = System.nullHostNumber THEN LOOP; OthelloDefs.WriteString[" "L]; WriteNumber[pup, 8, 3]; OthelloDefs.WriteString[" => "L]; WriteHostNumbers[ns]; OthelloDefs.WriteLine["."L]; ENDLOOP; END; ethernetOne => BEGIN pup: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup]; ns: RoutingTable.NetworkContext ← Protocol1.GetContext[network, ns]; stats: LONG POINTER TO EthernetDriverFriends.EtherStatsInfo ← network.stats; OthelloDefs.WriteString["8<=48 Translation Cache for Pup "L]; WriteNumber[pup.pupNetNumber, 8, 0]; OthelloDefs.WriteString["#"L]; WriteNumber[pup.pupHostNumber, 8, 0]; OthelloDefs.WriteString["#, NS net "L]; WriteNetNumbers[ns.netNumber]; OthelloDefs.WriteLine["."L]; FOR i: NAT IN [0..377B] DO pup: PupTypes.PupHostID ← [i]; ns: System.HostNumber ← NS3MBit.GetInfo[pup, network]; IF ns = System.nullHostNumber THEN LOOP; OthelloDefs.WriteString[" "L]; WriteNumber[pup, 8, 3]; OthelloDefs.WriteString[" <= "L]; WriteHostNumbers[ns]; OthelloDefs.WriteLine["."L]; ENDLOOP; END; ENDCASE => NULL; ENDLOOP; END; WriteAddresses: PROCEDURE [a: System.NetworkAddress] = BEGIN Push: Format.StringProc = BEGIN OthelloDefs.WriteString[s]; END; Format.NetworkAddress[Push, a, productSoftware]; OthelloDefs.WriteString["="L]; Format.NetworkAddress[Push, a, octal]; END; WriteHostNumbers: PROCEDURE [host: System.HostNumber] = BEGIN Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN OthelloDefs.WriteString[s]; END; Format.HostNumber[Push, host, productSoftware]; OthelloDefs.WriteString["="L]; Format.HostNumber[Push, host, octal]; END; WriteNetNumbers: PROCEDURE [net: System.NetworkNumber] = BEGIN Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN OthelloDefs.WriteString[s]; END; Format.NetworkNumber[Push, net, productSoftware]; OthelloDefs.WriteString["="L]; Format.NetworkNumber[Push, net, octal]; END; WriteProductNetNumber: PROCEDURE [net: System.NetworkNumber] = BEGIN Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN THROUGH [s.length..6) DO OthelloDefs.WriteChar[' ]; ENDLOOP; OthelloDefs.WriteString[s]; END; Format.NetworkNumber[Push, net, productSoftware]; END; WriteNetNumber: PROCEDURE [net: System.NetworkNumber] = BEGIN Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN THROUGH [s.length..6) DO OthelloDefs.WriteChar[' ]; ENDLOOP; OthelloDefs.WriteString[s]; END; Format.NetworkNumber[Push, net, octal]; END; WriteNetAndHost: PROCEDURE [ net: System.NetworkNumber, host: System.HostNumber] = BEGIN Append: Format.StringProc = BEGIN String.AppendString[temp, s]; END; temp: STRING = [50]; Format.NetworkNumber[Append, net, productSoftware]; String.AppendChar[temp, '.]; Format.HostNumber[Append, host, productSoftware]; String.AppendChar[temp, '.]; THROUGH [temp.length..25) DO OthelloDefs.WriteChar[' ]; ENDLOOP; OthelloDefs.WriteString[temp]; END; WriteDecimal: PROCEDURE [n: CARDINAL] = BEGIN WriteNumber[n, 10, 0]; END; D4: PROCEDURE [n: CARDINAL] = BEGIN WriteNumber[n, 10, 4]; END; WriteNumber: PROCEDURE [n, radix, width: CARDINAL] = BEGIN temp: STRING = [25]; String.AppendNumber[temp, n, radix]; THROUGH [temp.length..width) DO OthelloDefs.WriteChar[' ]; ENDLOOP; OthelloDefs.WriteString[temp]; END; Trouble: ERROR [reason: LONG STRING] = CODE; GetAddress: PROCEDURE [host: LONG STRING, socket: System.SocketNumber] RETURNS [addr: System.NetworkAddress] = BEGIN localFailed: BOOLEAN ← FALSE; IF host = NIL THEN ERROR Trouble ["NIL => Address Fault"L]; addr ← Unformat.NetworkAddress[host, octal ! Unformat.Error => BEGIN localFailed ← TRUE; CONTINUE; END ]; IF localFailed THEN BEGIN addr ← AddressTranslation.StringToNetworkAddress[host ! AddressTranslation.Error => BEGIN temp: STRING = [200]; proc: Format.StringProc = {String.AppendString[temp, s]}; AddressTranslation.PrintError[errorRecord, proc]; ERROR Trouble[temp]; END].addr; addr.socket ← socket; -- CH returns trash in socket END; IF addr.socket = System.nullSocketNumber THEN addr.socket ← socket; END; echoName: LONG STRING ← NIL; Commands: PROCEDURE [index: CARDINAL] = BEGIN SELECT index FROM 0 => BEGIN OthelloDefs.MyNameIs[myNameIs: "Echo User"L, myHelpIs: "NS echo user"L]; EchoUser[]; END; 1 => BEGIN OthelloDefs.MyNameIs[ myNameIs: "Routing Tables"L, myHelpIs: "Show this machine's NS routing table"L]; PrintRoutingTable[]; END; 2 => BEGIN OthelloDefs.MyNameIs[ myNameIs: "Print Device Statistics"L, myHelpIs: "Print Device dependent Statistics for all drivers"L]; PrintDeviceStats[]; END; 3 => BEGIN OthelloDefs.MyNameIs[ myNameIs: "Print Translation Cache(s)"L, myHelpIs: "Print 48/8 and 8/48 Address Translation Cache(s) for all drivers"L]; PrintTranslationCache[]; END; ENDCASE => OthelloDefs.IndexTooLarge; END; commandProcessor: OthelloDefs.CommandProcessor ← [Commands]; -- initialization OthelloDefs.RegisterCommandProc[@commandProcessor]; END.....