-- Copyright (C) 1984 by Xerox Corporation. All rights reserved.
-- NetWatcher.mesa, HGM, 11-Feb-84 16:41:36
DIRECTORY
Ascii USING [CR],
CmFile USING [Handle, TableError],
Format USING [HostNumber, NetworkNumber],
Heap USING [systemZone],
Process USING [Detach, MsecToTicks, Ticks, Pause, Yield],
Put USING [Text],
Runtime USING [UnboundProcedure],
String USING [AppendChar, AppendString, AppendNumber],
StringLookUp USING [noMatch],
System USING [
GreenwichMeanTime, GetGreenwichMeanTime, HostNumber, NetworkNumber,
nullHostNumber, nullNetworkNumber],
Time USING [AppendCurrent],
Token USING [Boolean],
Indirect USING [Close, NextValue, OpenSection],
InrFriends USING [DriverDetails, GetRouteInfo],
Router USING [
endEnumeration, EnumerateRoutingTable, GetDelayToNet, infinity,
NoTableEntryForNet, startEnumeration];
NetWatcher: PROGRAM
IMPORTS
CmFile, Format, Heap, Process, Put, Runtime, String, System, Time, Token,
Indirect, InrFriends, Router =
BEGIN
z: UNCOUNTED ZONE = Heap.systemZone;
seconds: CARDINAL ← 60;
oneSecond: Process.Ticks = Process.MsecToTicks[1000];
first: Handle ← NIL;
Handle: TYPE = LONG POINTER TO Object;
Object: TYPE = RECORD [
next: Handle,
net: System.NetworkNumber,
viaNet: System.NetworkNumber,
viaHost: System.HostNumber,
old: BOOLEAN,
delay: CARDINAL ];
Init: PROCEDURE =
BEGIN
off: BOOLEAN ← FALSE;
cmFile: CmFile.Handle;
Option: TYPE = {disable};
NextValue: PROCEDURE [
h: CmFile.Handle, table: LONG DESCRIPTOR FOR ARRAY Option OF LONG STRING]
RETURNS [Option] = LOOPHOLE[Indirect.NextValue];
optionTable: ARRAY Option OF LONG STRING ← [disable: "Disable"L];
cmFile ← Indirect.OpenSection["NetWatcher"L];
IF cmFile = NIL THEN RETURN;
DO
option: Option;
text: STRING = [200];
option ← NextValue[cmFile, DESCRIPTOR[optionTable] ! CmFile.TableError => RETRY];
SELECT option FROM
LOOPHOLE[StringLookUp.noMatch] => EXIT;
disable =>
BEGIN
off ← Token.Boolean[cmFile];
END;
ENDCASE => ERROR;
ENDLOOP;
Indirect.Close[cmFile];
IF ~off THEN Process.Detach[FORK Watch[]];
END;
Watch: PROCEDURE =
BEGIN
time: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[];
Process.Pause[120*oneSecond];
EnumerateRoutingTable[AddEntry];
DO
WHILE (System.GetGreenwichMeanTime[] - time) < seconds DO
Process.Pause[oneSecond]; ENDLOOP;
time ← System.GetGreenwichMeanTime[];
MarkOldNets[];
EnumerateRoutingTable[AddAndPrint];
CheckOldNets[];
THROUGH [0..100) DO Process.Yield[]; ENDLOOP;
ENDLOOP;
END;
EnumerateRoutingTable: PROCEDURE [
proc: PROCEDURE [
net: System.NetworkNumber,
delay: CARDINAL,
viaNet: System.NetworkNumber,
viaHost: System.HostNumber] ] =
BEGIN
net: System.NetworkNumber ← Router.startEnumeration;
FOR delay: CARDINAL IN [0..Router.infinity) DO
net: System.NetworkNumber ← Router.startEnumeration;
DO
details: InrFriends.DriverDetails;
net ← Router.EnumerateRoutingTable[net, delay];
IF net = Router.endEnumeration THEN EXIT;
[, details] ← InrFriends.GetRouteInfo[net !
Runtime.UnboundProcedure, Router.NoTableEntryForNet =>
BEGIN
details.driverNetwork ← System.nullNetworkNumber;
details.via.host ← System.nullHostNumber;
CONTINUE;
END];
proc[net, delay, details.driverNetwork, details.via.host];
ENDLOOP;
ENDLOOP;
END;
AddEntry: PROCEDURE [
net: System.NetworkNumber,
delay: CARDINAL,
viaNet: System.NetworkNumber,
viaHost: System.HostNumber] =
BEGIN
handle: Handle;
handle ← z.NEW[Object];
handle↑ ← [
next: first,
net: net,
viaNet: viaNet,
viaHost: viaHost,
old: FALSE,
delay: delay ];
first ← handle;
END;
AddAndPrint: PROCEDURE [
net: System.NetworkNumber,
delay: CARDINAL,
viaNet: System.NetworkNumber,
viaHost: System.HostNumber] =
BEGIN
FOR handle: Handle ← first, handle.next UNTIL handle = NIL DO
IF handle.net = net THEN
BEGIN handle.old ← FALSE; RETURN; END;
ENDLOOP;
AddEntry[net, delay, viaNet, viaHost];
IF first.delay = Router.infinity THEN RETURN; -- Routing fault: still unreachable
PrintMessage[first];
END;
MarkOldNets: PROCEDURE =
BEGIN
FOR handle: Handle ← first, handle.next UNTIL handle = NIL DO
handle.old ← TRUE;
ENDLOOP;
END;
CheckOldNets: PROCEDURE =
BEGIN
handle: Handle ← first;
UNTIL handle = NIL DO
delay: CARDINAL ← Router.infinity;
details: InrFriends.DriverDetails;
IF handle.old THEN
BEGIN
temp: Handle ← handle;
IF handle.delay # Router.infinity THEN
BEGIN
handle.delay ← Router.infinity;
PrintMessage[handle];
END;
IF first = handle THEN
BEGIN
first ← handle.next;
END
ELSE
BEGIN
FOR prev: Handle ← first, prev.next DO
IF prev.next = handle THEN
BEGIN
prev.next ← handle.next;
EXIT;
END;
ENDLOOP;
END;
handle ← handle.next;
z.FREE[@temp];
LOOP;
END;
delay ← Router.GetDelayToNet[handle.net ! Router.NoTableEntryForNet => CONTINUE];
[, details] ← InrFriends.GetRouteInfo[handle.net !
Runtime.UnboundProcedure, Router.NoTableEntryForNet =>
BEGIN
details.driverNetwork ← System.nullNetworkNumber;
details.via.host ← System.nullHostNumber;
CONTINUE;
END];
IF handle.delay # delay
OR handle.viaNet # details.driverNetwork
OR handle.viaHost # details.via.host THEN
BEGIN
handle.delay ← delay;
handle.viaNet ← details.driverNetwork;
handle.viaHost ← details.via.host;
PrintMessage[handle];
END;
handle ← handle.next;
ENDLOOP;
END;
PrintMessage: PROCEDURE [handle: Handle] =
BEGIN
text: STRING = [200];
net: RECORD [a, b: WORD] = LOOPHOLE[handle.net];
Time.AppendCurrent[text];
String.AppendString[text, " Net "L];
AppendNetNumber[text, handle.net];
IF net.b < 256 THEN
BEGIN
String.AppendString[text, " ("L];
AppendNetNumberOctal[text, handle.net];
String.AppendString[text, ")"L];
END;
String.AppendString[text, " is "L];
SELECT TRUE FROM
handle.delay = Router.infinity =>
String.AppendString[text, "unreachable"L];
(handle.delay = 0) => String.AppendString[text, "directly connected"L];
ENDCASE =>
BEGIN
String.AppendNumber[text, handle.delay, 10];
String.AppendString[text, " hops via "L];
AppendNetNumber[text, handle.viaNet];
String.AppendChar[text, '.];
AppendHostNumber[text, handle.viaHost];
String.AppendChar[text, '.];
END;
LogString[text];
THROUGH [0..1000) DO Process.Yield[]; ENDLOOP; -- Wait longer if things are busy
Process.Pause[5*oneSecond];
END;
AppendNetNumber: PROCEDURE [string: LONG STRING, net: System.NetworkNumber] =
BEGIN
Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
BEGIN String.AppendString[string, s]; END;
Format.NetworkNumber[Append, net, productSoftware];
END;
AppendNetNumberOctal: PROCEDURE [string: LONG STRING, net: System.NetworkNumber] =
BEGIN
Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
BEGIN String.AppendString[string, s]; END;
Format.NetworkNumber[Append, net, octal];
END;
AppendHostNumber: PROCEDURE [string: LONG STRING, host: System.HostNumber] =
BEGIN
Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
BEGIN String.AppendString[string, s]; END;
Format.HostNumber[Append, host, productSoftware];
END;
AppendNetAndHost: PROCEDURE [
string: LONG STRING, net: System.NetworkNumber, host: System.HostNumber] =
BEGIN
Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
BEGIN String.AppendString[string, s]; END;
Format.NetworkNumber[Append, net, productSoftware];
String.AppendChar[string, '.];
Format.HostNumber[Append, host, productSoftware];
String.AppendChar[string, '.];
END;
LogString: PROCEDURE [text: LONG STRING] =
BEGIN
String.AppendChar[text, '.];
String.AppendChar[text, Ascii.CR];
Put.Text[NIL, text];
END;
Init[];
END.