-- File: ArpaHostTableImpl.mesa - last edit: -- AOF 12-Mar-87 17:49:14 -- JAV 25-Feb-87 14:58:51 -- Copyright (C) 1986, 1987 by Xerox Corporation. All rights reserved. DIRECTORY ArpaAddressCache USING [AddEntry], ArpaAddressTranslation USING [StringToInternetAddress], ArpaHostTable USING [], ArpaRouter USING [GetAddress, InternetAddress, unknownInternetAddress], ArpaTypes USING [InternetAddress], Environment USING [Byte], ESCAlpha USING [aDAND, aDXOR], Heap USING [systemZone], Inline USING [DBITAND], Mopcodes USING [zESC, zIOR], Stream USING [Byte, EndOfStream, GetByte, Handle], String USING [ AppendChar, AppendSubString, CopyToNewString, Equivalent, FreeString, MakeString, StringBoundsFault, SubStringDescriptor]; ArpaHostTableImpl: PROGRAM IMPORTS ArpaAddressCache, ArpaAddressTranslation, ArpaRouter, Heap, Inline, Stream, String EXPORTS ArpaHostTable, ArpaRouter = BEGIN zone: UNCOUNTED ZONE ← Heap.systemZone; Tab: Environment.Byte ← 11B; CR: Environment.Byte ← 15B; SP: Environment.Byte ← 40B; comma: Environment.Byte ← 54B; colon: Environment.Byte ← 72B; semiColon: Environment.Byte ← 73B; InternetAddress: PUBLIC TYPE = ArpaTypes.InternetAddress; SkipLine: PROCEDURE [stream: Stream.Handle] = BEGIN char: Environment.Byte ← 0; WHILE char # CR DO char ← Stream.GetByte[stream ! Stream.EndOfStream => EXIT] ENDLOOP END; ParseHostsFile: PUBLIC PROCEDURE [fileStream: Stream.Handle] RETURNS [success: BOOLEAN ← TRUE] = BEGIN tokens: ARRAY [0..6) OF LONG STRING; EOF, charInHole: BOOLEAN ← FALSE; keyword: LONG STRING ← String.MakeString[zone, 256]; backChar: Environment.Byte ← 0; netMask: ArpaRouter.InternetAddress ← ArpaRouter.unknownInternetAddress; GetKeyword: PROCEDURE [string: LONG STRING] = BEGIN char: Environment.Byte ← 0; WHILE ~EOF DO IF charInHole THEN {char ← backChar; charInHole ← FALSE} ELSE char ← Stream.GetByte[fileStream ! Stream.EndOfStream => { EOF ← TRUE; CONTINUE}]; IF char = semiColon THEN {SkipLine[fileStream]; LOOP}; IF char = colon THEN EXIT; IF char = SP OR char = Tab THEN { WHILE char # colon DO IF EOF THEN EXIT; char ← Stream.GetByte[fileStream ! Stream.EndOfStream => {EOF ← TRUE; CONTINUE}]; ENDLOOP; EXIT}; IF ~EOF THEN String.AppendChar[string, LOOPHOLE[char] ! String.StringBoundsFault => { string ← String.CopyToNewString[s, zone, 30]; String.FreeString[zone, s]; RESUME[string]}]; ENDLOOP; END; GetTokens: PROCEDURE [numberOfTokens: CARDINAL] RETURNS [EOF: BOOLEAN ← FALSE] = BEGIN i: CARDINAL ← 0; char: Environment.Byte ← 0; EOL, CRSeen: BOOLEAN ← FALSE; WHILE ~EOL DO char ← Stream.GetByte[fileStream ! Stream.EndOfStream => { EOL ← EOF ← TRUE; CONTINUE}]; SELECT char FROM SP => IF EOL THEN CRSeen ← EOL ← FALSE; Tab => NULL; colon => {i ← i + 1; IF i > numberOfTokens THEN RETURN}; semiColon => {SkipLine[fileStream]; EOL ← TRUE; LOOP}; CR => CRSeen ← TRUE; ENDCASE => IF CRSeen THEN {backChar ← char; charInHole ← EOL ← TRUE} ELSE String.AppendChar[tokens[i], LOOPHOLE[char] ! String.StringBoundsFault => { tokens[i] ← String.CopyToNewString[s, zone, 30]; String.FreeString[zone, s]; RESUME[tokens[i]]}]; ENDLOOP; END; BuildNetMask: PROCEDURE [addr: ArpaRouter.InternetAddress] RETURNS [netMask: ArpaRouter.InternetAddress] = BEGIN InternetAddress: TYPE = MACHINE DEPENDENT RECORD[a, b: WORD]; classAMask: InternetAddress ← [100000B, 0B]; classBMask: InternetAddress ← [140000B, 0B]; classCMask: InternetAddress ← [160000B, 0B]; classA: InternetAddress ← [0B, 0B]; classB: InternetAddress ← [100000B, 0B]; classC: InternetAddress ← [140000B, 0B]; Mask: InternetAddress ← [0B, 0B]; SELECT TRUE FROM (Inline.DBITAND[LOOPHOLE[addr], LOOPHOLE[classAMask]] = LOOPHOLE[classA, LONG UNSPECIFIED]) => Mask ← [177400B, 0B]; (Inline.DBITAND[LOOPHOLE[addr], LOOPHOLE[classBMask]] = LOOPHOLE[classB, LONG UNSPECIFIED]) => Mask ← [177777B, 0B]; (Inline.DBITAND[LOOPHOLE[addr], LOOPHOLE[classCMask]] = LOOPHOLE[classC, LONG UNSPECIFIED]) => Mask ← [177777B, 177400B]; ENDCASE => --unimplemented extended addressing or unrecognizable. Mask ← [0B, 0B]; netMask ← LOOPHOLE[Mask]; END; AddrMismatch: PROCEDURE [mask, test, target: ArpaRouter.InternetAddress] RETURNS[BOOLEAN] = MACHINE CODE {Mopcodes.zESC, ESCAlpha.aDXOR; Mopcodes.zESC, ESCAlpha.aDAND; Mopcodes.zIOR}; LocalNet: PROCEDURE [addr: ArpaRouter.InternetAddress] RETURNS [true: BOOLEAN] = {RETURN[~AddrMismatch[netMask, ArpaRouter.GetAddress[], addr]]}; GetAddr: PROCEDURE [addrStr: LONG STRING] RETURNS [ addr: ArpaRouter.InternetAddress ← ArpaRouter.unknownInternetAddress] = BEGIN first: BOOLEAN ← TRUE; string: LONG STRING ← [256]; commaPosition, prevComma: CARDINAL ← 0; tempSubString: String.SubStringDescriptor; firstAddr: ArpaRouter.InternetAddress ← addr; FOR i: CARDINAL IN [0..addrStr.length) DO IF addrStr.text[i].ORD = comma OR (i = addrStr.length - 1) THEN BEGIN tempSubString ← [addrStr, prevComma, i - prevComma + (IF i = addrStr.length - 1 THEN 1 ELSE 0)]; String.AppendSubString[string, @tempSubString ! String.StringBoundsFault => { prevComma ← i + 1; string.length ← 0; LOOP}]; prevComma ← i + 1; addr ← ArpaAddressTranslation.StringToInternetAddress[string]; string.length ← 0; IF first THEN {first ← FALSE; firstAddr ← addr}; IF LocalNet[addr] THEN RETURN[addr]; END; ENDLOOP; IF firstAddr # ArpaRouter.unknownInternetAddress THEN RETURN[firstAddr]; END; AddEntry: PROCEDURE = BEGIN commaPosition, prevComma: CARDINAL ← 0; string: LONG STRING ← [256]; tempSubString: String.SubStringDescriptor; addr: ArpaRouter.InternetAddress ← ArpaRouter.unknownInternetAddress; netMask ← BuildNetMask[ArpaRouter.GetAddress[]]; addr ← GetAddr[tokens[0]]; FOR i: CARDINAL IN [0..tokens[1].length) DO IF tokens[1].text[i].ORD = comma OR (i = tokens[1].length - 1) THEN BEGIN tempSubString ← [tokens[1], prevComma, i - prevComma + (IF i = tokens[1].length - 1 THEN 1 ELSE 0)]; String.AppendSubString[string, @tempSubString ! String.StringBoundsFault => { prevComma ← i + 1; string.length ← 0; LOOP}]; prevComma ← i + 1; ArpaAddressCache.AddEntry[string, addr]; string.length ← 0; END; ENDLOOP; END; FOR index: CARDINAL IN [0..6) DO tokens[index] ← String.MakeString[zone, 50]; ENDLOOP; WHILE ~EOF DO GetKeyword[keyword]; SELECT TRUE FROM String.Equivalent[keyword, "NET"L] => { EOF ← GetTokens[2]; SkipLine[fileStream]}; String.Equivalent[keyword, "GATEWAY"L] => { EOF ← GetTokens[5]; SkipLine[fileStream]}; String.Equivalent[keyword, "HOST"L] => { EOF ← GetTokens[5]; AddEntry[]}; <<String.Equivalent[keyword, "DOMAIN"L] => SkipLine[fileStream];>> ENDCASE => SkipLine[fileStream]; keyword.length ← 0; FOR index: CARDINAL IN [0..6) DO tokens[index].length ← 0; ENDLOOP; ENDLOOP; FOR index: CARDINAL IN [0..6) DO String.FreeString[zone, tokens[index]]; ENDLOOP; END; END.