<> <> <> <<>> <> <<>> DIRECTORY CommDriver USING [GetNetworkChain, Network], Convert USING [RopeFromCard], Pup USING [allHosts, allNets, Address, nullAddress, nullHost, nullNet, nullSocket, Socket], PupBuffer USING [Buffer, maxAddresses], PupHop USING [GetHop, Hop, unreachable], PupName USING [Code], PupSocket USING [AllocBuffer, Broadcast, CopyRope, CreateEphemeral, Destroy, ExtractRope, FreeBuffer, Get, GetUserSize, Socket, SetNoErrors, SetUserSize], PupType USING [CardFromSocket, SocketFromCard], PupWKS USING [misc], Rope USING [Cat, Equal, Fetch, Length, ROPE]; PupNameImpl: CEDAR PROGRAM IMPORTS CommDriver, Convert, PupHop, PupSocket, PupType, Rope EXPORTS PupName = { ROPE: TYPE = Rope.ROPE; <> Error: PUBLIC ERROR [code: PupName.Code, text: ROPE] = CODE; <> MyName: PUBLIC PROC RETURNS [rope: ROPE] = { network: CommDriver.Network _ CommDriver.GetNetworkChain[]; me: Pup.Address _ Pup.nullAddress; IF network # NIL THEN me _ NameLookup["ME", Pup.nullSocket]; rope _ HisName[me]; }; <<>> MyRope: PUBLIC PROC RETURNS [rope: ROPE] = { network: CommDriver.Network _ CommDriver.GetNetworkChain[]; me: Pup.Address _ Pup.nullAddress; IF network # NIL THEN me _ [network.pup.net, network.pup.host, Pup.nullSocket]; rope _ AddressToRope[me]; }; <> NameLookup: PUBLIC PROC [name: ROPE, default: Pup.Socket] RETURNS [Pup.Address] = { addresses: LIST OF Pup.Address _ HisAddresses[name, default]; hops: PupHop.Hop; IF addresses = NIL THEN ERROR; hops _ PupHop.GetHop[addresses.first.net]; IF hops = PupHop.unreachable THEN Error[noRoute, "No route to host"]; RETURN[addresses.first]; }; HisAddresses: PUBLIC PROC [name: ROPE, default: Pup.Socket] RETURNS [LIST OF Pup.Address] = { address: Pup.Address; parsed: BOOL; socket: PupSocket.Socket; [parsed, address] _ CheckForME[name, default]; IF parsed THEN RETURN[LIST[address]]; [parsed, address] _ ParseAddress[name, default]; IF parsed THEN RETURN[LIST[address]]; socket _ PupSocket.CreateEphemeral[ remote: [Pup.allNets, Pup.allHosts, PupWKS.misc], getTimeout: 3000 ]; PupSocket.SetNoErrors[socket]; FOR try: CARDINAL IN [0..10) DO b: PupBuffer.Buffer _ PupSocket.AllocBuffer[socket]; b.type _ nameLookup; b.id _ [try, try]; PupSocket.CopyRope[b, name]; PupSocket.Broadcast[socket, b]; DO b _ PupSocket.Get[socket]; IF b = NIL THEN EXIT; SELECT b.type FROM nameReply => { head: LIST OF Pup.Address _ NIL; maxAnswers: NAT = PupBuffer.maxAddresses; hops: ARRAY [0..maxAnswers) OF PupHop.Hop _ ALL[PupHop.unreachable]; howMany: CARDINAL; howMany _ MIN[ maxAnswers, PupSocket.GetUserSize[b]/SIZE[Pup.Address]]; FOR i: NAT IN [0..howMany) DO hops[i] _ PupHop.GetHop[b.addresses[i].net]; IF b.addresses[i].socket = Pup.nullSocket THEN b.addresses[i].socket _ default; ENDLOOP; FOR j: PupHop.Hop DECREASING IN PupHop.Hop DO FOR i: NAT DECREASING IN [0..howMany) DO IF hops[i] # j THEN LOOP; head _ CONS[b.addresses[i], head]; ENDLOOP; ENDLOOP; PupSocket.FreeBuffer[b]; PupSocket.Destroy[socket]; RETURN[head]; }; nameError => { err: ROPE _ PupSocket.ExtractRope[b]; ERROR Error[errorFromServer, err]; }; ENDCASE => PupSocket.FreeBuffer[b]; ENDLOOP; ENDLOOP; ERROR Error[noResponse, "No name lookup server responded"]; }; CheckForME: PROCEDURE [name: Rope.ROPE, default: Pup.Socket] RETURNS [ok: BOOLEAN, him: Pup.Address] = { network: CommDriver.Network; IF ~Rope.Equal["ME", name, FALSE] THEN RETURN[FALSE, ]; ok _ TRUE; network _ CommDriver.GetNetworkChain[]; IF network = NIL THEN RETURN[ok, [Pup.nullNet, Pup.nullHost, default]]; him _ [network.pup.net, network.pup.host, default]; }; ParseAddress: PROCEDURE [name: Rope.ROPE, default: Pup.Socket] RETURNS [ok: BOOLEAN, him: Pup.Address] = { length: INT = Rope.Length[name]; net, host: CARDINAL _ 0; socket: LONG CARDINAL _ 0; him.socket _ default; ok _ FALSE; IF length = 0 THEN RETURN; FOR i: CARDINAL _ 0, i + 1 UNTIL i = length DO c: CHARACTER _ Rope.Fetch[name, i]; SELECT c FROM '# => { IF net # 0 OR socket > 0FFH THEN RETURN; net _ host; host _ socket; socket _ 0; }; IN ['0..'9] => { IF socket > LAST[LONG CARDINAL]/8 THEN RETURN; socket _ socket*8 + CARDINAL[c - '0]; }; ENDCASE => RETURN; ENDLOOP; IF net > 0FFH THEN RETURN; IF host > 0FFH THEN RETURN; him.net _ [net]; him.host _ [host]; IF socket # 0 THEN him.socket _ PupType.SocketFromCard[socket]; ok _ TRUE; }; <<>> AddressToRope: PUBLIC PROC [him: Pup.Address] RETURNS [rope: ROPE] = { net: ROPE = Convert.RopeFromCard[him.net, 8, FALSE]; host: ROPE = Convert.RopeFromCard[him.host, 8, FALSE]; rope _ Rope.Cat[net, "#", host, "#"]; IF him.socket # Pup.nullSocket THEN rope _ Rope.Cat[rope, Convert.RopeFromCard[PupType.CardFromSocket[him.socket], 8, FALSE] ]; }; HisName: PUBLIC PROC [him: Pup.Address] RETURNS [rope: ROPE] = { him.socket _ Pup.nullSocket; rope _ AddressLookup[him ! Error => { rope _ AddressToRope[him]; CONTINUE; }]; }; AddressLookup: PUBLIC PROC [him: Pup.Address] RETURNS [rope: ROPE] = { socket: PupSocket.Socket _ PupSocket.CreateEphemeral[ remote: [Pup.allNets, Pup.allHosts, PupWKS.misc], getTimeout: 3000 ]; PupSocket.SetNoErrors[socket]; FOR try: CARDINAL IN [0..10) DO b: PupBuffer.Buffer _ PupSocket.AllocBuffer[socket]; b.type _ addressLookup; b.id _ [try, try]; b.address _ him; PupSocket.SetUserSize[b, SIZE[Pup.Address]]; PupSocket.Broadcast[socket, b]; DO b _ PupSocket.Get[socket]; IF b = NIL THEN EXIT; SELECT b.type FROM addressReply => { rope _ PupSocket.ExtractRope[b]; PupSocket.FreeBuffer[b]; PupSocket.Destroy[socket]; RETURN; }; nameError => { err: ROPE _ PupSocket.ExtractRope[b]; ERROR Error[errorFromServer, err]; }; ENDCASE => PupSocket.FreeBuffer[b]; ENDLOOP; ENDLOOP; ERROR Error[noResponse, "No name lookup server responded"]; }; }.