NetworkNameEtcHostsImpl.mesa
Copyright Ó 1991, 1992 by Xerox Corporation. All rights reserved.
Demers, November 6, 1990 3:07 pm PST
Chauser, October 16, 1990 9:03 am PDT
Willie-s, January 3, 1991 7:36 pm PST
Swen Johnson, April 13, 1992 2:17 pm PDT
DIRECTORY
Arpa,
Convert,
IO,
NetworkName,
PFS,
Rope,
SymTab
;
NetworkNameEtcHostsImpl: CEDAR MONITOR
This is a backup implementation for $ARPA name lookup. It should be installed after NetworkNameSunYPImpl so that if YP isn't available and the host has a complete /etc/hosts file progress can still be made.
IMPORTS Convert, IO, NetworkName, PFS, Rope, SymTab
~ {
OPEN NN: NetworkName;
Types
ROPE: TYPE ~ Rope.ROPE;
Parameters
myFamily: ATOM ¬ $ARPA;
myFlavor: ATOM ¬ $EtcHosts;
Procs
SplitNameOrAddress: PROC [name: ROPE] RETURNS [hostPart: ROPE ¬ NIL, portPart: ROPE ¬ NIL] ~ {
portPos, hostLen: INT;
pos: INT ¬ 0;
IF Rope.IsEmpty[name] THEN RETURN;
SELECT TRUE FROM
(pos ¬ Rope.FindBackward[name, ":"]) >= 0 => {
portPos ¬ pos+1;
hostLen ¬ pos;
};
(pos ¬ Rope.FindBackward[name, "]"]) >= 0 => {
portPos ¬ pos+1;
hostLen ¬ pos+1;
};
ENDCASE => {
portPos ¬ Rope.Length[name];
hostLen ¬ portPos;
};
portPart ¬ Rope.Substr[name, portPos];
hostPart ¬ Rope.Substr[name, 0, hostLen];
IF (hostLen >= 2) AND (Rope.Fetch[hostPart, 0] = '[) AND (Rope.Fetch[hostPart, hostLen-1] = ']) THEN hostPart ¬ Rope.Substr[hostPart, 1, hostLen-2];
};
ConvertHostLiteral: PROC [literal: ROPE] RETURNS [ok: BOOL ¬ FALSE, host: ROPE ¬ NIL] ~ {
ENABLE Convert.Error => CONTINUE;
len: INT;
host ¬ Convert.RopeFromArpaAddress[
IF Rope.IsEmpty[literal]
THEN Arpa.nullAddress
ELSE Convert.ArpaAddressFromRope[literal]
];
len ¬ Rope.Length[host];
IF (len >= 2) AND (Rope.Fetch[host, 0] = '[)
THEN host ¬ Rope.Substr[host, 1, len-2];
ok ¬ TRUE;
};
LookupHostName: ENTRY PROC [name: ROPE] RETURNS [addr: ROPE ¬ NIL] ~ {
errorCodes: LIST OF ATOM ¬ NIL;
found: BOOL;
val: REF;
[found, val] ¬ SymTab.Fetch[hostsByName, name];
IF found THEN RETURN[NARROW[val]]
ELSE RETURN WITH ERROR NN.Error[ LIST[$notFound], "EtcHosts lookup error" ];
};
ConvertPortLiteral: PROC [portLiteral: ROPE] RETURNS [ok: BOOL ¬ FALSE, port: ROPE ¬ NIL] ~ {
ENABLE Convert.Error => CONTINUE;
n: CARD;
n ¬ IF Rope.IsEmpty[portLiteral] THEN 0 ELSE Convert.CardFromRope[portLiteral];
port ¬ Convert.RopeFromCard[n];
ok ¬ TRUE;
};
AddressFromName: NN.AddressFromNameProc -- [r, name, portHint, components] RETURNS [addr] -- ~ {
host, port, hostName, portName: ROPE ¬ NIL;
ok: BOOL;
addr ¬ NIL;
[hostName, portName] ¬ SplitNameOrAddress[name];
SELECT components FROM
host, hostAndPort => {
[ok, host] ¬ ConvertHostLiteral[hostName];
IF NOT ok THEN host ¬ LookupHostName[hostName]; -- ! NN.Error
};
ENDCASE;
SELECT components FROM
port, hostAndPort => {
IF Rope.IsEmpty[portName] THEN portName ¬ portHint;
[ok, port] ¬ ConvertPortLiteral[portName];
IF NOT ok THEN NN.Error[ LIST[$notFound], "port name not found"]; -- no symbolic port names from this package.
};
ENDCASE;
addr ¬ host;
IF NOT Rope.IsEmpty[portName] THEN addr ¬ Rope.Cat[addr, ":", port];
};
LookupHost: ENTRY PROC [host: ROPE] RETURNS [hostName: ROPE ¬ NIL] ~ {
errorCodes: LIST OF ATOM ¬ NIL;
found: BOOL;
val: REF;
[found, val] ¬ SymTab.Fetch[hostsByAddr, host];
IF found THEN RETURN[NARROW[val]]
ELSE RETURN WITH ERROR NN.Error[ LIST[$notFound], "EtcHosts lookup error" ];
};
NameFromAddress: NN.NameFromAddressProc -- [r, addr, components] RETURNS [name] -- ~ {
host, port, hostName, portName: ROPE ¬ NIL;
ok: BOOL;
name ¬ NIL;
[host, port] ¬ SplitNameOrAddress[addr];
SELECT components FROM
host, hostAndPort => {
IF NOT Rope.IsEmpty[host] THEN {
[ok, host] ¬ ConvertHostLiteral[host];
IF NOT ok THEN ERROR NN.Error[ LIST[$syntax], "host address syntax"];
hostName ¬ LookupHost[host]; -- ! NN.Error
};
};
ENDCASE;
SELECT components FROM
port, hostAndPort => {
IF NOT Rope.IsEmpty[port] THEN {
[ok, port] ¬ ConvertPortLiteral[port];
IF NOT ok THEN ERROR NN.Error[ LIST[$syntax], "port number syntax"];
portName ¬ port; -- no symbolic port names from this package
};
};
ENDCASE;
SELECT components FROM
host => RETURN [hostName];
port => RETURN [portName];
hostAndPort => RETURN [Rope.Cat[hostName, ":", portName]];
ENDCASE => ERROR;
};
hostsByName: SymTab.Ref ¬ SymTab.Create[];
hostsByAddr: SymTab.Ref ¬ SymTab.Create[];
nLines: CARD ¬ 0;
GetNLines: PROC [] RETURNS [CARD] ~ {
RETURN[nLines];
};
fileName: PFS.PATH ~ PFS.PathFromRope["/etc/hosts"];
CacheFile: ENTRY PROC [] RETURNS [] ~ {
hosts: IO.STREAM ¬ PFS.StreamOpen[fileName, read ! IO.Error, PFS.Error => GOTO Out];
ReadOneLine: PROC [] RETURNS [BOOL ¬ TRUE] ~ {
WhiteSpace: IO.BreakProc ~ {
IF (char = '#) THEN
comment ¬ TRUE;
RETURN[SELECT TRUE FROM
comment, char IN [IO.NUL .. IO.SP] => sepr,
ENDCASE => other
];
};
comment: BOOL ¬ FALSE; -- WhiteSpace state variable
line: ROPE ¬ IO.GetLineRope[hosts ! IO.EndOfStream, PFS.Error => GOTO none];
addr: ROPE;
firstOne: BOOL ¬ TRUE;
s: IO.STREAM;
IF ( line.Length[] = 0 ) THEN RETURN;
s ¬ IO.RIS[line];
addr ¬ s.GetTokenRope[WhiteSpace ! IO.EndOfStream => GO TO some].token;
DO
name: ROPE ¬ s.GetTokenRope[WhiteSpace ! IO.EndOfStream => GO TO some].token;
[] ¬ hostsByName.Store[name, addr];
IF firstOne THEN [] ¬ hostsByAddr.Store[addr, name];
firstOne ¬ FALSE;
ENDLOOP;
EXITS
none => RETURN[FALSE];
some => RETURN[TRUE];
};
hostsByName.Erase[];
hostsByAddr.Erase[];
{
ENABLE IO.Error, PFS.Error => GOTO Close;
nLines ¬ 0;
WHILE ReadOneLine[] DO nLines ¬ nLines+1 ENDLOOP;
hosts.Close[];
EXITS
Close => {
IO.Close[hosts ! IO.Error, PFS.Error => CONTINUE];
hostsByName.Erase[];
hostsByAddr.Erase[];
};
};
EXITS
Out => NULL;
};
RegisterSelf: PROC ~ {
r: NN.Registration;
RegistrationCallback: NN.RegistrationCallbackProc -- [oldRegistration] RETURNS [action, newRegistration] -- ~ {
RETURN [insert, r];
};
r ¬ NEW[NN.RegistrationObject ¬ [
family~myFamily,
flavor~myFlavor,
addressFromName~AddressFromName,
nameFromAddress~NameFromAddress
]];
NN.Register[myFamily, RegistrationCallback];
};
CacheFile[];
RegisterSelf[];
}.
Swen Johnson, April 13, 1992 14:16:50 am PDT
CacheFile was only checking the begining of the line for a '# (comments in /etc/hosts can start anywhere on a line).
changes to: WhiteSpace (local of ReadOneLine, local of CacheFile): Assign comment BOOL TRUE whenever a '# is encountered; return sepr if comment is TRUE. ReadOneLine (local of CacheFile): Declare comment; simplified test of first line.