<<>> <> <> <> <<>> <> <> DIRECTORY Arpa, Convert, NetworkName, Rope, SunYPAgent ; NetworkNameSunYPImpl: CEDAR PROGRAM IMPORTS Convert, NetworkName, Rope, SunYPAgent ~ { OPEN NN: NetworkName; <> ROPE: TYPE ~ Rope.ROPE; <> hostsByName: ROPE ¬ "hosts.byname"; hostsByAddr: ROPE ¬ "hosts.byaddr"; servicesByName: ROPE ¬ "services.byname"; myFamily: ATOM ¬ $ARPA; myFlavor: ATOM ¬ $SunYP; <> 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"]; }; <> 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[]; }.