-- Copyright (C) 1983 by Xerox Corporation. All rights reserved. -- FindGateways.mesa, HGM, 24-Sep-83 13:38:34 DIRECTORY Display USING [Bitmap, Invert, replaceFlags, White], Format USING [], -- Needed by Put.Number and Put.Date FormSW USING [ AllocateItemDescriptor, ClientItemsProcType, CommandItem, ItemHandle, newLine, NumberItem, ProcType, StringItem], Heap USING [Create, systemZone], MsgSW USING [Post], Process USING [Detach, Yield], Put USING [Char, CR, Decimal, Text, Line, Number, LongDecimal], Runtime USING [GetBcdTime], String USING [AppendChar, AppendLongNumber, AppendNumber, AppendString], Time USING [Append, AppendCurrent, Current, Unpack], Tool USING [ Create, MakeSWsProc, UnusedLogName, MakeMsgSW, MakeFormSW, MakeFileSW, AddThisSW], ToolWindow USING [CreateSubwindow, DisplayProcType, nullBox, TransitionProcType], Window USING [Handle, Box], Buffer USING [AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer], PupWireFormat USING [BcplLongNumber, BcplToMesaLongNumber], GateControlDefs USING [ gateControlStatsSend, gateControlStatsAck, GateControlStatsEntry], PupDefs USING [ PupPackageMake, PupPackageDestroy, PupBuffer, PupSocket, PupSocketDestroy, PupSocketMake, defaultNumberOfNetworks, GetHopsToNetwork, SecondsToTocks, SetPupContentsWords, AppendPupAddress, AppendHostName, AppendErrorPup, GetPupAddress, PupNameTrouble], PupTypes USING [PupAddress, fillInSocketID]; FindGateways: PROGRAM IMPORTS Display, FormSW, Heap, MsgSW, Process, Put, Runtime, String, Time, Tool, ToolWindow, Buffer, PupDefs, PupWireFormat = BEGIN OPEN PupDefs, PupTypes; msg, form, boxes, log: Window.Handle; z: UNCOUNTED ZONE = Heap.Create[initial: 20]; defaultMaxHops: CARDINAL = 3; pleaseStop: BOOLEAN ¬ FALSE; running: BOOLEAN ¬ FALSE; indicator: {left, right, off} ¬ off; first: Gateway ¬ NIL; maxHops: CARDINAL ¬ defaultMaxHops; where: PupAddress ¬ [[0], [0], [31415, 9265]]; target: LONG STRING ¬ NIL; Gateway: TYPE = LONG POINTER TO GatewayObject; GatewayObject: TYPE = RECORD [ next: Gateway, where: PupTypes.PupAddress, text: LONG STRING]; ScanCircle: FormSW.ProcType = BEGIN IF running THEN BEGIN MsgSW.Post[msg, "Somebody is already running..."L]; RETURN; END; WriteCR[]; WriteCurrentDateAndTime[]; running ¬ TRUE; Process.Detach[FORK ScanSeveral[]]; END; ScanTarget: FormSW.ProcType = BEGIN IF running THEN BEGIN MsgSW.Post[msg, "Somebody is already running..."L]; RETURN; END; WriteCR[]; WriteCurrentDateAndTime[]; WriteString[" Finding Gateways on "L]; IF ~FindPath[] THEN RETURN; running ¬ TRUE; Process.Detach[FORK ScanOne[]]; END; Stop: FormSW.ProcType = BEGIN Off[]; END; Off: PROCEDURE = BEGIN IF ~running THEN RETURN; pleaseStop ¬ TRUE; WHILE running DO Process.Yield[]; ENDLOOP; pleaseStop ¬ FALSE; END; FindPath: PROCEDURE RETURNS [BOOLEAN] = BEGIN WriteString[target]; WriteChar['=]; GetPupAddress[ @where, target ! PupNameTrouble => BEGIN MsgSW.Post[msg, e]; WriteLine[e]; GOTO Trouble; END]; PrintPupAddress[where]; WriteLine["."L]; RETURN[TRUE]; EXITS Trouble => RETURN[FALSE]; END; ScanSeveral: PROCEDURE = BEGIN first: BOOLEAN ¬ TRUE; SetupBoxes[]; FOR net: CARDINAL IN [1..PupDefs.defaultNumberOfNetworks) UNTIL pleaseStop DO IF GetHopsToNetwork[[net]] > maxHops THEN LOOP; where ¬ [[net], [0], [31415, 9265]]; IF first THEN Put.Text[log, " Searching network "] ELSE Put.Text[log, ", "]; Put.Number[log, net, [8, FALSE, TRUE, 0]]; Put.Char[log, '(]; Put.Decimal[log, GetHopsToNetwork[[net]]]; Put.Char[log, ')]; ScanSingle[]; first ¬ FALSE; ENDLOOP; Put.CR[log]; SetDownBoxes[]; PrintGatewayList[]; DeleteList[]; running ¬ FALSE; END; ScanOne: PROCEDURE = BEGIN SetupBoxes[]; ScanSingle[]; SetDownBoxes[]; PrintGatewayList[]; DeleteList[]; running ¬ FALSE; END; ScanSingle: PROCEDURE = BEGIN pool: Buffer.AccessHandle ¬ Buffer.MakePool[send: 1, receive: 10]; soc: PupSocket ¬ PupSocketMake[fillInSocketID, where, SecondsToTocks[5]]; sequenceNumber: CARDINAL ¬ GetNextSequenceNumber[]; FOR i: CARDINAL IN [0..5) DO b: PupBuffer ¬ Buffer.GetBuffer[pup, pool, send]; b.pup.pupID.a ¬ 27182; b.pup.pupID.b ¬ sequenceNumber; b.pup.pupType ¬ GateControlDefs.gateControlStatsSend; SetPupContentsWords[b, 0]; soc.put[b]; UNTIL (b ¬ soc.get[]) = NIL DO SELECT TRUE FROM ((b.pup.pupType = GateControlDefs.gateControlStatsAck) AND (b.pup.pupID.b = sequenceNumber)) => BEGIN gse: LONG POINTER TO GateControlDefs.GateControlStatsEntry; info: Gateway ¬ FindEntry[b.pup.source]; gse ¬ LOOPHOLE[@b.pup.pupBody]; FOR i: CARDINAL IN [0..gse.versionText.length) DO String.AppendChar[info.text, gse.versionText.char[i]]; ENDLOOP; AppendUpTime[info.text, gse.startTime]; FlipBoxes[]; END; ENDCASE => BEGIN temp: STRING = [100]; PupDefs.AppendErrorPup[temp, b]; MsgSW.Post[msg, temp]; END; Buffer.ReturnBuffer[b]; ENDLOOP; IF b # NIL THEN Buffer.ReturnBuffer[b]; ENDLOOP; PupSocketDestroy[soc]; Buffer.DestroyPool[pool]; END; AppendUpTime: PROCEDURE [ s: LONG STRING, startTime: PupWireFormat.BcplLongNumber] = BEGIN now, then: LONG INTEGER; sec: LONG INTEGER; min: LONG INTEGER; hours: LONG INTEGER; String.AppendString[s, " up "L]; then ¬ PupWireFormat.BcplToMesaLongNumber[startTime]; now ¬ Time.Current[]; sec ¬ now - then; IF sec < 0 THEN BEGIN -- Startup glitch sec ¬ -sec; String.AppendChar[s, '-]; END; hours ¬ sec/3600; sec ¬ sec - hours*3600; min ¬ sec/60; sec ¬ sec - min*60; String.AppendLongNumber[s, hours, 10]; String.AppendChar[s, ':]; IF min < 10 THEN String.AppendChar[s, '0]; String.AppendLongNumber[s, min, 10]; String.AppendChar[s, ':]; IF sec < 10 THEN String.AppendChar[s, '0]; String.AppendLongNumber[s, sec, 10]; END; FindEntry: PROCEDURE [where: PupTypes.PupAddress] RETURNS [new: Gateway] = BEGIN finger: Gateway ¬ NIL; FOR new ¬ first, new.next UNTIL new = NIL DO IF where = new.where THEN BEGIN new.text.length ¬ 0; RETURN; END; IF LessPupAddress[new.where, where] THEN finger ¬ new; ENDLOOP; new ¬ z.NEW[GatewayObject]; new­ ¬ [next: NIL, where: where, text: z.NEW[StringBody[100]] ]; SELECT TRUE FROM first = NIL => first ¬ new; -- first finger = NIL => BEGIN new.next ¬ first; first ¬ new; END; -- insert at front of list ENDCASE => BEGIN new.next ¬ finger.next; finger.next ¬ new; END; -- middle or end END; LessPupAddress: PROCEDURE [a, b: PupAddress] RETURNS [BOOLEAN] = BEGIN IF a.net < b.net THEN RETURN[TRUE]; IF a.net > b.net THEN RETURN[FALSE]; IF a.host < b.host THEN RETURN[TRUE]; IF a.host > b.host THEN RETURN[FALSE]; IF a.socket.a < b.socket.a THEN RETURN[TRUE]; IF a.socket.a > b.socket.a THEN RETURN[FALSE]; IF a.socket.b < b.socket.b THEN RETURN[TRUE]; IF a.socket.b > b.socket.b THEN RETURN[FALSE]; RETURN[FALSE]; END; DeleteList: PROCEDURE = BEGIN gate: Gateway ¬ first; UNTIL gate = NIL DO next: Gateway ¬ gate.next; z.FREE[@gate.text]; z.FREE[@gate]; gate ¬ next; ENDLOOP; first ¬ NIL; END; PrintGatewayList: PROCEDURE = BEGIN gate: Gateway ¬ first; Put.CR[log]; Put.Line[log, " Name and Address Text"L]; FOR gate: Gateway ¬ first, gate.next UNTIL gate = NIL DO where: PupAddress ¬ [[gate.where.net], [gate.where.host], [0, 0]]; temp: STRING = [50]; PupDefs.AppendHostName[temp, where]; String.AppendString[temp, " = "L]; AppendPupAddress[temp, where]; String.AppendString[temp, " "L]; Put.Text[log, temp]; FOR i: CARDINAL IN [temp.length..35) DO Put.Char[log, ' ]; ENDLOOP; Put.Text[log, gate.text]; Put.CR[log]; ENDLOOP; END; nextSequenceNumber: CARDINAL ¬ 123; GetNextSequenceNumber: PROCEDURE RETURNS [CARDINAL] = BEGIN RETURN[nextSequenceNumber ¬ nextSequenceNumber + 1]; END; -- IO things 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; WriteLongDecimal: PROCEDURE [n: LONG CARDINAL] = BEGIN Put.LongDecimal[log, n]; END; WriteDecimal: PROCEDURE [n: CARDINAL] = INLINE BEGIN WriteNumber[n, 10, 0]; END; WriteOctal: PROCEDURE [n: CARDINAL] = INLINE BEGIN WriteNumber[n, 8, 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; WriteString[temp]; END; D8: PROCEDURE [n: CARDINAL] = BEGIN WriteNumber[n, 10, 8]; END; O3: PROCEDURE [n: CARDINAL] = BEGIN WriteNumber[n, 8, 3]; END; O6: PROCEDURE [n: CARDINAL] = BEGIN WriteNumber[n, 8, 3]; END; O9: PROCEDURE [n: CARDINAL] = BEGIN WriteNumber[n, 8, 9]; 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; indicatorBox: Window.Box = [[25, 10], [16, 16]]; DisplayBoxes: ToolWindow.DisplayProcType = BEGIN pattern: ARRAY [0..1] OF ARRAY [0..8) OF WORD; left: WORD = 177400B; right: WORD = 000377B; SELECT indicator FROM left => pattern ¬ [ALL[left], ALL[right]]; right => pattern ¬ [ALL[right], ALL[left]]; off => pattern ¬ [ALL[0], ALL[0]]; ENDCASE; Display.Bitmap[window, indicatorBox, [@pattern, 0, 0], 16, Display.replaceFlags] END; SetupBoxes: PROCEDURE = BEGIN indicator ¬ left; DisplayBoxes[boxes]; END; FlipBoxes: PROCEDURE = BEGIN SELECT indicator FROM left => indicator ¬ right; off, right => indicator ¬ left; ENDCASE; Display.Invert[boxes, indicatorBox]; END; SetDownBoxes: PROCEDURE = BEGIN indicator ¬ off; Display.White[boxes, indicatorBox]; END; MakeBoxesSW: PROCEDURE [window: Window.Handle] = BEGIN box: Window.Box ¬ ToolWindow.nullBox; box.dims.h ¬ 36; boxes ¬ ToolWindow.CreateSubwindow[parent: window, display: DisplayBoxes, box: box]; Tool.AddThisSW[window: window, sw: boxes, swType: vanilla]; END; MakeSWs: Tool.MakeSWsProc = BEGIN logFileName: STRING = [40]; msg ¬ Tool.MakeMsgSW[window: window, lines: 5]; form ¬ Tool.MakeFormSW[window: window, formProc: MakeForm]; MakeBoxesSW[window]; Tool.UnusedLogName[logFileName, "FindGateways.log$"L]; log ¬ Tool.MakeFileSW[window: window, name: logFileName]; END; MakeForm: FormSW.ClientItemsProcType = BEGIN nParams: CARDINAL = 5; items ¬ FormSW.AllocateItemDescriptor[nParams]; items[0] ¬ FormSW.CommandItem[ tag: "Stop"L, proc: Stop, place: FormSW.newLine]; items[1] ¬ FormSW.CommandItem[ tag: "ScanCircle"L, proc: ScanCircle, place: FormSW.newLine]; items[2] ¬ FormSW.NumberItem[ tag: "MaxHops"L, value: @maxHops, default: defaultMaxHops]; items[3] ¬ FormSW.CommandItem[ tag: "ScanTarget"L, proc: ScanTarget, place: FormSW.newLine]; items[4] ¬ FormSW.StringItem[tag: "Target"L, string: @target, inHeap: TRUE]; RETURN[items, TRUE]; END; ClientTransition: ToolWindow.TransitionProcType = BEGIN SELECT TRUE FROM old = inactive => BEGIN target ¬ Heap.systemZone.NEW[StringBody[20]]; String.AppendString[target, "ME"L]; PupDefs.PupPackageMake[]; END; new = inactive => BEGIN IF running THEN Off[]; PupDefs.PupPackageDestroy[]; Heap.systemZone.FREE[@target]; END; ENDCASE; END; Init: PROCEDURE = BEGIN herald: STRING = [100]; String.AppendString[herald, "FindGateways of "L]; Time.Append[herald, Time.Unpack[Runtime.GetBcdTime[]]]; [] ¬ Tool.Create[ name: herald, makeSWsProc: MakeSWs, clientTransition: ClientTransition]; END; Init[]; END.