-- Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved. -- TrapBadPups.mesa, HGM, 6-Aug-85 21:04:11 DIRECTORY Ascii USING [CR, SP], CmFile USING [Handle, TableError], Heap USING [Create], Put USING [Text], String USING [AppendChar, AppendLongDecimal, AppendNumber, AppendString], StringLookUp USING [noMatch, TableDesc], System USING [ AdjustGreenwichMeanTime, GetGreenwichMeanTime, gmtEpoch, GreenwichMeanTime], Time USING [AppendCurrent], Token USING [Decimal, Filtered, FreeTokenString, Item, Line], Indirect USING [Close, NextValue, OpenSection], Mailer USING [Level, SendGVMail], Buffer USING [PupBuffer], Driver USING [Network], DriverTypes USING [Encapsulation], PupDefs USING [GetPupContentsBytes], ForwarderDefs USING [], PupRouterDefs USING [NetworkContext, RejectPupWithBadChecksum, SetPupChecksum]; TrapBadPups: MONITOR IMPORTS CmFile, Heap, Put, String, System, Time, Token, Indirect, Mailer, PupDefs, PupRouterDefs EXPORTS Buffer, ForwarderDefs SHARES Buffer = BEGIN -- EXPORTed TYPEs Network: PUBLIC TYPE = Driver.Network; to, cc: LONG STRING ← NIL; troubles: LONG STRING ← NIL; -- Also used as from z: UNCOUNTED ZONE = Heap.Create[1]; badSequenceNumber: LONG CARDINAL ← 0; recent: CARDINAL ← 0; clumpSize: CARDINAL ← 3; secondsPerPacket: CARDINAL ← 3600; -- one/hour lastTime: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[]; CollectInfo: PROCEDURE = BEGIN cmFile: CmFile.Handle; Option: TYPE = MACHINE DEPENDENT{ troubles(0), to, cc, clumpSize, secondsPerPacket, noMatch(StringLookUp.noMatch)}; DefinedOption: TYPE = Option [troubles..secondsPerPacket]; CheckType: PROCEDURE [h: CmFile.Handle, table: StringLookUp.TableDesc] RETURNS [index: CARDINAL] = Indirect.NextValue; MyNextValue: PROCEDURE [ h: CmFile.Handle, table: LONG DESCRIPTOR FOR ARRAY DefinedOption OF LONG STRING] RETURNS [index: Option] = LOOPHOLE[CheckType]; optionTable: ARRAY DefinedOption OF LONG STRING ← [ troubles: "Troubles"L, to: "to"L, cc: "cc"L, clumpSize: "Clump Size"L, secondsPerPacket: "Seconds Per Packet"L]; cmFile ← Indirect.OpenSection["TrapBadPups"L]; IF cmFile = NIL THEN BEGIN Message["Can't find [TrapBadPups] section in parameter file."L]; RETURN; END; DO option: Option; option ← MyNextValue[cmFile, DESCRIPTOR[optionTable] ! CmFile.TableError => BEGIN IF name[0] # '; THEN Message["Unrecognized parameter: ", name]; RETRY; END]; SELECT option FROM noMatch => EXIT; troubles => BEGIN temp: LONG STRING; z.FREE[@troubles]; temp ← Token.Item[cmFile]; troubles ← z.NEW[StringBody[temp.length]]; String.AppendString[troubles, temp]; [] ← Token.FreeTokenString[temp]; CheckForRegistry[troubles]; END; to => BEGIN temp: LONG STRING ← Token.Filtered[cmFile, NIL, Token.Line, whiteSpace, FALSE]; z.FREE[@to]; to ← z.NEW[StringBody[temp.length]]; String.AppendString[to, temp]; [] ← Token.FreeTokenString[temp]; CheckForRegistry[to]; END; cc => BEGIN temp: LONG STRING ← Token.Filtered[cmFile, NIL, Token.Line, whiteSpace, FALSE]; z.FREE[@cc]; cc ← z.NEW[StringBody[temp.length]]; String.AppendString[cc, temp]; [] ← Token.FreeTokenString[temp]; CheckForRegistry[cc]; END; clumpSize => BEGIN clumpSize ← Token.Decimal[cmFile]; END; secondsPerPacket => BEGIN clumpSize ← Token.Decimal[cmFile]; END; ENDCASE => ERROR; ENDLOOP; Indirect.Close[cmFile]; IF troubles = NIL THEN Message["Please specify somebody in case of TROUBLES"L]; IF to = NIL THEN Message["Please specify somebody to send the message to"L]; RETURN; END; CheckForRegistry: PROCEDURE [s: LONG STRING] = BEGIN dot: BOOLEAN ← FALSE; FOR i: CARDINAL IN [0..s.length) DO SELECT s[i] FROM '. => dot ← TRUE; ', => BEGIN IF ~dot THEN BEGIN Message["Registry expected in arg: "L, s]; RETURN; END; dot ← FALSE; END; ENDCASE => NULL; ENDLOOP; IF ~dot THEN BEGIN Message["Registry expected in arg: "L, s]; RETURN; END; END; Message: PROCEDURE [one, two, three: LONG STRING ← NIL] = BEGIN text: STRING = [100]; Time.AppendCurrent[text]; String.AppendString[text, " TrapBadPups: "L]; String.AppendString[text, one]; IF two # NIL THEN String.AppendString[text, two]; IF three # NIL THEN String.AppendString[text, three]; LogString[text]; END; Filter: PROCEDURE RETURNS [ok: BOOLEAN ← FALSE] = BEGIN -- Limit to avg of 1/hour, but allow clumps of 3. IF lastTime # System.gmtEpoch THEN BEGIN seconds: LONG CARDINAL ← System.GetGreenwichMeanTime[] - lastTime; WHILE seconds > secondsPerPacket DO IF recent = 0 THEN BEGIN lastTime ← System.GetGreenwichMeanTime[]; EXIT; END; recent ← recent - 1; lastTime ← System.AdjustGreenwichMeanTime[lastTime, secondsPerPacket]; ENDLOOP; END; IF recent < clumpSize THEN ok ← TRUE; IF ok THEN recent ← recent + 1; END; PrintBadPup: PUBLIC PROCEDURE [b: Buffer.PupBuffer] = BEGIN IF lastTime = System.gmtEpoch THEN lastTime ← System.GetGreenwichMeanTime[]; IF b = NIL THEN RETURN; badSequenceNumber ← badSequenceNumber + 1; IF Filter[] THEN MailBadPup[b]; PupRouterDefs.RejectPupWithBadChecksum[b]; END; maxWords: CARDINAL = 300; maxBytes: CARDINAL = 500 + maxWords*9; MailBadPup: PUBLIC PROCEDURE [b: Buffer.PupBuffer] = BEGIN body: STRING = [maxBytes]; size: CARDINAL ← (b.pup.pupLength - 1)/2; checksumLoc: LONG POINTER ← @b.pup.pupLength + size; words: CARDINAL ← (PupDefs.GetPupContentsBytes[b] + 1)/2; p: LONG POINTER; context: PupRouterDefs.NetworkContext = b.context; hack: BOOLEAN ← b.pup.pupType = echoMe OR b.pup.pupType = iAmEcho; Info: PROCEDURE [s: LONG STRING, level: Mailer.Level] = BEGIN -- Krock because Put.Line is not Atomic copy: LONG STRING ← z.NEW[StringBody[s.length + 2]]; String.AppendString[copy, s]; LogString[copy]; z.FREE[@copy]; END; O7: PROCEDURE [n: WORD] = BEGIN temp: STRING = [10]; String.AppendNumber[temp, n, 8]; THROUGH [temp.length..7) DO String.AppendChar[body, Ascii.SP]; ENDLOOP; String.AppendNumber[body, n, 8]; END; Time.AppendCurrent[body]; String.AppendString[body, " ***** Bad software checksum on Pup from net "L]; String.AppendNumber[body, context.pupNetNumber, 8]; String.AppendChar[body, Ascii.CR]; String.AppendString[body, "Bad pup number "L]; String.AppendLongDecimal[body, badSequenceNumber]; String.AppendString[body, " has a checksum of "L]; String.AppendNumber[body, checksumLoc↑, 8]; PupRouterDefs.SetPupChecksum[b]; -- Fix it up String.AppendString[body, ", but it should be "L]; String.AppendNumber[body, checksumLoc↑, 8]; String.AppendChar[body, Ascii.CR]; String.AppendString[body, "Driver length: "L]; String.AppendNumber[body, b.driver.length, 10]; String.AppendChar[body, Ascii.CR]; String.AppendString[body, "Encap: "L]; p ← @b.encapsulation; FOR i: CARDINAL IN [0..SIZE[DriverTypes.Encapsulation]) DO O7[(p + i)↑]; IF hack THEN String.AppendChar[body, ' ]; ENDLOOP; String.AppendChar[body, Ascii.CR]; String.AppendString[body, "Header:"L]; p ← @b.bufferBody; FOR i: CARDINAL IN [0..11 - 1) DO O7[(p + i)↑]; IF hack THEN String.AppendChar[body, ' ]; ENDLOOP; FOR i: CARDINAL ← 0, i + 1 UNTIL i >= MIN[words, maxWords] DO IF (i MOD 10) = 0 THEN BEGIN String.AppendChar[body, Ascii.CR]; String.AppendString[body, IF i = 0 THEN "Body: "L ELSE " "L]; END; O7[b.pup.pupWords[i]]; IF hack THEN BEGIN IF b.pup.pupBytes[2*i] # (2*i MOD 400B) OR b.pup.pupBytes[2*i + 1] # ((2*i + 1) MOD 400B) THEN String.AppendChar[body, '←] ELSE String.AppendChar[body, ' ]; END; ENDLOOP; String.AppendChar[body, Ascii.CR]; Put.Text[NIL, body]; IF troubles # NIL AND to # NIL THEN BEGIN [] ← Mailer.SendGVMail[ "Bad Pup Checksum info"L, to, cc, body, troubles, Info]; END; END; LogString: PROCEDURE [s: LONG STRING] = BEGIN String.AppendChar[s, '.]; String.AppendChar[s, Ascii.CR]; Put.Text[NIL, s]; END; -- initialization CollectInfo[]; END.