-- File: GateInfo.mesa - last edit: -- AOF 3-Feb-88 15:59:10 -- HGM 6-Aug-85 21:11:13 -- Copyright (C) 1984, 1985, 1988 by Xerox Corporation. All rights reserved. DIRECTORY Cursor USING [Defined, GetInfo, Set, Type], Event USING [aboutToSwap], EventTypes USING [aboutToBoot, aboutToBootPhysicalVolume], Format USING [HostNumber, NetworkNumber], Menu USING [Handle, ItemObject, MCRType, Create, Instantiate], Process USING [Yield], Put USING [ CR, Char, Date, Decimal, Line, LongNumber, Number, Text], Runtime USING [UnboundProcedure], String USING [AppendChar, AppendString], Supervisor USING [EnumerationAborted, NotifyDirectSubsystems], System USING [HostNumber, NetworkNumber, nullNetworkNumber, switches], TemporaryBooting USING [BootFromPhysicalVolume, BootFromVolume], Time USING [Current], UserInput USING [ GetDefaultWindow, UserAbort, WaitForConfirmation, WaitNoButtons], Volume USING [GetAttributes, systemID], Window USING [Handle], BootServerDefs USING [ statFileSent, statFileSentSlow, statBootNew, statMicrocodeBooted], Buffer USING [], BufferOps USING [GetStatistics, Statistics], Driver USING [Device, GetDeviceChain], EchoServer USING [GetCounters], ForwarderDefs USING [ Counters, GetPointerToBadPupStats, GetPointerToPupGateStats, statGateInfoReplies], GateDefs USING [GetVersionText, typescript], CpuIdle USING [GetSmoothedCpuUtilization], Inr USING [ForwardingStats], InrFriends USING [DriverDetails, GetRouteInfo], NameServerDefs USING [ GetNewDirectoryVersion, GetOldDirectoryVersion, statName, statAddress, statXlation, statSend], Protocol1 USING [GetContext], PupRouterDefs USING [NetworkContext, RoutingTableEntry, EnumerateRoutingTable], PupTimeServer USING [GetAltoTimeRequests], Router USING [ endEnumeration, EnumerateRoutingTable, infinity, NoTableEntryForNet, startEnumeration], Stats USING [ StatCounterIndex, StatGetCounter, StatPrintCurrent, StatSince, StatUpdate], TimeServerOps USING [GetOldTimeRequests, GetTimeRequests], Trouble USING [ForceOutTypescriptFile]; GateInfo: PROGRAM IMPORTS Cursor, Event, Format, Menu, Process, Put, Runtime, String, Supervisor, System, TemporaryBooting, Time, UserInput, Volume, BootServerDefs, BufferOps, Driver, Protocol1, EchoServer, ForwarderDefs, GateDefs, CpuIdle, Inr, InrFriends, NameServerDefs, PupRouterDefs, PupTimeServer, Router, Stats, TimeServerOps, Trouble EXPORTS Buffer = BEGIN Device: PUBLIC TYPE = Driver.Device; items: ARRAY [0..6] OF Menu.ItemObject ← [ ["Gate", DoInfo], ["Pup RT", DoInfo], ["NS RT", DoInfo], ["Recent", DoInfo], [ "Total", DoInfo], ["Restart", DoInfo], ["Quit", DoInfo]]; gate: CARDINAL = 0; pupRoute: CARDINAL = 1; nsRoute: CARDINAL = 2; recent: CARDINAL = 3; total: CARDINAL = 4; restart: CARDINAL = 5; quit: CARDINAL = 6; DoInfo: Menu.MCRType = BEGIN wh: Window.Handle = GateDefs.typescript; Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN Put.Line[wh, s]; END; SELECT index FROM gate => PrintGateStats[wh]; pupRoute => PrintPupRoutingTable[wh]; nsRoute => PrintNSRoutingTable[wh]; recent => Stats.StatSince[Push]; total => Stats.StatPrintCurrent[Push]; restart => Restart[]; quit => Quit[]; ENDCASE => ERROR; END; SetupGateMenu: PROCEDURE = BEGIN menu: Menu.Handle ← Menu.Create[DESCRIPTOR[items], "Gate"]; Menu.Instantiate[menu, UserInput.GetDefaultWindow[]]; Menu.Instantiate[menu, GateDefs.typescript]; END; version: LONG STRING = GateDefs.GetVersionText[]; firstDevice: Device = Driver.GetDeviceChain[]; packets: LONG POINTER TO ForwarderDefs.Counters; bytes: LONG POINTER TO ForwarderDefs.Counters; bad: LONG POINTER TO ForwarderDefs.Counters; nets: CARDINAL; PrintGateStats: PUBLIC PROCEDURE [wh: Window.Handle] = BEGIN PupForwardingStats: PROCEDURE RETURNS [p, b: LONG CARDINAL ← 0] = BEGIN FOR from: Device ← firstDevice, from.next UNTIL from = NIL DO FOR to: Device ← firstDevice, to.next UNTIL to = NIL DO p ← p + packets[from.index + to.index*nets]; b ← b + bytes[from.index + to.index*nets]; ENDLOOP; ENDLOOP; END; PrintPacketsForwarded: PROCEDURE = BEGIN Line["Pups forwarded:"L]; Text[" Discard"L]; FOR to: Device ← firstDevice, to.next UNTIL to = NIL DO toContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[to, pup]; Text[" "L]; O4[toContext.pupNetNumber]; ENDLOOP; IF bad # NIL THEN FOR network: Device ← firstDevice, network.next UNTIL network = NIL DO IF bad[network.index] # 0 THEN BEGIN Text[" Bad"L]; EXIT; END; ENDLOOP; CR[]; FOR from: Device ← firstDevice, from.next UNTIL from = NIL DO fromContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[from, pup]; O4[fromContext.pupNetNumber]; Text[IF from.alive THEN " "L ELSE "*"L]; LD10Dash[packets[from.index + 0*nets]]; FOR to: Device ← firstDevice, to.next UNTIL to = NIL DO LD10Dash[packets[from.index + to.index*nets]]; ENDLOOP; IF bad # NIL AND (bad[from.index] # 0) THEN LD10Dash[bad[from.index]]; CR[]; ENDLOOP; END; PrintBytesForwarded: PROCEDURE = BEGIN Line["KBytes forwarded:"L]; Text[" Discard"L]; FOR to: Device ← firstDevice, to.next UNTIL to = NIL DO toContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[to, pup]; Text[" "L]; O4[toContext.pupNetNumber]; ENDLOOP; CR[]; FOR from: Device ← firstDevice, from.next UNTIL from = NIL DO fromContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[from, pup]; O4[fromContext.pupNetNumber]; Text[IF from.alive THEN " "L ELSE "*"L]; LD10Dash[bytes[from.index + 0*nets]/1000]; FOR to: Device ← firstDevice, to.next UNTIL to = NIL DO LD10Dash[bytes[from.index + to.index*nets]/1000]; ENDLOOP; CR[]; ENDLOOP; END; PrintMaybe: PROCEDURE [s: LONG STRING, x: Stats.StatCounterIndex] = BEGIN n: LONG CARDINAL = Stats.StatGetCounter[x]; IF n = 0 THEN RETURN; Text[s]; Text[": "L]; LD[n]; CR[]; END; O4: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, FALSE, TRUE, 4]]; END; D: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 0]]; END; LD: PROCEDURE [n: LONG CARDINAL] = BEGIN Put.LongNumber[wh, n, [10, FALSE, TRUE, 0]]; END; LDS: PROCEDURE [x: Stats.StatCounterIndex] = BEGIN LD[Stats.StatGetCounter[x]]; END; LD10Dash: PROCEDURE [n: LONG CARDINAL] = BEGIN IF n = 0 THEN Put.Text[wh, " - "L] ELSE Put.LongNumber[wh, n, [10, FALSE, TRUE, 10]]; END; PrintUpTime: PROCEDURE = BEGIN sec: LONG INTEGER ← Stats.StatGetCounter[statSeconds]; min: LONG INTEGER; hours: LONG INTEGER; hours ← sec/3600; sec ← sec - hours*3600; min ← sec/60; sec ← sec - min*60; LD[hours]; Char[':]; LD[min]; Char[':]; LD[sec]; END; Line: PROCEDURE [s: LONG STRING] = BEGIN Put.Line[wh, s]; END; Text: PROCEDURE [s: LONG STRING] = BEGIN Put.Text[wh, s]; END; Char: PROCEDURE [c: CHARACTER] = BEGIN Put.Char[wh, c]; END; CR: PROCEDURE = BEGIN Put.CR[wh]; END; Stats.StatUpdate[]; -- be sure time is up to date PutHeader[wh, version, FALSE]; CR[]; Text["UP = "L]; PrintUpTime[]; Text[", CPU = "]; D[CpuIdle.GetSmoothedCpuUtilization[]]; Text["%"]; CR[]; BEGIN packets, bytes: LONG CARDINAL; [packets, bytes] ← EchoServer.GetCounters[]; Text["Echo: "L]; LD[packets]; Text[" packets, "L]; LD[bytes]; Text[" bytes"L]; Text[", Time: "L]; LD[TimeServerOps.GetTimeRequests[]]; Text[", Old Time: "L]; LD[TimeServerOps.GetOldTimeRequests[]]; CR[]; END; BEGIN seconds: LONG CARDINAL = Stats.StatGetCounter[statSeconds]; packets, bytes: LONG CARDINAL; [packets, bytes] ← Inr.ForwardingStats[]; Text["NS: "L]; LD[packets]; Text[" packets, "L]; LD[bytes]; Text[" bytes"L]; IF seconds # 0 THEN BEGIN Text[", "L]; LD[packets/seconds]; Text[" packets/second, "L]; LD[bytes/(seconds/8)]; Text[" bits/second"L]; END; CR[]; [packets, bytes] ← PupForwardingStats[]; Text["Pup: "L]; LD[packets]; Text[" packets, "L]; LD[bytes]; Text[" bytes"L]; IF seconds # 0 THEN BEGIN Text[", "L]; LD[packets/seconds]; Text[" packets/second, "L]; LD[bytes/(seconds/8)]; Text[" bits/second"L]; END; CR[]; END; Text["PupEcho: "L]; LDS[pupsEchoed]; Text[", Route: "L]; LDS[ForwarderDefs.statGateInfoReplies]; Text[", Boot: "L]; LDS[BootServerDefs.statFileSent]; Text[", MicroBoot: "L]; LDS[BootServerDefs.statMicrocodeBooted]; Text[", Alto Time: "L]; LD[PupTimeServer.GetAltoTimeRequests[]]; CR[]; Text["Name=>Address: "L]; LDS[NameServerDefs.statName]; Text[", Address=>Name: "L]; LDS[NameServerDefs.statAddress]; Text[", 48=>8: "L]; LDS[NameServerDefs.statXlation]; CR[]; DoSomeYields[]; BEGIN version: CARDINAL; inTransit: BOOLEAN; Text["Directory version: "L]; [version, inTransit] ← NameServerDefs.GetOldDirectoryVersion[]; D[version]; IF inTransit THEN Text["(In Transit)"L]; [version, inTransit] ← NameServerDefs.GetNewDirectoryVersion[]; Text["/"L]; D[version]; END; BEGIN info: ARRAY BufferOps.Statistics OF CARDINAL ← BufferOps.GetStatistics[]; Text[", Buffers: "L]; D[info[available]]; Text["/"L]; D[info[allocated]]; Text["/"L]; D[info[requested]]; END; Text[", Free Disk Pages: "L]; LD[Volume.GetAttributes[Volume.systemID].freePageCount]; CR[]; DoSomeYields[]; PrintMaybe["Pup Network Directories sent"L, NameServerDefs.statSend]; PrintMaybe["Slow boot files sent"L, BootServerDefs.statFileSentSlow]; PrintMaybe["New boot files retrieved"L, BootServerDefs.statBootNew]; CR[]; DoSomeYields[]; IF packets # NIL THEN PrintPacketsForwarded[]; CR[]; DoSomeYields[]; IF bytes # NIL THEN PrintBytesForwarded[]; DoSomeYields[]; END; PrintPupRoutingTable: PUBLIC PROCEDURE [wh: Window.Handle] = BEGIN O3Z: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, TRUE, TRUE, 3]]; END; O4: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, FALSE, TRUE, 4]]; END; D4: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 4]]; END; PrintOne: PROCEDURE [rte: PupRouterDefs.RoutingTableEntry] = BEGIN context: PupRouterDefs.NetworkContext ← rte.context; IF context = NIL THEN RETURN; nets ← nets + 1; IF UserInput.UserAbort[wh] THEN RETURN; IF k = 0 THEN Put.Char[wh, '|]; O4[rte.net]; O4[context.pupNetNumber]; Put.Char[wh, '#]; IF rte.hop # 0 THEN O3Z[rte.route] ELSE O3Z[context.pupHostNumber]; Put.Char[wh, '#]; D4[rte.hop]; Put.Text[wh, " |"L]; IF (k ← k + 1) = 4 THEN BEGIN Put.CR[wh]; k ← 0; DoSomeYields[]; END; END; k, nets: CARDINAL ← 0; PutHeader[wh, " Local Routing Table."L]; Put.Line[ wh, "| Net Via Hops | Net Via Hops | Net Via Hops | Net Via Hops |"L]; Put.Line[ wh, "|-------------------|-------------------|-------------------|-------------------|"L]; PupRouterDefs.EnumerateRoutingTable[PrintOne]; IF k # 0 THEN Put.CR[wh]; IF nets > 1 THEN BEGIN Put.Text[wh, "There are "L]; Put.Decimal[wh, nets - 1]; Put.Line[wh, " active networks."L]; END; END; PrintNSRoutingTable: PUBLIC PROCEDURE [wh: Window.Handle] = BEGIN O: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [8, FALSE, FALSE, 0]]; END; D4: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 4]]; END; 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 UserInput.UserAbort[wh] THEN RETURN; IF k = 0 THEN Put.Char[wh, '|]; PutProductNetNumber[wh, net]; PutNetNumber[wh, net]; Put.Char[wh, ' ]; SELECT TRUE FROM hickup => Put.Text[wh, " ????? "]; ENDCASE => PutNetAndHost[wh, details.driverNetwork, details.via.host]; D4[delay]; IF delay # delay2 THEN Put.Char[wh,'?] ELSE Put.Char[wh,' ]; Put.Text[wh, "|"L]; IF (k ← k + 1) = 2 THEN BEGIN Put.CR[wh]; k ← 0; END; DoSomeYields[]; END; k, nets, duds: CARDINAL ← 0; PutHeader[wh, " Local NS Routing Table."L]; Put.Line[ wh, "| Net Via Dly | Net Via Dly |"L]; Put.Line[ wh, "|-------------------------------------------|-------------------------------------------|"L]; BEGIN net: System.NetworkNumber ← Router.startEnumeration; 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]; ENDLOOP; ENDLOOP; END; IF k # 0 THEN Put.CR[wh]; IF nets > 1 THEN BEGIN Put.Text[wh, "There are "L]; Put.Decimal[wh, nets - 1]; Put.Line[wh, " active networks."L]; END; IF duds > 0 THEN BEGIN Put.Text[wh, "There are "L]; Put.Decimal[wh, duds]; Put.Line[wh, " dead slots."L]; END; END; PutHeader: PROCEDURE [wh: Window.Handle, s: LONG STRING, cr: BOOLEAN ← TRUE] = BEGIN Put.CR[wh]; Put.Date[wh, Time.Current[], dateTime]; Put.Text[wh, " "L]; Put.Text[wh, s]; IF cr THEN Put.CR[wh]; END; PutProductNetNumber: PROCEDURE [wh: Window.Handle, net: System.NetworkNumber] = BEGIN Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN THROUGH [s.length..6) DO Put.Char[wh, ' ]; ENDLOOP; Put.Text[wh, s]; END; Format.NetworkNumber[Push, net, productSoftware]; END; PutNetNumber: PROCEDURE [wh: Window.Handle, net: System.NetworkNumber] = BEGIN Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN THROUGH [s.length..6) DO Put.Char[wh, ' ]; ENDLOOP; Put.Text[wh, s]; END; Format.NetworkNumber[Push, net, octal]; END; PutNetAndHost: PROCEDURE [ wh: Window.Handle, net: System.NetworkNumber, host: System.HostNumber] = BEGIN temp: STRING = [50]; Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN String.AppendString[temp, s]; END; Format.NetworkNumber[Append, net, productSoftware]; String.AppendChar[temp, '.]; Format.HostNumber[Append, host, productSoftware]; String.AppendChar[temp, '.]; THROUGH [temp.length..25) DO Put.Char[wh, ' ]; ENDLOOP; Put.Text[wh, temp]; END; DoSomeYields: PROCEDURE = BEGIN THROUGH [0..100) DO Process.Yield[]; ENDLOOP; END; Restart: PROCEDURE = BEGIN oldType: Cursor.Type = Cursor.GetInfo[].type; IF ~Confirm[] THEN RETURN; Cursor.Set[hourGlass]; BEGIN ENABLE Supervisor.EnumerationAborted => CONTINUE; Supervisor.NotifyDirectSubsystems[ event: [EventTypes.aboutToBoot], which: clients, subsystem: Event.aboutToSwap]; Trouble.ForceOutTypescriptFile[]; TemporaryBooting.BootFromVolume[Volume.systemID, System.switches]; END; IF oldType IN Cursor.Defined THEN Cursor.Set[oldType]; END; Quit: PROCEDURE = BEGIN oldType: Cursor.Type = Cursor.GetInfo[].type; IF ~Confirm[] THEN RETURN; Cursor.Set[hourGlass]; BEGIN ENABLE Supervisor.EnumerationAborted => CONTINUE; Supervisor.NotifyDirectSubsystems[ event: [EventTypes.aboutToBootPhysicalVolume], which: clients, subsystem: Event.aboutToSwap]; Trouble.ForceOutTypescriptFile[]; TemporaryBooting.BootFromPhysicalVolume[Volume.systemID, System.switches]; END; IF oldType IN Cursor.Defined THEN Cursor.Set[oldType]; END; Confirm: PROCEDURE RETURNS [okay: BOOLEAN] = BEGIN oldType: Cursor.Type = Cursor.GetInfo[].type; Cursor.Set[mouseRed]; okay ← UserInput.WaitForConfirmation[].okay; IF oldType IN Cursor.Defined THEN Cursor.Set[oldType]; UserInput.WaitNoButtons[]; END; -- Initialization [packets, bytes, nets] ← ForwarderDefs.GetPointerToPupGateStats[]; bad ← ForwarderDefs.GetPointerToBadPupStats[]; SetupGateMenu[]; END.