-- 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.