NetworkNameSunYPImpl.mesa
Copyright Ó 1991, 1992 by Xerox Corporation. All rights reserved.
Demers, November 6, 1990 3:06 pm PST
NOTE: There ought to be a generic bounded-size/timed-out/LRU cache mechanism this guy can use ...
Willie-s, November 7, 1990 12:13 pm PST
DIRECTORY
Arpa,
Convert,
NetworkName,
Rope,
SunYPAgent
;
NetworkNameSunYPImpl: CEDAR PROGRAM
IMPORTS Convert, NetworkName, Rope, SunYPAgent
~ {
OPEN NN: NetworkName;
Types
ROPE: TYPE ~ Rope.ROPE;
Parameters
hostsByName: ROPE ¬ "hosts.byname";
hostsByAddr: ROPE ¬ "hosts.byaddr";
servicesByName: ROPE ¬ "services.byname";
myFamily: ATOM ¬ $ARPA;
myFlavor: ATOM ¬ $SunYP;
Port Name Stuff
PortNameMapEntry: TYPE ~ RECORD [
portName: ROPE,
port: ROPE
];
portNameMapUDP: LIST OF PortNameMapEntry ¬ NIL;
portNameMapTCP: LIST OF PortNameMapEntry ¬ NIL;
InitPortNameMaps: PROC ~ {
h: SunYPAgent.Handle ¬ NIL;
errorCode: ATOM ¬ NIL;
newMapUDP: LIST OF PortNameMapEntry ¬ NIL;
newMapTCP: LIST OF PortNameMapEntry ¬ NIL;
Insert: PROC [pn: ROPE, p: ROPE, proto: ROPE] ~ {
SELECT TRUE FROM
Rope.Equal[proto, "TCP", FALSE] =>
newMapTCP ¬ CONS[ PortNameMapEntry[pn, p], newMapTCP];
Rope.Equal[proto, "UDP", FALSE] =>
newMapUDP ¬ CONS[ PortNameMapEntry[pn, p], newMapUDP];
ENDCASE => NULL;
};
{
ENABLE SunYPAgent.Error => { errorCode ¬ code; CONTINUE };
key: ROPE;
val, txt: REF TEXT;
r, port, proto: ROPE;
pos: INT;
seq: SunYPAgent.TextSeq;
ok: BOOL;
h ¬ SunYPAgent.ObtainHandle[];
key ¬ NIL;
DO
{
ENABLE SunYPAgent.Error => IF code = $noMoreEntries THEN EXIT;
IF key = NIL
THEN [key, val] ¬ SunYPAgent.First[h, servicesByName]
ELSE [key, val] ¬ SunYPAgent.Next[h, servicesByName, key];
};
seq ¬ SunYPAgent.Tokenize[val];
IF seq.length < 2 THEN LOOP;
txt ¬ seq.refText[0];
IF (txt.length > 0) AND (txt[0] = '#) THEN LOOP;
txt ¬ seq.refText[1];
IF (txt.length > 0) AND (txt[0] = '#) THEN LOOP;
r ¬ Rope.FromRefText[txt];
pos ¬ Rope.Find[r, "/"];
IF pos < 0 THEN LOOP;
proto ¬ Rope.Substr[r, pos+1];
port ¬ Rope.Substr[r, 0, pos];
[ok, port] ¬ ConvertPortLiteral[port];
IF NOT ok THEN LOOP;
Insert[Rope.FromRefText[seq.refText[0]], port, proto];
FOR i: INT IN [2 .. seq.length) DO
txt ¬ seq.refText[i];
IF (txt.length > 0) AND (txt[0] = '#) THEN EXIT;
Insert[Rope.FromRefText[txt], port, proto];
ENDLOOP;
ENDLOOP;
};
IF h # NIL THEN SunYPAgent.ReleaseHandle[h ! SunYPAgent.Error => CONTINUE];
IF errorCode # NIL THEN ERROR NN.Error[ LIST[$serviceError, errorCode], "SunYPAgent Error" ];
portNameMapTCP ¬ newMapTCP;
portNameMapUDP ¬ newMapUDP;
};
LookupPortName: PROC [portName: ROPE] RETURNS [port: ROPE ¬ NIL] ~ {
IF (portNameMapUDP = NIL) AND (portNameMapTCP = NIL) THEN InitPortNameMaps[];
FOR p: LIST OF PortNameMapEntry ¬ portNameMapTCP, p.rest WHILE p # NIL DO
IF Rope.Equal[portName, p.first.portName, FALSE] THEN RETURN [p.first.port];
ENDLOOP;
FOR p: LIST OF PortNameMapEntry ¬ portNameMapUDP, p.rest WHILE p # NIL DO
IF Rope.Equal[portName, p.first.portName, FALSE] THEN RETURN [p.first.port];
ENDLOOP;
ERROR NN.Error[ LIST[$notFound], "port name not found"];
};
LookupPort: PROC [port: ROPE] RETURNS [portName: ROPE] ~ {
ok: BOOL;
[ok, port] ¬ ConvertPortLiteral[port];
IF ok THEN {
IF (portNameMapUDP = NIL) AND (portNameMapTCP = NIL) THEN InitPortNameMaps[];
FOR p: LIST OF PortNameMapEntry ¬ portNameMapTCP, p.rest WHILE p # NIL DO
IF Rope.Equal[port, p.first.port, FALSE] THEN RETURN [p.first.portName];
ENDLOOP;
FOR p: LIST OF PortNameMapEntry ¬ portNameMapUDP, p.rest WHILE p # NIL DO
IF Rope.Equal[port, p.first.port, FALSE] THEN RETURN [p.first.portName];
ENDLOOP;
};
ERROR NN.Error[ LIST[$notFound], "port name not found"];
};
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: PROC [name: ROPE] RETURNS [addr: ROPE ¬ NIL] ~ {
h: SunYPAgent.Handle ¬ NIL;
errorCodes: LIST OF ATOM ¬ NIL;
matchedVal: REF TEXT ¬ NIL;
seq: SunYPAgent.TextSeq ¬ NIL;
{
ENABLE SunYPAgent.Error => { errorCodes ¬ LIST[$serviceError, code]; GOTO Out };
h ¬ SunYPAgent.ObtainHandle[];
matchedVal ¬ SunYPAgent.Match[h, hostsByName, name
! SunYPAgent.Error => IF code = $keyNotFound THEN { errorCodes ¬ LIST[$notFound]; GOTO Out }];
seq ¬ SunYPAgent.Tokenize[matchedVal];
IF (seq # NIL) AND (seq.length > 0) THEN {
addr ¬ Rope.FromRefText[seq.refText[0]];
};
EXITS
Out => NULL;
};
IF h # NIL THEN SunYPAgent.ReleaseHandle[h ! SunYPAgent.Error => CONTINUE];
IF errorCodes # NIL THEN ERROR NN.Error[ errorCodes, "SunYP 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 port ¬ LookupPortName[portName]; -- ! NN.Error
};
ENDCASE;
addr ¬ host;
IF NOT Rope.IsEmpty[portName] THEN addr ¬ Rope.Cat[addr, ":", port];
};
LookupHost: PROC [host: ROPE] RETURNS [hostName: ROPE ¬ NIL] ~ {
h: SunYPAgent.Handle ¬ NIL;
errorCodes: LIST OF ATOM ¬ NIL;
matchedVal: REF TEXT ¬ NIL;
seq: SunYPAgent.TextSeq ¬ NIL;
ok: BOOL;
{
ENABLE SunYPAgent.Error => { errorCodes ¬ LIST[$serviceError, code]; GOTO Out };
h ¬ SunYPAgent.ObtainHandle[];
[ok, host] ¬ ConvertHostLiteral[host];
IF NOT ok THEN { errorCodes ¬ LIST[$syntax]; GOTO Out };
matchedVal ¬ SunYPAgent.Match[h, hostsByAddr, host
! SunYPAgent.Error => IF code = $keyNotFound THEN { errorCodes ¬ LIST[$notFound]; GOTO Out }];
seq ¬ SunYPAgent.Tokenize[matchedVal];
IF (seq # NIL) AND (seq.length > 1) THEN {
hostName ¬ Rope.FromRefText[seq.refText[1]];
};
EXITS
Out => NULL;
};
IF h # NIL THEN SunYPAgent.ReleaseHandle[h ! SunYPAgent.Error => CONTINUE];
IF errorCodes # NIL THEN ERROR NN.Error[ errorCodes, "SunYP 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"];
{
ENABLE NN.Error => {
IF (codes # NIL) AND (codes.first = $notFound) AND (components = hostAndPort) THEN { portName ¬ port; CONTINUE };
};
portName ¬ LookupPort[port]; -- ! NN.Error
};
};
};
ENDCASE;
SELECT components FROM
host => RETURN [hostName];
port => RETURN [portName];
hostAndPort => RETURN [Rope.Cat[hostName, ":", portName]];
ENDCASE => ERROR;
};
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];
};
RegisterSelf[];
}.