-- File: RoutingInfoTool.mesa - last edit: -- AOF 3-Feb-88 18:35:29 -- WIrish 5-Feb-88 12:27:16 -- HGM 6-Aug-85 21:05:01 -- Copyright (C) 1984, 1985, 1988 by Xerox Corporation. All rights reserved. DIRECTORY Format USING [HostNumber, NetworkAddress, NetworkNumber, StringProc], FormSW USING [ AllocateItemDescriptor, BooleanItem, ClientItemsProcType, CommandItem, newLine, NumberItem, ProcType, StringItem], Heap USING [systemZone], Process USING [Detach, Yield], Put USING [Char, CR, Text, Line], Runtime USING [GetBcdTime, UnboundProcedure], SpecialSystem USING [GetProcessorID], String USING [AppendChar, AppendString, AppendNumber], System USING [ HostNumber, NetworkAddress, NetworkNumber, nullNetworkNumber, nullSocketNumber, SocketNumber], Time USING [Append, AppendCurrent, Unpack], Tool USING [Create, MakeSWsProc, MakeFormSW, MakeFileSW, UnusedLogName], ToolWindow USING [TransitionProcType], Unformat USING [Error, NetworkAddress], UserInput USING [UserAbort], Window USING [Handle], AddressTranslation USING [Error, PrintError, StringToNetworkAddress], Buffer USING [], NSBuffer USING [Body, Buffer], Driver USING [Device, GetDeviceChain], InrFriends USING [DriverDetails, GetRouteInfo], NSTypes USING [RoutingInfoTuple], NSConstants USING [routingInformationSocket], Protocol1 USING [GetContext], PupRouterDefs USING [NetworkContext, RoutingTableEntry, EnumerateRoutingTable, PupGateInfo], PupDefs USING [ PupPackageMake, PupPackageDestroy, Body, PupBuffer, PupSocket, PupSocketDestroy, PupSocketMake, SecondsToTocks, SetPupContentsBytes, GetPupContentsBytes, AppendPupAddress, AppendErrorPup, GetPupAddress, PupNameTrouble, AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer], PupTypes USING [PupAddress, fillInSocketID, gatewaySoc, allHosts], Router USING [ endEnumeration, EnumerateRoutingTable, FillRoutingTable, infinity, NoTableEntryForNet, startEnumeration], RoutingTable USING [NetworkContext], Socket USING [ ChannelHandle, Create, Delete, GetPacket, GetPacketBytes, GetSendBuffer, GetSource, PutPacket, ReturnBuffer, SetDestination, SetPacketWords, SetWaitTime, TimeOut]; RoutingInfoTool: PROGRAM IMPORTS Format, FormSW, Heap, Process, Put, Runtime, SpecialSystem, String, Time, Tool, Unformat, UserInput, AddressTranslation, Driver, InrFriends, Protocol1, PupRouterDefs, PupDefs, Router, Socket EXPORTS Buffer = BEGIN OPEN PupDefs, PupTypes; Device: PUBLIC TYPE = Driver.Device; z: UNCOUNTED ZONE = Heap.systemZone; form, log: Window.Handle ← NIL; me, pupTarget, nsTarget: LONG STRING ← NIL; hops: CARDINAL ← 3; nearbyOnly: BOOLEAN ← FALSE; pupOn: BOOLEAN ← FALSE; Init: PROCEDURE = BEGIN herald: LONG STRING = [100]; String.AppendString[herald, "Routing Info of "L]; Time.Append[herald, Time.Unpack[Runtime.GetBcdTime[]]]; [] ← Tool.Create[ name: herald, makeSWsProc: MakeSWs, clientTransition: ClientTransition]; END; FillRoutingTable: FormSW.ProcType = BEGIN Router.FillRoutingTable[hops]; END; DeviceChain: FormSW.ProcType = BEGIN WriteCR[]; WriteCurrentDateAndTime[]; WriteLine[" Device Chain:"L]; WriteLine[" ix Net net hst speed bfr dn type"L]; FOR network: Device ← Driver.GetDeviceChain[], network.next UNTIL network = NIL DO pup: PupRouterDefs.NetworkContext = Protocol1.GetContext[network, pup]; ns: RoutingTable.NetworkContext = Protocol1.GetContext[network, ns]; IF UserInput.UserAbort[log] THEN EXIT; O4[network.index]; WriteProductNetNumber[ns.netNumber]; WriteNetNumber[ns.netNumber]; O4[pup.pupNetNumber]; O4[pup.pupHostNumber]; WriteString[" ?"L]; D4[network.buffers]; WriteString[IF network.alive THEN " "L ELSE " *"L]; WriteString[" "L]; SELECT network.device FROM ethernetOne => WriteLine["Ethernet - 3mb"L]; ethernet => WriteLine["Ethernet - 10mb"L]; phonenet => WriteLine["Phone Net"L]; ENDCASE => WriteLine["???"L]; ENDLOOP; END; LocalPup: FormSW.ProcType = BEGIN PrintOne: PROCEDURE [rte: PupRouterDefs.RoutingTableEntry] = BEGIN context: PupRouterDefs.NetworkContext ← rte.context; IF UserInput.UserAbort[log] THEN RETURN; IF context = NIL THEN RETURN; IF nearbyOnly AND rte.hop > hops THEN RETURN; nets ← nets + 1; IF k = 0 THEN WriteChar['|]; O4[rte.net]; O4[context.pupNetNumber]; WriteChar['#]; IF rte.hop # 0 THEN O3Z[rte.route] ELSE O3Z[context.pupHostNumber]; WriteChar['#]; D4[rte.hop]; WriteString[" |"L]; IF (k ← k + 1) = 4 THEN BEGIN WriteCR[]; k ← 0; END; END; k, nets: CARDINAL ← 0; IF ~pupOn THEN BEGIN [] ← PupDefs.PupPackageMake[]; pupOn ← TRUE; END; WriteCR[]; WriteCurrentDateAndTime[]; WriteLine[" Local Pup Routing Table."L]; WriteLine["| Net Via Hops | Net Via Hops | Net Via Hops | Net Via Hops |"L]; WriteLine["|------------------|------------------|------------------|------------------|"L]; PupRouterDefs.EnumerateRoutingTable[PrintOne]; IF k # 0 THEN WriteCR[]; IF nets > 1 THEN BEGIN WriteString["There are "L]; WriteDecimal[nets - 1]; WriteLine[" active networks."L]; END; END; RemotePup: FormSW.ProcType = BEGIN where: PupAddress; FindPath: PROCEDURE RETURNS [BOOLEAN] = BEGIN WriteString[pupTarget]; WriteChar['=]; where ← [[0], [0], PupTypes.gatewaySoc]; GetPupAddress[ @where, pupTarget ! PupNameTrouble => BEGIN WriteLine[e]; GOTO Trouble; END]; PrintPupAddress[where]; WriteLine["."L]; RETURN[TRUE]; EXITS Trouble => RETURN[FALSE]; END; pool: PupDefs.AccessHandle; soc: PupSocket; b: PupBuffer; body: PupDefs.Body; nets: CARDINAL ← 0; IF ~pupOn THEN BEGIN [] ← PupDefs.PupPackageMake[]; pupOn ← TRUE; END; WriteCR[]; WriteCurrentDateAndTime[]; WriteString[" Routing Table from "L]; IF ~FindPath[] THEN RETURN; pool ← PupDefs.MakePool[send: 1, receive: 10]; soc ← PupSocketMake[PupTypes.fillInSocketID, where, SecondsToTocks[2]]; THROUGH [0..10) UNTIL nets # 0 DO b ← PupDefs.GetBuffer[pool, send]; body ← b.pup; body.pupType ← gatewayRequest; SetPupContentsBytes[b, 0]; body.pupID ← [0, 0]; soc.put[b]; UNTIL (b ← soc.get[]) = NIL DO -- 2 sec wait body ← b.pup; IF where # body.source THEN BEGIN WriteString["Reply from: "L]; PrintPupAddress[body.source]; WriteLine["."L]; END; SELECT body.pupType FROM gatewayInfo => BEGIN length: CARDINAL = GetPupContentsBytes[b]; info: LONG POINTER TO PupRouterDefs.PupGateInfo ← LOOPHOLE[@body.pupWords]; k, n: CARDINAL; n ← length/(2*SIZE[PupRouterDefs.PupGateInfo]); IF (length MOD (2*SIZE[PupRouterDefs.PupGateInfo])) # 0 THEN WriteLine["***** Funny Length *****"L]; WriteLine[ "| Net Via Hops | Net Via Hops | Net Via Hops | Net Via Hops |"L]; WriteLine[ "|------------------|------------------|------------------|------------------|"L]; k ← 0; FOR i: CARDINAL IN [0..n) DO nets ← nets + 1; IF ~nearbyOnly OR info.hop < hops THEN BEGIN IF k = 0 THEN WriteChar['|]; O4[info.net]; O4[info.viaNet]; WriteChar['#]; O3Z[info.viaHost]; WriteChar['#]; D4[info.hop]; WriteString[" |"L]; IF (k ← k + 1) = 4 THEN BEGIN WriteCR[]; k ← 0; END; END; info ← info + SIZE[PupRouterDefs.PupGateInfo]; ENDLOOP; IF k # 0 THEN WriteCR[]; END; ENDCASE => PrintErrorPup[b]; PupDefs.ReturnBuffer[b]; ENDLOOP; IF nets = 0 THEN WriteChar['?]; ENDLOOP; IF where.host # PupTypes.allHosts THEN BEGIN WriteString["There are "L]; WriteDecimal[nets]; WriteLine[" active networks."L]; END; PupSocketDestroy[soc]; PupDefs.DestroyPool[pool]; END; LocalNS: FormSW.ProcType = BEGIN Process.Detach[FORK LocalNSx[]]; END; LocalNSx: 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 UserInput.UserAbort[log] THEN RETURN; IF nearbyOnly AND delay > hops THEN RETURN; IF k = 0 THEN WriteChar['|]; WriteProductNetNumber[net]; WriteNetNumber[net]; WriteChar[' ]; SELECT TRUE FROM hickup => WriteString[" ????? "]; ENDCASE => WriteNetAndHost[details.driverNetwork, details.via.host]; D4[delay]; IF delay # delay2 THEN WriteChar['?] ELSE WriteChar[' ]; WriteString["|"L]; IF (k ← k + 1) = 2 THEN BEGIN WriteCR[]; k ← 0; Process.Yield[]; END; END; k, nets, duds: CARDINAL ← 0; WriteCR[]; WriteCurrentDateAndTime[]; WriteLine[" Local NS Routing Table."L]; WriteLine["| Net Via Dly | Net Via Dly |"L]; 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]; ENDLOOP; ENDLOOP; END; IF k # 0 THEN WriteCR[]; IF nets > 1 THEN BEGIN WriteString["There are "L]; WriteDecimal[nets - 1]; WriteLine[" active networks."L]; END; IF duds > 0 THEN BEGIN WriteString["There are "L]; WriteDecimal[duds]; WriteLine[" dead slots."L]; END; END; RemoteNS: FormSW.ProcType = BEGIN Process.Detach[FORK RemoteNSx[]]; END; RemoteNSx: PROCEDURE = BEGIN k, nets: CARDINAL ← 0; PrintOne: PROCEDURE [rte: LONG POINTER TO NSTypes.RoutingInfoTuple] = BEGIN nets ← nets + 1; IF UserInput.UserAbort[log] THEN RETURN; IF ~nearbyOnly OR rte.interrouterDelay < hops THEN BEGIN IF k = 0 THEN WriteChar['|]; WriteProductNetNumber[rte.objectNetID]; WriteNetNumber[rte.objectNetID]; D4[rte.interrouterDelay]; WriteString[" |"L]; IF (k ← k + 1) = 4 THEN BEGIN WriteCR[]; k ← 0; END; END; END; remoteAddr: System.NetworkAddress; cH: Socket.ChannelHandle; b: NSBuffer.Buffer; body: NSBuffer.Body; errFlag, hit: BOOLEAN ← FALSE; WriteCR[]; WriteCurrentDateAndTime[]; WriteString[" Remote NS Routing Table from "L]; WriteString[nsTarget]; WriteString[" = "L]; remoteAddr ← GetAddress[nsTarget, NSConstants.routingInformationSocket ! Trouble => BEGIN WriteLine[reason]; errFlag ← TRUE; CONTINUE; END]; IF errFlag THEN RETURN; WriteNetworkAddressVerbose[remoteAddr]; WriteLine["."L]; cH ← Socket.Create[socket: System.nullSocketNumber, receive: 10]; Socket.SetWaitTime[cH, 2500]; -- milli-seconds FOR i: CARDINAL IN [0..10) UNTIL hit DO b ← Socket.GetSendBuffer[cH]; Socket.SetPacketWords[b, 1]; Socket.SetDestination[b, remoteAddr]; body.packetType ← routingInformation; body.routingType ← routingInfoRequest; Socket.PutPacket[cH, b]; DO b ← Socket.GetPacket[cH ! Socket.TimeOut => EXIT]; body ← b.ns; SELECT TRUE FROM (body.routingType # routingInfoResponse) => BEGIN WriteChar['#]; END; ENDCASE => BEGIN -- the response we were looking for network: Device ← b.fo.network; context: RoutingTable.NetworkContext ← b.fo.context; length, entrys: CARDINAL; length ← Socket.GetPacketBytes[b]; entrys ← length/(2*SIZE[NSTypes.RoutingInfoTuple]); IF remoteAddr # Socket.GetSource[b] THEN BEGIN WriteString["Response from: "L]; WriteNetworkAddressVerbose[Socket.GetSource[b]]; WriteLine["."L]; END; IF network # NIL AND context.netNumber # remoteAddr.net THEN BEGIN WriteString["Response via: "L]; WriteNetNumber[context.netNumber]; WriteLine["."L]; END; hit ← TRUE; k ← 0; WriteLine["| Net Hops | Net Hops | Net Hops | Net Hops |"L]; WriteLine["|-----------------|-----------------|-----------------|-----------------|"L]; FOR n: CARDINAL IN [0..entrys) DO PrintOne[@body.routingTuple[n]]; ENDLOOP; IF k # 0 THEN WriteCR[]; END; Socket.ReturnBuffer[b]; ENDLOOP; IF nets = 0 THEN WriteChar['?]; ENDLOOP; WriteCR[]; Socket.Delete[cH]; END; -- IO things WriteProductNetNumber: PROCEDURE [net: System.NetworkNumber] = BEGIN Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN THROUGH [s.length..6) DO WriteChar[' ]; ENDLOOP; 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 WriteChar[' ]; ENDLOOP; WriteString[s]; END; Format.NetworkNumber[Push, net, octal]; END; WriteNetAndHost: PROCEDURE [ net: System.NetworkNumber, host: System.HostNumber] = BEGIN temp: STRING = [50]; Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN String.AppendString[temp, s]; END; Format.NetworkNumber[Push, net, productSoftware]; String.AppendChar[temp, '#]; Format.HostNumber[Push, host, productSoftware]; String.AppendChar[temp, '#]; THROUGH [temp.length..25) DO WriteChar[' ]; ENDLOOP; WriteString[temp]; END; WriteNetworkAddressVerbose: PROCEDURE [address: System.NetworkAddress] = BEGIN Push: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN WriteString[s]; END; Format.NetworkAddress[Push, address, octal]; WriteString[" = "L]; Format.NetworkAddress[Push, address, productSoftware]; END; WriteChar: PROCEDURE [c: CHARACTER] = BEGIN Put.Char[log, c]; END; WriteCR: PROCEDURE = BEGIN Put.CR[log]; END; WriteString: PROCEDURE [s: LONG STRING] = BEGIN Put.Text[log, s]; END; WriteLine: PROCEDURE [s: LONG STRING] = BEGIN Put.Line[log, s]; END; WriteDecimal: PROCEDURE [n: CARDINAL] = INLINE BEGIN WriteNumber[n, 10, 0]; END; WriteNumber: PROCEDURE [n, radix, width: CARDINAL] = INLINE BEGIN temp: STRING = [25]; String.AppendNumber[temp, n, radix]; THROUGH [temp.length..width) DO WriteChar[' ]; ENDLOOP; Put.Text[log, temp]; END; O3Z: PROCEDURE [n: CARDINAL] = BEGIN temp: STRING = [25]; String.AppendNumber[temp, n, 8]; THROUGH [temp.length..3) DO WriteChar['0]; ENDLOOP; Put.Text[log, temp]; END; O4: PROCEDURE [n: CARDINAL] = BEGIN WriteNumber[n, 8, 4]; END; D4: PROCEDURE [n: CARDINAL] = BEGIN WriteNumber[n, 10, 4]; END; D6: PROCEDURE [n: CARDINAL] = BEGIN WriteNumber[n, 10, 6]; END; WriteCurrentDateAndTime: PROCEDURE = BEGIN time: STRING = [20]; Time.AppendCurrent[time]; WriteString[time]; END; PrintPupAddress: PROCEDURE [a: PupAddress] = BEGIN temp: STRING = [40]; AppendPupAddress[temp, a]; WriteString[temp]; END; PrintErrorPup: PUBLIC PROCEDURE [b: PupDefs.PupBuffer] = BEGIN text: STRING = [100]; AppendErrorPup[text, b]; Put.Line[log, text]; END; MakeSWs: Tool.MakeSWsProc = BEGIN logFileName: STRING = [40]; form ← Tool.MakeFormSW[window: window, formProc: MakeForm]; Tool.UnusedLogName[logFileName, "RoutingInfo.log$"L]; log ← Tool.MakeFileSW[window: window, name: logFileName, allowTypeIn: FALSE]; END; MakeForm: FormSW.ClientItemsProcType = BEGIN nParams: CARDINAL = 11; items ← FormSW.AllocateItemDescriptor[nParams]; items[0] ← FormSW.CommandItem[ tag: "LocalPup"L, proc: LocalPup, place: FormSW.newLine]; items[1] ← FormSW.CommandItem[tag: "RemotePup"L, proc: RemotePup]; items[2] ← FormSW.StringItem[tag: "PupTarget"L, string: @pupTarget, inHeap: TRUE]; items[3] ← FormSW.CommandItem[ tag: "LocalNS"L, proc: LocalNS, place: FormSW.newLine]; items[4] ← FormSW.CommandItem[tag: "RemoteNS"L, proc: RemoteNS]; items[5] ← FormSW.StringItem[tag: "NSTarget"L, string: @nsTarget, inHeap: TRUE]; items[6] ← FormSW.CommandItem[ tag: "FillRoutingTable"L, proc: FillRoutingTable, place: FormSW.newLine]; items[7] ← FormSW.BooleanItem[tag: "NearbyOnly"L, switch: @nearbyOnly]; items[8] ← FormSW.NumberItem[tag: "Hops"L, value: @hops]; items[9] ← FormSW.CommandItem[ tag: "DeviceChain"L, proc: DeviceChain, place: FormSW.newLine]; items[10] ← FormSW.StringItem[tag: "MyProcessorID"L, string: @me]; RETURN[items, TRUE]; END; ClientTransition: ToolWindow.TransitionProcType = BEGIN SELECT TRUE FROM old = inactive => BEGIN AppendMe: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] = BEGIN String.AppendString[me, s]; END; pupTarget ← z.NEW[StringBody[40]]; String.AppendString[pupTarget, "ME"L]; nsTarget ← z.NEW[StringBody[40]]; String.AppendString[nsTarget, "0#*#1"L]; me ← z.NEW[StringBody[100]]; Format.HostNumber[AppendMe, LOOPHOLE[SpecialSystem.GetProcessorID[]], hex]; String.AppendString[me, " "L]; Format.HostNumber[AppendMe, LOOPHOLE[SpecialSystem.GetProcessorID[]], productSoftware]; String.AppendString[me, " "L]; Format.HostNumber[AppendMe, LOOPHOLE[SpecialSystem.GetProcessorID[]], octal]; END; new = inactive => BEGIN IF pupOn THEN PupDefs.PupPackageDestroy[]; pupOn ← FALSE; z.FREE[@pupTarget]; z.FREE[@nsTarget]; z.FREE[@me]; END; ENDCASE; 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; Init[]; END.