<> <> <> DIRECTORY Atom USING [GetPName], BasicTime USING [Now], Buttons USING [Button, ButtonProc, Create, SetDisplayStyle], Commander USING [CommandProc, Register], Containers USING [ChildXBound, ChildYBound, Create], Convert USING [RopeFromTime], IO USING [Close, Flush, PutF, PutFR, PutRope, STREAM], Labels USING [Create], Loader USING [BCDBuildTime], Process USING [MsecToTicks, Pause, priorityForeground, SetPriority, Ticks], PupHop USING [GetRouting, RoutingTableEntry, unreachable], PupName USING [HisName], Rope USING [Find, ROPE], Rules USING [Create], TypeScript USING [ChangeLooks, Create], VFonts USING [FontHeight, StringWidth], ViewerClasses USING [Viewer], ViewerEvents USING [EventProc, RegisterEventProc], ViewerIO USING [CreateViewerStreams], ViewerOps USING [AddProp, ComputeColumn, CreateViewer, FetchProp, MoveViewer, OpenIcon, SetOpenHeight], ViewerTools USING [GetContents, MakeNewTextViewer, SetContents, SetSelection]; PupNetWatcher: CEDAR MONITOR IMPORTS Atom, BasicTime, Buttons, Commander, Containers, Convert, IO, Labels, Loader, Process, PupHop, PupName, Rope, Rules, TypeScript, VFonts, ViewerEvents, ViewerIO, ViewerOps, ViewerTools = { BYTE: TYPE = [0..100H); ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Viewer: TYPE = ViewerClasses.Viewer; <> buttonHeight: INT _ VFonts.FontHeight[] + 3; buttonWidth: INT _ VFonts.StringWidth["Route"] + 2*3; <> <> watcherLog: STREAM _ NIL; pleaseStopWatcher: BOOLEAN _ FALSE; watcher: PROCESS _ NIL; ClientData: TYPE = REF ClientDataRep; ClientDataRep: TYPE = RECORD [ log: STREAM _ NIL, in: STREAM _ NIL, pleaseStop: BOOLEAN _ FALSE ]; global: ClientData _ NIL; -- debugging Create: Commander.CommandProc = { viewer, buttons, log: Viewer _ NIL; data: ClientData _ NEW[ClientDataRep _ []]; global _ data; viewer _ ViewerOps.CreateViewer [ flavor: $Container, info: [name: "PupNetWatcher", column: right, iconic: TRUE, scrollable: FALSE]]; [] _ ViewerEvents.RegisterEventProc[Poof, destroy, viewer, TRUE]; ViewerOps.AddProp[viewer, $PupNetWatcher, data]; log _ TypeScript.Create[ [name: "PupNetWatcher.log", wy: 27+4, parent: viewer, border: FALSE], FALSE]; [data.in, data.log] _ ViewerIO.CreateViewerStreams [ name: "PupNetWatcher.log", backingFile: "PupNetWatcher.log", viewer: log, editedStream: FALSE]; IF watcherLog = NIL THEN { watcherLog _ data.log; StartWatcher[]; }; Containers.ChildXBound[viewer, log]; Containers.ChildYBound[viewer, log]; CreateButtons[data, viewer, log]; TypeScript.ChangeLooks[log, 'f]; IO.PutF[data.log, "PupNetWatcher of %G.\n", [time[Loader.BCDBuildTime[Create]]]]; ViewerOps.OpenIcon[viewer]; }; CreateButtons: ENTRY 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 _ MakeLabel[kids, child, "What: "]; child _ MakeButton[kids, child, data, "Route", RouteProc]; 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]; }; }; Poof: ViewerEvents.EventProc = { <<[viewer: ViewerClasses.Viewer, event: ViewerEvent, before: BOOL]>> <> data: ClientData _ NARROW[ViewerOps.FetchProp[viewer, $PupNetWatcher]]; IF event # destroy OR before # TRUE THEN ERROR; IF data.log = watcherLog THEN { StopWatcher[]; watcherLog _ NIL; }; IO.Close[data.log]; IO.Close[data.in]; }; StartWatcher: ENTRY PROC = { IF watcher # NIL THEN RETURN; pleaseStopWatcher _ FALSE; watcher _ FORK Watcher[]; }; StopWatcher: ENTRY PROC = { IF watcher = NIL THEN RETURN; pleaseStopWatcher _ TRUE; IF watcher # NIL THEN TRUSTED { JOIN watcher; watcher _ NIL; }; }; Watcher: PROC = { oneSecond: Process.Ticks = Process.MsecToTicks[1000]; old: ARRAY [0..256) OF PupHop.RoutingTableEntry; Process.SetPriority[Process.priorityForeground]; FOR n: NAT IN [0..256) DO old[n] _ PupHop.GetRouting[[n]]; old[n].time _ 0; ENDLOOP; UNTIL pleaseStopWatcher DO FOR n: NAT IN [0..256) DO temp: PupHop.RoutingTableEntry _ PupHop.GetRouting[[n]]; temp.time _ 0; IF temp # old[n] THEN { netName: ROPE _ PupName.HisName[[[n],[0],[0,0,0,0]]]; IF Rope.Find[netName, "#"] = -1 THEN netName _ IO.PutFR["%G (%B##)", [rope[netName]], [integer[n]] ]; IO.PutRope[watcherLog, Convert.RopeFromTime[ BasicTime.Now[], hours, seconds, FALSE, FALSE, FALSE]]; IF temp.hop = PupHop.unreachable THEN IO.PutF[watcherLog, " Net %G is unreachable.\n", [rope[netName]] ] ELSE IO.PutF[watcherLog, " Net %G is %G hops via %G.\n", [rope[netName]], [integer[temp.hop]], [rope[PupName.HisName[temp.immediate]]] ]; IO.Flush[watcherLog]; }; old[n] _ temp; ENDLOOP; FOR i: NAT IN [0..30) UNTIL pleaseStopWatcher DO Process.Pause[oneSecond]; ENDLOOP; ENDLOOP; }; RouteProc: Buttons.ButtonProc = { <> data: ClientData _ NARROW[clientData]; Route[data]; }; Route: PROC [data: ClientData] = { PrintOne: PROC [net: BYTE] = { rte: PupHop.RoutingTableEntry _ PupHop.GetRouting[[net]]; IF rte.hop = PupHop.unreachable THEN RETURN; nets _ nets + 1; IF k = 0 THEN IO.PutF[data.log, "|"]; IO.PutF[data.log, "%3B%4B#%3B#%4D |", [integer[net]], [integer[rte.immediate.net]], [integer[rte.immediate.host]], [integer[rte.hop]] ]; IF (k _ k + 1) = 3 THEN { IO.PutF[data.log, "\n"]; k _ 0; }; }; k, nets: INT _ 0; IO.PutF[data.log, "\n Local Pup Routing Table.\n"]; IO.PutF[data.log, "| Net Via Hops | Net Via Hops | Net Via Hops |\n"]; IO.PutF[data.log, "|-----------------|-----------------|-----------------|\n"]; FOR net: BYTE IN BYTE DO PrintOne[net]; ENDLOOP; IF k # 0 THEN IO.PutF[data.log, "\n"]; IF nets > 1 THEN IO.PutF[data.log, "There are %D active networks.\n", [integer[nets]]]; }; 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, guarded: BOOL _ FALSE] RETURNS[child: Viewer] = { child _ Buttons.Create[ info: [name: name, parent: parent, border: TRUE, wy: sibling.wy, wx: sibling.wx + sibling.ww - 1, ww: buttonWidth], proc: proc, clientData: data, fork: TRUE, guarded: guarded, paint: FALSE]; }; SelectorProc: TYPE = PROC [parent: Viewer, clientData: REF, value: ATOM]; Selector: TYPE = REF SelectorRec; SelectorRec: TYPE = RECORD [ value: REF ATOM, change: PROC [parent: Viewer, clientData: REF, value: ATOM], clientData: REF, buttons: LIST OF Buttons.Button, values: LIST OF ATOM ]; MakeSelector: PROC [name: ROPE, values: LIST OF ATOM, init: REF ATOM _ NIL, change: SelectorProc _ NIL, clientData: REF _ NIL, parent: Viewer, x, y: INTEGER] RETURNS [child: Viewer] = { selector: Selector _ NEW [SelectorRec _ [ value: IF init # NIL THEN init ELSE NEW [ATOM _ values.first], change: change, clientData: clientData, buttons: NIL, values: values ] ]; last: LIST OF Buttons.Button _ NIL; child _ Labels.Create[info: [name: name, parent: parent, border: FALSE, wx: x, wy: y] ]; FOR a: LIST OF ATOM _ values, a.rest UNTIL a = NIL DO child _ Buttons.Create[ info: [name: Atom.GetPName[a.first], parent: parent, border: TRUE, wx: child.wx + child.ww + 2, wy: child.wy], proc: SelectorHelper, clientData: selector, fork: TRUE, paint: TRUE]; IF last = NIL THEN last _ selector.buttons _ CONS[first: child, rest: NIL] ELSE { last.rest _ CONS[first: child, rest: NIL]; last _ last.rest }; IF a.first = selector.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack]; ENDLOOP; }; SelectorHelper: Buttons.ButtonProc = { <> self: Buttons.Button = NARROW[parent]; selector: Selector = NARROW[clientData]; buttons: LIST OF Buttons.Button _ selector.buttons; FOR a: LIST OF ATOM _ selector.values, a.rest UNTIL a = NIL DO IF self = buttons.first THEN { selector.value^ _ a.first; IF selector.change # NIL THEN selector.change[self.parent, selector.clientData, a.first]; Buttons.SetDisplayStyle[buttons.first, $WhiteOnBlack]; } ELSE Buttons.SetDisplayStyle[buttons.first, $BlackOnWhite]; buttons _ buttons.rest; ENDLOOP; }; 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 [name: ROPE, init: REF BOOL, change: BoolProc _ NIL, clientData: REF _ NIL, parent: Viewer, x, y: INTEGER] RETURNS [child: Viewer] = { bool: Bool _ NEW [BoolRec _ [ value: IF init # NIL THEN init ELSE NEW [BOOL _ TRUE], change: change, clientData: clientData, button: NIL ] ]; 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 = { <> 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, ww: VFonts.StringWidth[name] + 2*3 + 2], paint: FALSE ]; }; MakeLabeledText: PROC [ parent, sibling: Viewer, name, data: ROPE, prev: Viewer, width: INT, newline: BOOL _ TRUE] RETURNS [child: Viewer] = { buttonWidth: INT _ VFonts.StringWidth[name] + 2*3; 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: width+10, data: IF prev = NIL THEN data ELSE ViewerTools.GetContents[prev], border: FALSE, wx: x + buttonWidth + 2, wy: y, scrollable: FALSE ], paint: FALSE ]; [] _ 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 = { <> 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; }; Commander.Register["PupNetWatcher", Create, "Watch Pup Routing table."]; }.