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]];
};
};
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]];
};
};
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[];
}.