PupNameImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Hal Murray, June 2, 1986 5:37:05 pm PDT
This module deliberately drops buffers and sockets on the floor on error paths to make sure they really work and/or provide a handy test case.
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;
Errors
Error: PUBLIC ERROR [code: PupName.Code, text: ROPE] = CODE;
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"];
};
}.