-- Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved. -- OthelloNS.mesa, HGM, 19-Apr-85 16:19:48 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], NSConstants USING [echoerSocket], NSTypes USING [maxIDPDataWords], PhoneNetFriends USING [PhoneNetInfo], PhoneNetExtras USING [nsCongestion, nsTooGreedy, pupCongestion, pupTooGreedy], Router USING [ endEnumeration, EnumerateRoutingTable, infinity, NoTableEntryForNet, startEnumeration], Socket USING [ AssignNetworkAddress, ChannelHandle, Create, Delete, GetPacket, GetPacketBytes, GetSendBuffer, PutPacket, ReturnBuffer, SetDestination, SetPacketWords, SetWaitTime, TimeOut]; OthelloNS: PROGRAM IMPORTS Format, OthelloDefs, OthelloForgot, Process, Runtime, String, System, Unformat, AddressTranslation, Driver, InrFriends, Router, Socket = BEGIN EchoUser: PROCEDURE = BEGIN funny, late, missed: LONG CARDINAL ¬ 0; recv, sent: LONG CARDINAL ¬ 0; wrong: LONG CARDINAL ¬ 0; me, 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]]; me ¬ Socket.AssignNetworkAddress[]; soc ¬ Socket.Create[me]; Socket.SetWaitTime[soc, 5000]; WriteAddresses[me]; 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]; OthelloDefs.WriteString[" ("L]; OthelloDefs.WriteLongNumber[(recv*100)/sent]; OthelloDefs.WriteLine["%)"L]; IF late # 0 THEN BEGIN OthelloDefs.WriteString["Late: "L]; OthelloDefs.WriteLongNumber[late]; OthelloDefs.WriteString[" ("L]; OthelloDefs.WriteLongNumber[(late*100)/sent]; OthelloDefs.WriteLine["%)"L]; END; IF missed # 0 THEN BEGIN OthelloDefs.WriteString["Missing: "L]; OthelloDefs.WriteLongNumber[missed]; OthelloDefs.WriteString[" ("L]; OthelloDefs.WriteLongNumber[(missed*100)/sent]; OthelloDefs.WriteLine["%)"L]; END; IF funny # 0 THEN BEGIN OthelloDefs.WriteLongNumber[funny]; OthelloDefs.WriteLine[" funny"L]; END; IF wrong # 0 THEN BEGIN OthelloDefs.WriteLongNumber[wrong]; OthelloDefs.WriteLine[" wrong data"L]; END; 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 stats: LONG POINTER TO EthernetDriverFriends.EtherStatsInfo ¬ network.statsLevel0; OthelloDefs.WriteString["Ethernet"L]; IF network.device = ethernetOne THEN OthelloDefs.WriteString["One"L]; OthelloDefs.WriteString[" Statistics for Pup "L]; WriteNumber[network.pupNetNumber, 8, 0]; OthelloDefs.WriteString["#"L]; WriteNumber[network.pupHostNumber, 8, 0]; OthelloDefs.WriteString["#, NS net "L]; WriteNetNumbers[network.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 CrapForINRLoophole: TYPE = MONITORED RECORD [ clientData: LONG UNSPECIFIED, lineNumber: CARDINAL]; foo: LONG POINTER TO CrapForINRLoophole = network.statsLevel0; stats: LONG POINTER TO PhoneNetFriends.PhoneNetInfo ¬ foo.clientData; OthelloDefs.WriteString["PhoneNet Statistics for Pup "L]; WriteNumber[network.pupNetNumber, 8, 0]; OthelloDefs.WriteString["#"L]; WriteNumber[network.pupHostNumber, 8, 0]; OthelloDefs.WriteString["#, NS net "L]; WriteNetNumbers[network.netNumber]; OthelloDefs.WriteString[", Line "L]; OthelloDefs.WriteLongNumber[stats.lineNumber]; OthelloDefs.WriteString[", "L]; OthelloDefs.WriteLongNumber[stats.speed]; OthelloDefs.WriteString["KB"L]; SELECT TRUE FROM stats.remoteHostNumber = System.nullHostNumber => OthelloDefs.WriteString[", Down"L]; stats.remoteHostNumber = System.localHostNumber => OthelloDefs.WriteString[", Looped"L]; ENDCASE => BEGIN OthelloDefs.NewLine[]; OthelloDefs.WriteString[" Up to "L]; WriteHostNumbers[stats.remoteHostNumber]; END; OthelloDefs.NewLine[]; IF stats = NIL THEN RETURN; 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[" 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.WriteString[", Pups "L]; OthelloDefs.WriteLongNumber[stats.stats[pupSent]]; OthelloDefs.WriteString[", NS "L]; OthelloDefs.WriteLongNumber[stats.stats[nsSent]]; 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[" Pup "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.pupCongestion]]; OthelloDefs.WriteString[", NS "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.nsCongestion]]; OthelloDefs.NewLine[]; OthelloDefs.WriteString[" conn too greedy "L]; OthelloDefs.WriteLongNumber[stats.stats[connTooGreedy]]; OthelloDefs.WriteString[", Pup "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.pupTooGreedy]]; OthelloDefs.WriteString[", NS "L]; OthelloDefs.WriteLongNumber[stats.stats[PhoneNetExtras.nsTooGreedy]]; OthelloDefs.NewLine[]; IF stats.stats[controlPktReceived] # 0 THEN { OthelloDefs.WriteString[" probes/duplicates discarded: "L]; OthelloDefs.WriteLongNumber[stats.stats[controlPktReceived]]; OthelloDefs.NewLine[]; }; 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 [net: System.HostNumber] = BEGIN Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN OthelloDefs.WriteString[s]; END; Format.HostNumber[Push, net, productSoftware]; OthelloDefs.WriteString["="L]; Format.HostNumber[Push, net, 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; ENDCASE => OthelloDefs.IndexTooLarge; END; commandProcessor: OthelloDefs.CommandProcessor ¬ [Commands]; -- initialization OthelloDefs.RegisterCommandProc[@commandProcessor]; END.....