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;
Local name
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];
};
Name/Address translation
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"];
};