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