DIRECTORY BasicTime: TYPE USING [Now], Buttons: TYPE USING [Button, ButtonProc, Create], Commander USING [CommandProc, Register], Containers: TYPE USING [ChildXBound, ChildYBound, Container, Create], DriverDefs: TYPE USING [Network], IO, Labels: TYPE USING [Create, Label, Set, SetDisplayStyle], Menus: TYPE USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc], Process: TYPE USING [Pause, SecondsToTicks], ProcessorFace USING [processorID], PupDefs: TYPE USING [DataWordsPerPupBuffer, GetFreePupBuffer, GetPupAddress, GetPupContentsBytes, MoveRopeToPupBuffer, ReturnFreePupBuffer, PupAddressToRope, PupBuffer, PupNameTrouble, PupPackageDestroy, PupPackageMake, PupRouterBroadcastThis, PupSocket, PupSocketDestroy, PupSocketMake, SecondsToTocks, SetPupContentsBytes], PupRouterDefs: TYPE USING [GetRoutingTable, GetRoutingTableEntry, RoutingTableEntry, RoutingTable, RoutingTableObject], PupTypes: TYPE USING [echoSoc, fillInPupAddress, fillInSocketID, maxDataWordsPerGatewayPup, miscSrvSoc, PupAddress, PupSocketID], Rope: TYPE USING [Concat, FromChar, Length, ROPE, Substr], SystemVersion USING [machineType], TypeScript: TYPE USING [Create], VFonts: TYPE USING [CharWidth], ViewerClasses: TYPE USING [Viewer, ViewerClassRec], ViewerIO: TYPE USING [CreateViewerStreams], ViewerOps: TYPE USING [DestroyViewer, PaintViewer], ViewerTools: TYPE USING [GetContents, MakeNewTextViewer, SetSelection]; PupTool: MONITOR IMPORTS BasicTime, Buttons, Commander, Containers, IO, Labels, Menus, Process, ProcessorFace, PupDefs, PupRouterDefs, Rope, SystemVersion, TypeScript, VFonts, ViewerIO, ViewerOps, ViewerTools = BEGIN entryHeight: NAT = 15; entryVSpace: NAT = 8; entryHSpace: NAT = 10; -- a ToolHandle is a REF to the data for a particular instance of the tool. ToolHandle: TYPE = REF ToolHandleRec; ToolHandleRec: TYPE = RECORD [ pleaseStop, echoInUse: BOOL _ FALSE, -- useful flags viewer, root, msg: ViewerClasses.Viewer, -- viewer and parent out: IO.STREAM, -- text stream echoThrough: CONDITION]; -- echo process is done MakeTool: PROC = BEGIN handle: ToolHandle _ NEW[ToolHandleRec]; promptButton, textBox: ViewerClasses.Viewer; menu: Menus.Menu _ Menus.CreateMenu[1]; height: NAT _ 0; charSize: INTEGER = VFonts.CharWidth['0]; initData: Rope.ROPE = "ME"; -- must use this string PupDefs.PupPackageMake[]; handle.root _ Containers.Create[[ name: "PupTool", iconic: TRUE, menu: menu, column: left, scrollable: FALSE ]]; Menus.AppendMenuEntry[menu: menu, line: 0, entry: Menus.CreateEntry[clientData: handle, name: "EchoOn", proc: EchoProc, fork: TRUE]]; Menus.AppendMenuEntry[menu: menu, line: 0, entry: Menus.CreateEntry[clientData: handle, name: "EchoOff", proc: StopProc, fork: FALSE]]; Menus.AppendMenuEntry[menu: menu, line: 0, entry: Menus.CreateEntry[clientData: handle, name: "RoutingTable", proc: RouteProc, fork: FALSE]]; Menus.AppendMenuEntry[menu: menu, line: 0, entry: Menus.CreateEntry[clientData: handle, name: "GetName", proc: ToNameProc, fork: FALSE]]; Menus.AppendMenuEntry[menu: menu, line: 0, entry: Menus.CreateEntry[clientData: handle, name: "GetAddress", proc: ToAddressProc, fork: FALSE]]; Menus.AppendMenuEntry[menu: menu, line: 0, entry: Menus.CreateEntry[clientData: handle, name: "ProcessorID", proc: GetProcID, fork: FALSE]]; height _ height + entryVSpace; promptButton _ Buttons.Create[ info: [name: "Name or Address", wy: height, wh: entryHeight, wx: 10*charSize, parent: handle.root], proc: Prompt, clientData: handle]; handle.viewer _ ViewerTools.MakeNewTextViewer[[ parent: handle.root, wx: promptButton.wx + promptButton.ww + entryHSpace, wy: height+2, -- (hack: add 2 to align text with button baseline) ww: 50*charSize, -- 50 digits worth of width wh: entryHeight, data: initData, scrollable: FALSE, border: FALSE ]]; height _ height + entryHeight + entryVSpace; handle.msg _ Labels.Create[[ parent: handle.root, wx: 10*charSize, wy: height, ww: 80*charSize, -- 80 digits worth of width wh: entryHeight, border: FALSE ]]; height _ height + entryHeight + entryVSpace; -- interline spacing textBox _ TypeScript.Create [[ parent: handle.root, border: FALSE, wy: height ]]; Containers.ChildXBound[handle.root, textBox]; Containers.ChildYBound[handle.root, textBox]; [, handle.out] _ ViewerIO.CreateViewerStreams[viewer: textBox, name: NIL]; PrintHeaderLine[handle.out]; ViewerOps.PaintViewer[handle.root, all]; END; Prompt: Buttons.ButtonProc = TRUSTED BEGIN handle: ToolHandle _ NARROW[clientData]; -- get our data ViewerTools.SetSelection[handle.viewer]; -- force the selection END; PrintHeaderLine: PROC[out: IO.STREAM] = BEGIN meID: PupTypes.PupSocketID _ [0,0]; me: PupTypes.PupAddress _ [,,[0,0]]; pID: RECORD[a, b, c: NAT] _ LOOPHOLE[ProcessorFace.processorID]; me _ PupDefs.GetPupAddress[meID, "ME"]; -- must use this string IO.PutF[out, "PupTool of %t running on a %g processor\n", IO.time[BasicTime.Now[]], [rope[SELECT SystemVersion.machineType FROM dolphin => "Dolphin", dorado => "Dorado", dandelion => "Dandelion", dicentra => "Dicentra", ENDCASE => "{Unknown processor type!}"]]]; END; ErrorMsg: PROC[l: Labels.Label, r: Rope.ROPE _ NIL] = BEGIN IF Rope.Length[r] > 70 THEN r _ Rope.Substr[r, 0, 70]; IF Rope.Length[r] < 62 THEN r _ Rope.Concat["ERROR > ", r]; Labels.Set[l, r]; Labels.SetDisplayStyle[l, $WhiteOnBlack]; Process.Pause[Process.SecondsToTicks[1]]; Labels.SetDisplayStyle[l, $BlackOnWhite]; END; ClearMsg: PROC[l: Labels.Label] = BEGIN Labels.Set[l, NIL]; Labels.SetDisplayStyle[l, $BlackOnWhite]; END; InRope: PROC[v: ViewerClasses.Viewer] RETURNS [r: Rope.ROPE _ NIL] = BEGIN r _ ViewerTools.GetContents[v]; END; PutSep: PROC[out: IO.STREAM] = BEGIN IO.PutText[out, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"]; END; NewLine: PROC[out: IO.STREAM] = BEGIN IO.PutChar[out, '\n]; END; ErrorPupToRope: PROC[b: PupDefs.PupBuffer] RETURNS[s: Rope.ROPE]= BEGIN source: PupTypes.PupAddress _ b.source; IF b.pupType = error THEN BEGIN len: NAT = PupDefs.GetPupContentsBytes[b]; s _ IO.PutFR["[Pup, code=%b, from: ", IO.card[LOOPHOLE[b.errorCode, NAT]]]; s _ Rope.Concat[s, PupDefs.PupAddressToRope[source]]; s _ Rope.Concat[s, "] "]; FOR i: NAT IN [0..len-2*(10+1+1)) DO s _ Rope.Concat[s, Rope.FromChar[b.errorText[i]]]; ENDLOOP; END ELSE s _ IO.PutFR["## Funny PupType = %b ##\n ", IO.card[LOOPHOLE[b.pupType, NAT]]]; END; PupBodyToRope: PROC[b: PupDefs.PupBuffer] RETURNS[s: Rope.ROPE]= BEGIN s _ NIL; FOR i: NAT IN [0..PupDefs.GetPupContentsBytes[b]) DO s _ Rope.Concat[s, Rope.FromChar[b.pupChars[i]]]; ENDLOOP; END; EchoProc: Menus.MenuProc = TRUSTED BEGIN OPEN PupDefs, PupTypes; h: ToolHandle = NARROW[clientData]; bytesPerBuffer: NAT; funny, late, recv, sent, wrong: INT _ 0; me, where: PupAddress _ [,,echoSoc]; mySoc: PupSocket; mySocID: PupSocketID _ echoSoc; packetNumber: NAT _ 0; routing: PupRouterDefs.RoutingTableEntry; r: Rope.ROPE; IF EchoIsInUse[h] THEN RETURN; ClearMsg[h.msg]; r _ InRope[h.viewer]; IF Rope.Length[r] = 0 THEN {ErrorMsg[h.msg, "Name needed"]; GOTO GetOut}; where _ GetPupAddress[mySocID, r ! PupNameTrouble => {ErrorMsg[h.msg, e]; GOTO GetOut }]; mySoc _ PupSocketMake[fillInSocketID, where, SecondsToTocks[2]]; me _ mySoc.getLocalAddress[]; PutSep[h.out]; IO.PutF[h.out, "Echo to <%g> via [%g] => [", IO.rope[r], IO.rope[PupAddressToRope[me]]]; routing _ PupRouterDefs.GetRoutingTableEntry[where.net]; IF (routing.hop # 0) AND (routing.network # NIL) THEN IO.PutF[h.out, "%b#%b#] => [", IO.card[LOOPHOLE[routing.network.netNumber.b, NAT]], IO.card[LOOPHOLE[routing.route, NAT]]]; IO.PutF[h.out, "%g]\n", IO.rope[PupAddressToRope[where]]]; bytesPerBuffer _ 2*MIN[DataWordsPerPupBuffer[], maxDataWordsPerGatewayPup]; UNTIL EchoShouldStop[h] DO FOR len: NAT IN [0..bytesPerBuffer] UNTIL EchoShouldStop[h] DO b: PupBuffer _ GetFreePupBuffer[]; b.pupID.a _ b.pupID.b _ (packetNumber _ packetNumber+1); b.pupType _ echoMe; SetPupContentsBytes[b,len]; FOR i: NAT IN [0..len) DO b.pupBytes[i] _ i MOD 400B; ENDLOOP; mySoc.put[b]; sent _ sent+1; UNTIL (b _ mySoc.get[]) = NIL DO SELECT TRUE FROM (b.pupType # iAmEcho) => {funny _ funny+1; ErrorMsg[h.msg, ErrorPupToRope[b]]; IO.PutChar[h.out, 'x]; GOTO Wrong}; ((b.pupID.a # packetNumber) OR (b.pupID.b # packetNumber) OR (len # GetPupContentsBytes[b])) => {IO.PutChar[h.out, '#]; late _ late+1 }; ENDCASE => BEGIN FOR i: NAT IN [0..len) DO IF b.pupBytes[i] # (i MOD 400B) THEN {wrong _ wrong+1; IO.PutChar[h.out, '~]; GOTO Wrong}; ENDLOOP; IO.PutChar[h.out, '!]; -- successful echo recv _ recv+1; EXIT; END; ReturnFreePupBuffer[b]; REPEAT Wrong => NULL; ENDLOOP; IF b # NIL THEN ReturnFreePupBuffer[b] ELSE IO.PutChar[h.out, '?]; ENDLOOP; NewLine[h.out]; ENDLOOP; PupSocketDestroy[mySoc]; IO.PutF[h.out, "Out: %d, In: %d (%d%%)\n", -- ? timedout IO.card[sent], IO.card[recv], IO.card[(recv*100)/sent]]; -- ! ok (outbound) IF late # 0 THEN IO.PutF[h.out, "Late: %d (%d%%)\n", IO.card[late], IO.card[(late*100)/sent]]; -- # IF funny # 0 THEN IO.PutF[h.out, "%d funny packets\n", IO.card[funny]]; -- x IF wrong # 0 THEN IO.PutF[h.out, "%d wrong data\n", IO.card[wrong]]; -- ~ EchoUserStopped[h]; EXITS GetOut => {h: ToolHandle = NARROW[clientData]; EchoUserStopped[h]}; END; RouteProc: Menus.MenuProc = TRUSTED BEGIN pupRt: PupRouterDefs.RoutingTable; h: ToolHandle _ NARROW[clientData]; k: NAT _ 0; PutSep[h.out]; ClearMsg[h.msg]; IO.PutText[h.out, "Local PupRouting Table\n"]; IO.PutText[h.out, "| Net Via Hops | Net Via Hops | Net Via Hops |\n"]; IO.PutText[h.out, "|.....................................|.......................................|......................................|\n"]; pupRt _ PupRouterDefs.GetRoutingTable[]; FOR i: NAT IN [0..pupRt.length) DO r: PupRouterDefs.RoutingTableEntry = @pupRt[i]; network: DriverDefs.Network = r.network; IF network=NIL THEN LOOP; IF k=0 THEN IO.PutChar[h.out, '|]; IO.PutF[h.out, "%4b%4b#", IO.card[i], IO.card[LOOPHOLE[network.netNumber.b, NAT]]]; IO.PutF[h.out, "%03b#%4b |", IO.card[IF r.hop # 0 THEN r.route ELSE network.hostNumber], IO.card[r.hop]]; IF (k_k+1)=3 THEN {NewLine[h.out]; k_0}; ENDLOOP; IF k # 0 THEN NewLine[h.out]; IO.PutText[h.out, "|.....................................|.......................................|......................................|\n\n"]; END; ToNameProc: Menus.MenuProc = TRUSTED BEGIN OPEN PupTypes, PupDefs; h: ToolHandle = NARROW[clientData]; soc: PupSocket; b: PupBuffer; addrID: PupSocketID _ [0, 0]; addr: PupAddress _ [, , [0, 0]]; hit: BOOL _ FALSE; r: Rope.ROPE; r _ InRope[h.viewer]; ClearMsg[h.msg]; IF Rope.Length[r] = 0 THEN BEGIN ErrorMsg[h.msg, "Address needed"]; RETURN; END; addr _ GetPupAddress[addrID, r ! PupNameTrouble => {ErrorMsg[h.msg, e]; GOTO NoName;}]; soc _ PupSocketMake[fillInSocketID, fillInPupAddress, SecondsToTocks[2]]; THROUGH [0..10) UNTIL hit DO b _ GetFreePupBuffer[]; b.pupType _ addressLookup; b.pupID _ [0, 0]; b.dest.socket _ PupTypes.miscSrvSoc; b.source _ soc.getLocalAddress[]; b.address _ addr; SetPupContentsBytes[b, 2*SIZE[PupAddress]]; PupRouterBroadcastThis[b]; UNTIL hit OR (b _ soc.get[]) = NIL DO SELECT b.pupType FROM addressIs => BEGIN hit _ TRUE; PutSep[h.out]; IO.PutF[h.out, "Name of <%g> is: %g\n", IO.rope[r], IO.rope[PupBodyToRope[b]]]; END; nameError => BEGIN hit _ TRUE; ErrorMsg[h.msg, PupBodyToRope[b]]; END; ENDCASE => ErrorMsg[h.msg, ErrorPupToRope[b]]; ReturnFreePupBuffer[b]; ENDLOOP; IF ~hit THEN ErrorMsg[h.msg, "No Response that try"]; ENDLOOP; PupSocketDestroy[soc]; EXITS NoName => NULL; END; ToAddressProc: Menus.MenuProc = TRUSTED BEGIN OPEN PupTypes, PupDefs; h: ToolHandle = NARROW[clientData]; soc: PupSocket; b: PupBuffer; hit: BOOL _ FALSE; r: Rope.ROPE; r _ InRope[h.viewer]; ClearMsg[h.msg]; IF Rope.Length[r] = 0 THEN BEGIN ErrorMsg[h.msg, "Name needed"]; RETURN; END; soc _ PupSocketMake[fillInSocketID, fillInPupAddress, SecondsToTocks[2]]; THROUGH [0..10) UNTIL hit DO b _ GetFreePupBuffer[]; b.pupType _ nameLookup; b.pupID _ [0, 0]; b.dest.socket _ PupTypes.miscSrvSoc; b.source _ soc.getLocalAddress[]; PupDefs.MoveRopeToPupBuffer[b, r]; PupRouterBroadcastThis[b]; UNTIL hit OR (b _ soc.get[]) = NIL DO SELECT b.pupType FROM nameIs => BEGIN n: NAT _ GetPupContentsBytes[b]/(2*SIZE[PupAddress]); addresses: LONG POINTER TO ARRAY [0..0) OF PupAddress _ LOOPHOLE[@b.pupBody]; hit _ TRUE; PutSep[h.out]; IO.PutF[h.out, "Address of <%g> is: ", IO.rope[r]]; FOR i: NAT IN [0..n) DO IF i # 0 THEN IO.PutText[h.out, ", "]; IO.PutRope[h.out, PupAddressToRope[addresses[i]]]; ENDLOOP; NewLine[h.out]; END; nameError => BEGIN hit _ TRUE; ErrorMsg[h.msg, PupBodyToRope[b]]; END; ENDCASE => ErrorMsg[h.msg, ErrorPupToRope[b]]; ReturnFreePupBuffer[b]; ENDLOOP; IF ~hit THEN ErrorMsg[h.msg, "No Response that try"]; ENDLOOP; PupSocketDestroy[soc]; END; QuitProc: Menus.MenuProc = TRUSTED BEGIN h: ToolHandle = NARROW[clientData]; StopEchoUser[h]; ViewerOps.DestroyViewer[h.root]; PupDefs.PupPackageDestroy[]; END; StopProc: Menus.MenuProc = TRUSTED BEGIN h: ToolHandle = NARROW[clientData]; StopEchoUser[h]; END; GetProcID: Menus.MenuProc = TRUSTED BEGIN h: ToolHandle = NARROW[clientData]; pID: RECORD[a, b, c: NAT] _ LOOPHOLE[ProcessorFace.processorID]; PutSep[h.out]; IO.PutF[h.out, "\nThis processor id is: %b%b%bB\n", [integer[pID.a]], [integer[pID.b]], [integer[pID.c]]]; END; StopEchoUser: ENTRY PROC [h: ToolHandle] = BEGIN h.pleaseStop _ TRUE; UNTIL NOT h.echoInUse DO WAIT h.echoThrough ENDLOOP; h.pleaseStop _ FALSE; END; EchoShouldStop: ENTRY PROC [h: ToolHandle] RETURNS[BOOL] = INLINE {RETURN[h.pleaseStop]}; EchoUserStopped: ENTRY PROC [h: ToolHandle] = {h.echoInUse _ FALSE; NOTIFY h.echoThrough}; EchoIsInUse: ENTRY PROC [h: ToolHandle] RETURNS [BOOL] = {IF h.echoInUse THEN RETURN [TRUE]; h.echoInUse _ TRUE; RETURN[FALSE]}; DoIt: Commander.CommandProc = TRUSTED BEGIN MakeTool[] END; Commander.Register[key: "PupTool", proc: DoIt, doc: "Simple network interrogation program"]; END. ` PupTool.mesa; By Steve Temple on August 27, 1982 9:39 am Adapted from PupHacks by Hal Murray Last edited by Steve Temple, November 11, 1982 2:41 pm Converted to Cedar 5.2 by Neil Gunther, February 27, 1985 3:40:54 pm PST Last edited by John Larson, July 29, 1985 4:41:57 pm PDT John Larson July 29, 1985 2:28:05 pm PDT changes to: DIRECTORY Κr˜™Jšœ…™…JšœEΟk™HIcode™8K™K™šΣ œœœœœ,œ)œœ?œœœ œœ2œœIœœ,œœœυœœtœœœœœœœœœœ œœ(œœ&œœ1œœ<œœ8œ›œœœœ ΟcLœ œœ œœœœžœ*žœœœ žœ œžœΟnœœœœqœœ)œ Οiœaœ.œ₯œ¦œ§œ£œͺœ«œυž4œžœ3œ œ₯žœœ8žœGœΟœTœ!œœœžœ+žœœŸœœœœœRœ œœM œœAœ'œ˜β*Jšœ˜J˜J˜J˜Jš’ œ/œŸœœœœœœœœœΚœœBœ œœœ#œ œ œœœHœ œ œœœœœœVœœ œ,œ œœœdœœœœFœœœ œ.œœ œœœœœœœœ%œ7œœœ œ)œ œ$œsœ<œœ œFœ"œZœ…œ+œ œ[œ/œœ%œœœ œœœ œœ=œ8œœœœœ-œ«œœ"œœ3œœœ œœœŽœ:œ'œWœœ œœ œœœœ:œœœ œ(œœ*œ œ œœœœœœDœ œ œ  œœ œœ"œ œ œ œœ#œœ œœ œ5œœ%œ#œœ8œœ-œ/œXœž%œ)ž&œžœ0œœœœfœ œœœœœœœœœœœ œ%œœ œ œœœ œœœœœž%œ)ž&œ œ"œœœ&œzœœ œ2œœœ$œœ_œœZœ œœΤœ2œœœœœ œœ œœ&œ œœœ œ/œœBœœœ.œœ œœ'œœœ&œ7œœ œ4œœœ!œœRœ œœθœœœœœ œœ œœœœœœœœœœ%œœœœœœœœœ8œœœ œ/œœBœœœ-œœœœœaœœœœ!œ"œœœœ œœ.œpœŸ œœœœœœœ œœœœœŸœœœœœœœŸœœœ$œœŸ œœœœœœ œœœœœœ$œœœcœΡostΡpst˜ΖM——™(Kšœ Οr ™—K™—…—<Eb