IPNameTool.mesa
Hal Murray June 24, 1985 9:10:31 pm PDT
John Larson, July 12, 1987 2:43:06 am PDT
Sharon Johnson, April 10, 1987 10:02:06 am PDT
DIRECTORY
BasicTime USING [GMT, Now, Period],
Buttons USING [Button, ButtonProc, Create, Destroy, SetDisplayStyle],
Commander USING [CommandProc, Register],
Containers USING [ChildXBound, ChildYBound, Create],
IO USING [Flush, PutF, PutRope, STREAM, Value],
Labels USING [Create],
Loader USING [BCDBuildTime],
Rope USING [Cat, ROPE, Length],
Rules USING [Create],
TypeScript USING [ChangeLooks, Create],
ViewerClasses USING [Viewer],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [AddProp, ComputeColumn, CreateViewer, MoveViewer, OpenIcon, SetOpenHeight],
ViewerTools USING [GetContents, MakeNewTextViewer, SetContents, SetSelection],
IPDefs USING [Address],
IPName USING [AddressToName, AddressToRope, LoadCacheFromAddress, LoadCacheFromName, NameState, NameToAddress, NormalizeName],
IPNameCache,
IPNameSupport USING [AddressSummaryLine, AliasSummaryLine, BogusAddressSummaryLine, BogusNameSummaryLine, DownAddressSummaryLine, DownNameSummaryLine, DownServerSummaryLine, MXSummaryLine, NameSummaryLine, ZoneSummaryLine];
IPNameTool: CEDAR MONITOR
IMPORTS
BasicTime, Buttons, Commander, Containers, IO, Labels, Loader, Rope, Rules, TypeScript, ViewerIO, ViewerOps, ViewerTools, IPName, IPNameCache, IPNameSupport =
BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
Viewer: TYPE = ViewerClasses.Viewer;
Viewer layout parameters
buttonHeight: INTEGER ← 0;
buttonWidth: INTEGER ← 0;
ClientData: TYPE = REF ClientDataRep;
ClientDataRep: TYPE = RECORD [
log: STREAMNIL,
in: STREAMNIL,
query: Viewer,
arg: Viewer];
sequenceNumber: CARDINAL ← 0;
NameEntry: TYPE = IPNameCache.NameEntry;
AliasEntry: TYPE = IPNameCache.AliasEntry;
MXEntry: TYPE = IPNameCache.MXEntry;
BogusNameEntry: TYPE = IPNameCache.BogusNameEntry;
DownNameEntry: TYPE = IPNameCache.DownNameEntry;
AddressEntry: TYPE = IPNameCache.AddressEntry;
BogusAddressEntry: TYPE = IPNameCache.BogusAddressEntry;
DownAddressEntry: TYPE = IPNameCache.DownAddressEntry;
DownServerEntry: TYPE = IPNameCache.DownServerEntry;
HistogramEntry: TYPE = IPNameCache.HistogramEntry;
ZoneEntry: TYPE = IPNameCache.ZoneEntry;
Create: Commander.CommandProc = { CreateOne[]; };
CreateOne: PROC = {
data: ClientData ← NEW[ClientDataRep ← []];
viewer, buttons, log: Viewer ← NIL;
viewer ← ViewerOps.CreateViewer [
flavor: $Container,
info: [name: "IPNameTool", column: left, iconic: TRUE, scrollable: FALSE]];
ViewerOps.AddProp[viewer, $IPNameTool, data];
{ -- Kludge to find Button size
temp: Buttons.Button = Buttons.Create[
info: [name: "Aliases:", parent: viewer, border: FALSE,
wx: 0, wy: 0],
proc: NIL, clientData: NIL, fork: FALSE, paint: FALSE];
buttonWidth ← temp.ww;
buttonHeight ← temp.wh;
Buttons.Destroy[temp]; };
log ← TypeScript.Create[
[name: "IPNameTool.log", wy: 27+4, parent: viewer, border: FALSE], FALSE];
[data.in, data.log] ← ViewerIO.CreateViewerStreams [
name: "IPNameTool.log", backingFile: "IPNameTool.log", viewer: log, editedStream: FALSE];
Containers.ChildXBound[viewer, log];
Containers.ChildYBound[viewer, log];
CreateButtons[data, viewer, log];
TypeScript.ChangeLooks[log, 'f];
IO.PutF[data.log, "IPName Tool of %G.\n", [time[Loader.BCDBuildTime[Create]]]];
IF FALSE THEN ViewerOps.OpenIcon[viewer]; };
CreateButtons: PROC[data: ClientData, parent, log: Viewer] = {
child: Viewer ← NIL;
kids: Viewer = Containers.Create[
info: [parent: parent, border: FALSE, scrollable: FALSE, wx: 0, wy: -9999, ww: 9999, wh: 0] ];
Containers.ChildXBound[parent, kids];
child ← MakeRule[kids, child];
child ← data.query ← MakeLabeledText[
parent: kids,
sibling: child,
name: "Query:",
data: "Xerox.COM",
prev: data.query];
child ← data.arg ← MakeLabeledText[
parent: kids,
sibling: child,
name: "Arg:",
data: "[10.2.0.32]",
prev: data.arg];
child ← MakeRule[kids, child];
child ← MakeLabel[kids, child, "Poke:"];
child ← MakeButton[kids, child, data, "N=>A", N2A];
child ← MakeButton[kids, child, data, "N=>MX", N2MX];
child ← MakeButton[kids, child, data, "N=>N", N2N];
child ← MakeButton[kids, child, data, "A=>N", A2N];
child ← MakeButton[kids, child, data, "Quick", Quick];
child ← MakeLabel[kids, child, "Info:"];
child ← MakeButton[kids, child, data, "Slot", Slot];
child ← MakeButton[kids, child, data, "Names", Names];
child ← MakeButton[kids, child, data, "Addrs", Addrs];
child ← MakeButton[kids, child, data, "Aliases", Aliases];
child ← MakeButton[kids, child, data, "MXs", MXs];
child ← MakeButton[kids, child, data, "Bogus", Bogus];
child ← MakeButton[kids, child, data, "Down", Down];
child ← MakeButton[kids, child, data, "Zones", Zones];
child ← MakeButton[kids, child, data, "Hist", Hist];
child ← MakeButton[kids, child, data, "Zap", Zap];
child ← MakeButton[kids, child, data, "Add", Add];
child ← MakeRule[kids, child];
{
kidsY: INTEGER = 2;
kidsH: INTEGER = child.wy + child.wh + 2;
ViewerOps.MoveViewer[viewer: log, x: 0, y: kidsY + kidsH, w: log.ww, h: parent.ch - (kids.wy + kidsH), paint: FALSE];
ViewerOps.SetOpenHeight[parent, kidsY + kidsH + 12 * buttonHeight];
IF ~parent.iconic THEN ViewerOps.ComputeColumn[parent.column];
ViewerOps.MoveViewer[viewer: kids, x: kids.wx, y: kidsY, w: kids.ww, h: kidsH]; };
};
Zap: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
IPNameCache.ZapWholeCache[];
IO.PutRope[log, "Zapped name and server caches.\n\n"]; };
N2A: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.query];
addresses: LIST OF IPDefs.Address;
state: IPName.NameState ← IPName.LoadCacheFromName[query, TRUE, TRUE];
IF state = bogus OR state = down THEN {IO.PutRope[log, Rope.Cat[query, " => "]]; RETURN};
addresses ← IPName.NameToAddress[query];
IO.PutRope[log, query];
PrintListOfAddresses[log, " => ", addresses]; };
N2N: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.query];
name: ROPE;
state: IPName.NameState ← IPName.LoadCacheFromName[query, TRUE, FALSE];
IF state = bogus OR state = down THEN {IO.PutRope[log, Rope.Cat[query, " => "]]; RETURN};
name ← IPName.NormalizeName[query];
IO.PutF[log, "%G => %G.\n", [rope[query]], [rope[name]]]; };
N2MX: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.query];
state: IPName.NameState ← IPName.LoadCacheFromName[query, TRUE, FALSE];
Log: PROC [rope: ROPE] ~ {
IO.PutRope[log, rope];
IO.Flush[log]};
IF state = mxOk THEN {
mx: MXEntry ← IPNameCache.MXLookup[query];
IF mx # NIL THEN IPNameSupport.MXSummaryLine[mx, FALSE, TRUE, Log];
};
};
A2N: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.query];
where: LIST OF IPDefs.Address ← IPName.NameToAddress[query];
name: Rope.ROPE;
IF where = NIL THEN {
IO.PutF[log, "\"Query\" needs to be a valid Address.\n"]; RETURN[]; };
name ← IPName.AddressToName[where.first];
IO.PutF[log, "%G => %G.\n", [rope[IPName.AddressToRope[where.first]]], [rope[name]]]; };
Quick: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
names: LIST OF NameEntry = IPNameCache.GetNames[];
mxList: LIST OF MXEntry = IPNameCache.GetMXList[];
aliases: LIST OF AliasEntry = IPNameCache.GetAliases[];
bogusNames: LIST OF BogusNameEntry = IPNameCache.GetBogusNames[];
downNames: LIST OF DownNameEntry = IPNameCache.GetDownNames[];
addresses: LIST OF AddressEntry = IPNameCache.GetAddresses[];
bogusAddresses: LIST OF BogusAddressEntry = IPNameCache.GetBogusAddresses[];
downAddresses: LIST OF DownAddressEntry = IPNameCache.GetDownAddresses[];
downServers: LIST OF DownServerEntry = IPNameCache.GetDownServers[];
zones: LIST OF ZoneEntry = IPNameCache.GetZones[];
Log: PROC [rope: ROPE] ~ {
IO.PutRope[log, rope];
IO.Flush[log]};
IO.PutRope[log, "\nCache Summary:\n"];
IF names = NIL THEN IO.PutRope[log, "Name Cache is empty.\n"]
ELSE IO.PutRope[log, "Names:\n"];
FOR list: LIST OF NameEntry ← names, list.rest UNTIL list = NIL DO
IPNameSupport.NameSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IF aliases = NIL THEN IO.PutRope[log, "Alias Cache is empty.\n"]
ELSE IO.PutRope[log, "Aliases:\n"];
FOR list: LIST OF AliasEntry ← aliases, list.rest UNTIL list = NIL DO
IPNameSupport.AliasSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IF mxList = NIL THEN IO.PutRope[log, "MX Cache is empty.\n"]
ELSE IO.PutRope[log, "MXs:\n"];
FOR list: LIST OF MXEntry ← mxList, list.rest UNTIL list = NIL DO
IPNameSupport.MXSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IF bogusNames = NIL THEN IO.PutRope[log, "Bogus Name Cache is empty.\n"]
ELSE IO.PutRope[log, "Bogus Names:\n"];
FOR list: LIST OF BogusNameEntry ← bogusNames, list.rest UNTIL list = NIL DO
IPNameSupport.BogusNameSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IF downNames # NIL THEN IO.PutRope[log, "Down Names:\n"];
FOR list: LIST OF DownNameEntry ← downNames, list.rest UNTIL list = NIL DO
IPNameSupport.DownNameSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IF addresses = NIL THEN IO.PutRope[log, "Address Cache is empty.\n"]
ELSE IO.PutRope[log, "Addresses:\n"];
FOR list: LIST OF AddressEntry ← addresses, list.rest UNTIL list = NIL DO
IPNameSupport.AddressSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IF bogusAddresses = NIL THEN IO.PutRope[log, "Bogus Address Cache is empty.\n"]
ELSE IO.PutRope[log, "Bogus Addresses:\n"];
FOR list: LIST OF BogusAddressEntry ← bogusAddresses, list.rest UNTIL list = NIL DO
IPNameSupport.BogusAddressSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IF downAddresses # NIL THEN IO.PutRope[log, "Down Addresses:\n"];
FOR list: LIST OF DownAddressEntry ← downAddresses, list.rest UNTIL list = NIL DO
IPNameSupport.DownAddressSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IF downServers # NIL THEN IO.PutRope[log, "Down Servers:\n"];
FOR list: LIST OF DownServerEntry ← downServers, list.rest UNTIL list = NIL DO
IPNameSupport.DownServerSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IF zones = NIL THEN IO.PutRope[log, "Zone Cache is empty.\n"]
ELSE IO.PutRope[log, "Zones:\n"];
FOR list: LIST OF ZoneEntry ← zones, list.rest UNTIL list = NIL DO
IPNameSupport.ZoneSummaryLine[list.first, FALSE, TRUE, Log];
ENDLOOP;
IO.PutRope[log, "\n\n"];
IO.Flush[log]; };
Add: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
query: ROPE ← ViewerTools.GetContents[data.query];
log: IO.STREAM ← data.log;
arg: ROPE ← ViewerTools.GetContents[data.arg];
addresses: LIST OF IPDefs.Address;
IF query.Length[] = 0 OR arg.Length[] = 0 THEN RETURN;
IPNameCache.AddAddressToName[entry: IPNameCache.UpdateName[name: query, source: [10,2,0,32], ttl: 3333, authoritative: FALSE], address: IPName.NameToAddress[name: arg].first];
addresses ← IPName.NameToAddress[query];
IO.PutRope[log, query];
PrintListOfAddresses[log, " => ", addresses];
};
Slot: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
found: BOOLEANFALSE;
query: ROPE ← ViewerTools.GetContents[data.query];
this: NameEntry ← IPNameCache.NameLookup[query];
alias: AliasEntry ← IPNameCache.AliasLookup[query];
mx: MXEntry ← IPNameCache.MXLookup[query];
bogus: BogusNameEntry ← IPNameCache.BogusNameLookup[query];
down: DownNameEntry ← IPNameCache.DownNameLookup[query];
zone: ZoneEntry ← IPNameCache.ZoneLookup[query];
IO.PutRope[log, "\n"];
IF this # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← IPName.AddressToName[this.source];
expires: INT ← BasicTime.Period[from: now, to: this.expires];
found ← TRUE;
IO.PutF[log, "Name Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]],[integer[this.ttl]]];
IO.PutF[log,
" NameCacheLoad: %G, NameToAddress: %G, NormalizeName: %G, Rejuvinates: %G.\n",
[integer[this.nameCacheLoad]],
[integer[this.nameToAddress]],
[integer[this.normalizeName]],
[integer[this.rejuvinations]]];
IO.PutF[log, " Name: %G.\n", [rope[this.name]]];
PrintListOfAddresses[log, " Addresses: ", this.addresses];
IO.PutRope[log, "\n"];};
IF alias # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← IPName.AddressToName[alias.source];
expires: INT ← BasicTime.Period[from: now, to: alias.expires];
found ← TRUE;
IO.PutF[log, "Alias Loaded: %G, From: %G", [time[alias.loaded]], [rope[source]]];
IF ~alias.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[alias.referenced]], [integer[expires]], [integer[alias.ttl]]];
IO.PutF[log,
" AliasToName: %G, Rejuvinates: %G.\n",
[integer[alias.aliasToName]],
[integer[alias.rejuvinations]]];
IO.PutF[log, " Alias: %G.\n", [rope[alias.alias]]];
IO.PutF[log, " Name: %G.\n", [rope[alias.name]]];
IO.PutRope[log, "\n"];};
IF mx # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← IPName.AddressToName[mx.source];
expires: INT ← BasicTime.Period[from: now, to: mx.expires];
found ← TRUE;
IO.PutF[log, "MX Loaded: %G, From: %G", [time[mx.loaded]], [rope[source]]];
IF ~mx.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[mx.referenced]], [integer[expires]], [integer[mx.ttl]]];
IO.PutF[log,
" NameToMX: %G, Rejuvinates: %G.\n",
[integer[mx.nameToMX]],
[integer[mx.rejuvinations]]];
IO.PutF[log, " Name: %G.\n", [rope[mx.name]]];
FOR list: LIST OF IPNameCache.MXHostInfo ← mx.mxHosts, list.rest UNTIL list = NIL DO
IO.PutF[log, " MX Host: %G", [rope[list.first.host]]];
IO.PutF[log,", Preference: %G", [integer[list.first.preference]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.PutRope[log, "\n"];
};
IF bogus # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← IPName.AddressToName[bogus.source];
expires: INT ← BasicTime.Period[from: now, to: bogus.expires];
found ← TRUE;
IO.PutF[log, "Bogus Name Loaded: %G, From: %G", [time[bogus.loaded]], [rope[source]]];
IF ~bogus.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[bogus.referenced]], [integer[expires]], [integer[bogus.ttl]]];
IO.PutF[log,
" NameToBogus: %G, Rejuvinates: %G.\n",
[integer[bogus.nameToBogus]],
[integer[bogus.rejuvinations]]];
IO.PutF[log, " Bogus Name: %G.\n", [rope[bogus.bogus]]];
IO.PutRope[log, "\n"];};
IF down # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← BasicTime.Period[from: now, to: down.expires];
found ← TRUE;
IO.PutF[log, "Down Name Loaded: %G", [time[down.loaded]]];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[down.referenced]], [integer[expires]], [integer[down.ttl]]];
IO.PutF[log,
" NameToDown: %G.\n",
[integer[down.nameToDown]]];
IO.PutF[log, " Down Name: %G.\n", [rope[down.name]]];
IO.PutRope[log, "\n"];};
IF zone # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← IPName.AddressToName[zone.source];
expires: INT ← BasicTime.Period[from: now, to: zone.expires];
found ← TRUE;
IO.PutF[log, "Zone Loaded: %G, From: %G", [time[zone.loaded]], [rope[source]]];
IF ~zone.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[zone.referenced]], [integer[expires]], [integer[zone.ttl]]];
IO.PutF[log,
" ZoneLookup: %G, Rejuvinates: %G.\n",
[integer[zone.zoneLookup]],
[integer[zone.rejuvinations]]];
IO.PutF[log, " Zone: %G.\n", [rope[zone.zone]]];
PrintListOfNames[log, " Servers: ", zone.servers];
IO.PutRope[log, "\n"];};
IF ~found THEN IO.PutRope[log, "Entry not found.\n"];
IO.PutRope[log, "\n"];
IO.Flush[log]; };
Addrs: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
addresses: LIST OF AddressEntry = IPNameCache.GetAddresses[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF AddressEntry ← addresses, list.rest UNTIL list = NIL DO
this: AddressEntry ← list.first;
source: ROPE ← IPName.AddressToName[this.source];
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Address slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log,
" AddressCacheLoad: %G, AddressToName: %G, Rejuvinated: %G.\n",
[integer[this.addressCacheLoad]],
[integer[this.addressToName]],
[integer[this.rejuvinations]]];
IO.PutF[log, " Address: %G.\n", [rope[IPName.AddressToRope[this.address]]]];
PrintListOfRopes[log, " Names: ", this.names];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
Aliases: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
aliases: LIST OF AliasEntry = IPNameCache.GetAliases[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF AliasEntry ← aliases, list.rest UNTIL list = NIL DO
this: AliasEntry ← list.first;
source: ROPE ← IPName.AddressToName[this.source];
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Alias slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log,
" AddressToName: %G, Rejuvinated: %G.\n",
[integer[this.aliasToName]],
[integer[this.rejuvinations]]];
IO.PutF[log, " Alias: %G.\n", [rope[this.alias]]];
IO.PutF[log, " Name: %G.\n", [rope[this.name]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
MXs: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
mxList: LIST OF MXEntry = IPNameCache.GetMXList[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF MXEntry ← mxList, list.rest UNTIL list = NIL DO
mx: MXEntry ← list.first;
source: ROPE ← IPName.AddressToName[mx.source];
expires: INT ← BasicTime.Period[from: now, to: mx.expires];
n ← n + 1;
IO.PutF[log, "MX slot %G.\n", [integer[n]]];
IO.PutF[log, "Loaded: %G, From: %G", [time[mx.loaded]], [rope[source]]];
IF ~mx.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[mx.referenced]], [integer[expires]], [integer[mx.ttl]]];
IO.PutF[log,
" NameToMX: %G, Rejuvinates: %G.\n",
[integer[mx.nameToMX]],
[integer[mx.rejuvinations]]];
IO.PutF[log, " Name: %G.\n", [rope[mx.name]]];
FOR list: LIST OF IPNameCache.MXHostInfo ← mx.mxHosts, list.rest UNTIL list = NIL DO
IO.PutF[log, " MX Host: %G", [rope[list.first.host]]];
IO.PutF[log, ", Preference: %G", [integer[list.first.preference]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
Bogus: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
bogusAddresses: LIST OF BogusAddressEntry = IPNameCache.GetBogusAddresses[];
bogusNames: LIST OF BogusNameEntry = IPNameCache.GetBogusNames[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF BogusNameEntry ← bogusNames, list.rest UNTIL list = NIL DO
this: BogusNameEntry ← list.first;
source: ROPE ← IPName.AddressToName[this.source];
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Bogus slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log,
" N=>?: %G, R: %G.\n",
[integer[this.nameToBogus]],
[integer[this.rejuvinations]]];
IO.PutF[log, " Name: %G.\n", [rope[this.bogus]]];
IO.PutRope[log, "\n"];
ENDLOOP;
FOR list: LIST OF BogusAddressEntry ← bogusAddresses, list.rest UNTIL list = NIL DO
this: BogusAddressEntry ← list.first;
source: ROPE ← IPName.AddressToName[this.source];
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Bogus slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log,
" BogusNameLookup: %G, Rejuvinated: %G.\n",
[integer[this.addressToBogus]],
[integer[this.rejuvinations]]];
IO.PutF[log, " Address: %G.\n", [rope[IPName.AddressToRope[this.bogus]]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };

Down: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
downAddresses: LIST OF DownAddressEntry = IPNameCache.GetDownAddresses[];
downNames: LIST OF DownNameEntry = IPNameCache.GetDownNames[];
downServers: LIST OF DownServerEntry = IPNameCache.GetDownServers[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF DownNameEntry ← downNames, list.rest UNTIL list = NIL DO
this: DownNameEntry ← list.first;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Down name slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G", [time[this.loaded]]];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " N=>?: %G.\n", [integer[this.nameToDown]]];
IO.PutF[log, " Name: %G.\n", [rope[this.name]]];
IO.PutRope[log, "\n\n"];
ENDLOOP;
n ← 0;
FOR list: LIST OF DownAddressEntry ← downAddresses, list.rest UNTIL list = NIL DO
this: DownAddressEntry ← list.first;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Down address slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G", [time[this.loaded]]];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " DownNameLookup: %G.\n", [integer[this.addressToDown]]];
IO.PutF[log, " Address: %G.\n", [rope[IPName.AddressToRope[this.address]]]];
IO.PutRope[log, "\n\n"];
ENDLOOP;
n ← 0;
FOR list: LIST OF DownServerEntry ← downServers, list.rest UNTIL list = NIL DO
this: DownServerEntry ← list.first;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Down server slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G", [time[this.loaded]]];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " DownServerLookup: %G.\n", [integer[this.serverToDown]]];
IO.PutF[log, " Address: %G.\n", [rope[IPName.AddressToRope[this.address]]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };

Names: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
names: LIST OF NameEntry = IPNameCache.GetNames[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF NameEntry ← names, list.rest UNTIL list = NIL DO
this: NameEntry ← list.first;
source: ROPE ← IPName.AddressToName[this.source];
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Name slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log,
" NameCacheLoad: %G, NameToAddress: %G, NameToName: %G, Rejuvinated: %G.\n",
[integer[this.nameCacheLoad]],
[integer[this.nameToAddress]],
[integer[this.normalizeName]],
[integer[this.rejuvinations]]];
IO.PutF[log, " Name: %G.\n", [rope[this.name]]];
PrintListOfAddresses[log, " Addresses: ", this.addresses];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
Zones: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
servers: LIST OF ZoneEntry = IPNameCache.GetZones[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF ZoneEntry ← servers, list.rest UNTIL list = NIL DO
this: ZoneEntry ← list.first;
source: ROPE ← IPName.AddressToName[this.source];
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Zone slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutF[log, ".\n"];
IO.PutF[data.log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log,
" ZoneLookup: %G, Rejuvinated: %G.\n",
[integer[this.zoneLookup]],
[integer[this.rejuvinations]]];
IO.PutF[log, " Zone: %G\n", [rope[this.zone]]];
PrintListOfRopes[log, " Servers: ", this.servers];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
Hist: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
histograms: LIST OF HistogramEntry = IPNameCache.GetHistograms[];
FOR list: LIST OF HistogramEntry ← histograms, list.rest UNTIL list = NIL DO
[] ← IPName.LoadCacheFromAddress[list.first.server, TRUE];
ENDLOOP;
IO.PutRope[log, "\n"];
IO.PutF[log, "Names: %G, ", [integer[ListLength[IPNameCache.GetNames[]]]]];
IO.PutF[log, "Aliases: %G, ", [integer[ListLength[IPNameCache.GetAliases[]]]]];
IO.PutF[log, "Bogus Names: %G\n", [integer[ListLength[IPNameCache.GetBogusNames[]]]]];
IO.PutF[log, "Addresses: %G, ", [integer[ListLength[IPNameCache.GetAddresses[]]]]];
IO.PutF[log, "Bogus Addresses: %G\n", [integer[ListLength[IPNameCache.GetBogusAddresses[]]]]];
IO.PutF[log, "Zones: %G.\n", [integer[ListLength[IPNameCache.GetZones[]]]]];
FOR list: LIST OF HistogramEntry ← histograms, list.rest UNTIL list = NIL DO
running: INT ← 0;
this: HistogramEntry ← list.first;
serverRope: ROPE = IPName.AddressToRope[this.server];
serverName: ROPE = IPName.AddressToName[this.server];
cacheHits: INT ← TotalCacheHits[this];
probes: INT ← TotalProbes[this];
querys: INT ← probes + cacheHits;
IO.PutF[log, " Server: %G = %G, Miss rate: %1.2F%%.\n", [rope[serverRope]], [rope[serverName]], [real[100.0*probes/querys]] ];
IF this.lost # 0 THEN IO.PutF[log, " Packets Lost: %G, %1.2F%%.\n", [integer[this.lost]], [real[100.0*this.lost/probes]] ];
IO.PutF[log, " Cache Hits: %G.\n", [integer[cacheHits]] ];
FOR type: IPNameCache.CacheType IN IPNameCache.CacheType DO
counter: INT ← this.cacheHits[type];
counterPerCent: REAL;
IF counter = 0 THEN LOOP;
counterPerCent ← 100.0*counter/cacheHits;
IO.PutF[log, "%7G %7.2F%% %G\n", [integer[counter]], [real[counterPerCent]], [rope[cacheHitText[type]]] ];
ENDLOOP;
IO.PutF[log, " Probes: %G.\n", [integer[probes]] ];
FOR type: IPNameCache.ProbeType IN IPNameCache.ProbeType DO
counter: INT ← this.probes[type];
counterPerCent: REAL;
IF counter = 0 THEN LOOP;
counterPerCent ← 100.0*counter/probes;
IO.PutF[log, "%7G %7.2F%% %G\n", [integer[counter]], [real[counterPerCent]], [rope[probeText[type]]] ];
ENDLOOP;
IO.PutRope[log, " Response time:\n"];
FOR i: INT IN [0..IPNameCache.histogramSlots) DO
counter: INT ← this.counters[i];
milliseconds: INT ← i*IPNameCache.histogramSlotSize;
counterPerCent, runningPerCent: REAL;
IF counter = 0 THEN LOOP;
running ← running + counter;
counterPerCent ← 100.0*counter/probes;
runningPerCent ← 100.0*running/probes;
IO.PutF[log, "%7G %7.2F %7.2F %7G\n", [integer[counter]], [real[counterPerCent]], [real[runningPerCent]], [integer[milliseconds]] ];
ENDLOOP;
IO.PutRope[log, "\n"];
ENDLOOP;
IO.PutRope[log, "\n"];
IO.Flush[log]; };
ListLength: PROCEDURE [arg: REF ANY] RETURNS [length: INT ← 0] = TRUSTED {
FOR list: LIST OF REF ANYLOOPHOLE[arg], list.rest UNTIL list = NIL DO
length ← length + 1;
ENDLOOP; };
cacheHitText: ARRAY IPNameCache.CacheType OF ROPE = [
name: "Names", alias: "Aliases", bogusName: "Bogus Names", address: "Addresses", bogusAddress: "Bogus Addresses", zone: "Zones"];
TotalCacheHits: PROCEDURE [entry: HistogramEntry] RETURNS [total: INT ← 0] = {
FOR type: IPNameCache.CacheType IN IPNameCache.CacheType DO
total ← total + entry.cacheHits[type];
ENDLOOP; };
probeText: ARRAY IPNameCache.ProbeType OF ROPE = [
name: "Names",
nameRejuvination: "Name Rejuvenation",
aliasRejuvination: "Alias Rejuvenation",
bogusNameRejuvination: "Bogus Name Rejuvenation",
address: "Address",
addressRejuvination: "Address Rejuvenation",
bogusAddressRejuvination: "Bogus Address Rejuvenation",
newZone: "New Zone",
zoneRejuvination: "Zone Rejuvenation",
newServer: "New Server"];
TotalProbes: PROCEDURE [entry: HistogramEntry] RETURNS [total: INT ← 0] = {
FOR type: IPNameCache.ProbeType IN IPNameCache.ProbeType DO
total ← total + entry.probes[type];
ENDLOOP; };
PrintListOfRopes: PROC [log: IO.STREAM, header: ROPE, ropes: LIST OF ROPE] = {
IO.PutRope[log, header];
FOR list: LIST OF ROPE ← ropes, list.rest UNTIL list = NIL DO
IF list # ropes THEN IO.PutRope[log, ", "];
IO.PutF[log, "\"%G\"", [rope[list.first]]];
ENDLOOP;
IO.PutRope[log, "\n"]; };
PrintListOfAddresses: PROC [log: IO.STREAM, header: ROPE, addresses: LIST OF IPDefs.Address] = {
IO.PutRope[log, header];
FOR list: LIST OF IPDefs.Address ← addresses, list.rest UNTIL list = NIL DO
IF list # addresses THEN IO.PutRope[log, ", "];
IO.PutRope[log, IPName.AddressToRope[list.first]];
ENDLOOP;
IO.PutRope[log, "\n"]; };
PrintListOfNames: PROC [log: IO.STREAM, header: ROPE, names: LIST OF ROPE] = {
IO.PutRope[log, header];
FOR list: LIST OF ROPE ← names, list.rest UNTIL list = NIL DO
IF list # names THEN IO.PutRope[log, ", "];
IO.PutRope[log, list.first];
ENDLOOP;
IO.PutRope[log, "\n"]; };
MakeRule: PROC [parent, sibling: Viewer] RETURNS [child: Viewer] = {
child ← Rules.Create[
info: [parent: parent, border: FALSE,
wy: IF sibling = NIL THEN 0 ELSE sibling.wy + sibling.wh + 2, wx: 0, ww: parent.ww, wh: 1],
paint: FALSE ];
Containers.ChildXBound[parent, child]; };
MakeButton: PROC [parent, sibling: Viewer, data: REF ANY, name: ROPE, proc: Buttons.ButtonProc] RETURNS[child: Viewer] = {
child ← Buttons.Create[
info: [name: name, parent: parent, border: TRUE,
wy: sibling.wy, wx: sibling.wx + buttonWidth - 1, ww: buttonWidth],
proc: proc,
clientData: data,
fork: TRUE,
paint: FALSE]; };
BoolProc: TYPE = PROC [parent: Viewer, clientData: REF, value: BOOL];
Bool: TYPE = REF BoolRec;
BoolRec: TYPE = RECORD [
value: REF BOOL,
change: BoolProc,
clientData: REF,
button: Viewer ];
MakeBool: PROC
[parent, sibling: Viewer, clientData: REFNIL, name: ROPE, init: REF BOOL, change: BoolProc ← NIL, x, y: INTEGER ← 0]
RETURNS [child: Viewer] = {
bool: Bool ← NEW [BoolRec ← [
value: IF init # NIL THEN init ELSE NEW [BOOLTRUE],
change: change,
clientData: clientData,
button: NIL ] ];
IF y = 0 THEN y ← sibling.wy + sibling.wh;
IF x = 0 THEN x ← 2;
child ← Buttons.Create[
info: [name: name, parent: parent, border: TRUE, wx: x, wy: y],
proc: BoolHelper, clientData: bool, fork: TRUE, paint: TRUE];
bool.button ← child;
IF bool.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack]; };
BoolHelper: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
self: Buttons.Button = NARROW[parent];
bool: Bool = NARROW[clientData];
bool.value^ ← ~bool.value^;
IF bool.value^ THEN Buttons.SetDisplayStyle[bool.button, $WhiteOnBlack]
ELSE Buttons.SetDisplayStyle[bool.button, $BlackOnWhite];
IF bool.change # NIL THEN bool.change[self.parent, bool.clientData, bool.value^]; };
MakeLabel: PROC [parent, sibling: Viewer, name: ROPE] RETURNS [child: Viewer] = {
child ← Labels.Create[
info: [name: name, parent: parent, border: FALSE,
wy: sibling.wy + sibling.wh + (IF sibling.class.flavor = $Button THEN -1 ELSE 2),
wx: 2],
paint: FALSE ]; };
MakeLabeledText: PROC [
parent, sibling: Viewer, name, data: ROPE, prev: Viewer, newline: BOOLTRUE] RETURNS [child: Viewer] = {
x: INTEGER = IF newline THEN 2 ELSE sibling.wx + sibling.ww + 10;
y: INTEGER = IF newline THEN sibling.wy + sibling.wh + 1 ELSE sibling.wy;
child ← ViewerTools.MakeNewTextViewer[
info: [parent: parent, wh: buttonHeight, ww: 999, scrollable: TRUE,
data: IF prev = NIL THEN data ELSE ViewerTools.GetContents[prev],
border: FALSE,
wx: x + buttonWidth + 2, wy: y],
paint: FALSE ];
Containers.ChildXBound[parent, child];
[] ← Buttons.Create[
info: [name: name, parent: parent, wh: buttonHeight, border: FALSE, wx: x, wy: y],
proc: LabeledTextProc, clientData: child, fork: FALSE, paint: FALSE];
RETURN[child]; };
LabeledTextProc: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
text: Viewer = NARROW[clientData];
SELECT mouseButton FROM
red => ViewerTools.SetSelection[text, NIL];
yellow => NULL;
blue => { ViewerTools.SetContents[text, NIL]; ViewerTools.SetSelection[text, NIL] };
ENDCASE => ERROR; };
CreateOne[];
Commander.Register["IPNameTool", Create, "MailGateway name cache control."];
END.