File: NameConversion.mesa,
Last Edit: HGM March 22, 1981 9:54 PM
Last Edit: Andrew Birrell May 26, 1983 3:29 pm
Last Edited by: Levin, June 24, 1983 5:21 pm
DIRECTORY
Convert USING[ RopeFromCard ],
PrincOps USING [zEXCH],
StatsDefs USING [StatIncr],
PupRouterDefs USING [GetRoutingTableEntry, RoutingTableEntry, maxHop],
CommFlags USING [doStats],
DriverDefs USING [Glitch],
PupStream USING [],
PupDefs USING [ AnyLocalPupAddress, GetFreePupBuffer, ReturnFreePupBuffer, DataWordsPerPupBuffer, GetPupContentsBytes, SetPupContentsWords, SetPupContentsBytes, NameLookupErrorCode, PupAddress, PupBuffer, PupSocket, PupRouterBroadcastThis, PupSocketDestroy, PupSocketMake, SecondsToTocks],
PupTypes USING [fillInPupAddress, fillInSocketID, miscSrvSoc, PupSocketID],
Rope USING [Cat, Equal, Fetch, FromRefText, Length, ROPE];
NameConversion: PROGRAM
IMPORTS Convert, DriverDefs, PupRouterDefs, PupDefs, Rope, StatsDefs
EXPORTS PupDefs, PupStream =
BEGIN OPEN PupDefs;
PupNameTrouble: PUBLIC SAFE ERROR [e: Rope.ROPE, code: NameLookupErrorCode] = CODE;
StringTooLong: PUBLIC ERROR = CODE;
GetPupAddress: PUBLIC SAFE PROCEDURE [soc: PupTypes.PupSocketID, name: Rope.ROPE] RETURNS[ addr: PupAddress ] =
TRUSTED BEGIN
ok: BOOL;
[ok, addr] ← ParsePupAddressConstant[soc, name];
IF NOT ok THEN addr ← PupNameLookup[soc, name];
END;
Lookup Text string as Name Via Gateways
PupNameLookup: PUBLIC SAFE PROCEDURE [soc: PupTypes.PupSocketID, name: Rope.ROPE] RETURNS[ a: PupAddress ] =
TRUSTED BEGIN
TakeTheFirst: PROCEDURE [him: PupAddress] RETURNS [BOOLEAN] =
BEGIN
rte: PupRouterDefs.RoutingTableEntry;
rte ← PupRouterDefs.GetRoutingTableEntry[him.net];
IF rte = NIL OR rte.network = NIL OR rte.hop > PupRouterDefs.maxHop THEN
RETURN[FALSE]; -- but skip unreachable ones
a.net ← him.net;
a.host ← him.host;
IF him.socket # [0, 0] THEN a.socket ← him.socket;
RETURN[TRUE];
END;
a.socket ← soc; -- default--
IF name.Equal["ME", FALSE] THEN
BEGIN -- special case hack
me: PupAddress ← AnyLocalPupAddress[soc];
a.net ← me.net;
a.host ← me.host;
RETURN;
END;
IF EnumeratePupAddresses[name, TakeTheFirst] THEN RETURN;
ERROR PupNameTrouble["No Route to that Host", noRoute];
END;
EnumeratePupAddresses: PUBLIC SAFE PROCEDURE [
name: Rope.ROPE, filter: PROCEDURE [PupAddress] RETURNS [BOOLEAN]]
RETURNS [hit: BOOLEAN] =
TRUSTED BEGIN
soc: PupSocket;
b: PupBuffer ← NIL;
soc ← PupSocketMake[
PupTypes.fillInSocketID, PupTypes.fillInPupAddress, SecondsToTocks[2]];
BEGIN
ENABLE
UNWIND => -- this is the error exit
BEGIN IF b # NIL THEN ReturnFreePupBuffer[b]; PupSocketDestroy[soc]; END;
FOR try: CARDINAL IN [0..10) DO
b ← GetFreePupBuffer[];
b.pupType ← nameLookup;
b.pupID ← [try, try];
b.dest.socket ← PupTypes.miscSrvSoc;
b.source ← soc.getLocalAddress[];
MoveRopeToPupBuffer[b, name];
PupRouterBroadcastThis[b];
b ← NIL; -- In case we get Aborted and then UNWIND
b ← soc.get[]; -- 2 sec wait
IF b # NIL THEN
SELECT b.pupType FROM
nameIs =>
BEGIN
maxAnswers: CARDINAL = 35;
longHop: CARDINAL = PupRouterDefs.maxHop + 1;
trialAddress: LONG POINTER TO ARRAY OF PupAddress ←
LOOPHOLE[@b.pupWords];
distance: ARRAY [0..maxAnswers) OF CARDINALALL[longHop];
howMany: CARDINAL;
howMany ← MIN[
maxAnswers, GetPupContentsBytes[b]/(2*SIZE[PupAddress])];
FOR i: CARDINAL IN [0..howMany) DO
rte: PupRouterDefs.RoutingTableEntry;
rte ← PupRouterDefs.GetRoutingTableEntry[trialAddress[i].net];
IF rte # NIL AND rte.network # NIL THEN distance[i] ← rte.hop;
ENDLOOP;
hit ← FALSE;
FOR j: CARDINAL IN [0..longHop] UNTIL hit DO
FOR i: CARDINAL IN [0..howMany) UNTIL hit DO
IF distance[i] # j THEN LOOP;
hit ← filter[trialAddress[i]];
ENDLOOP;
ENDLOOP;
ReturnFreePupBuffer[b];
PupSocketDestroy[soc];
RETURN;
END;
nameError =>
ERROR PupNameTrouble[RopeFromPup[b], errorFromServer];
ENDCASE =>
BEGIN
IF CommFlags.doStats THEN StatsDefs.StatIncr[statMouseTrap];
ReturnFreePupBuffer[b];
b ← NIL;
END;
ENDLOOP;
ERROR PupNameTrouble["No name lookup server responded", noResponse];
END; -- of ENABLE
END;
Parse a string of the form net#host#socket
Setup net and host appropiately, Don't change socket if not specified
RETURNs TRUE unless can't parse it.
ParsePupAddressConstant: PUBLIC SAFE PROCEDURE [soc: PupTypes.PupSocketID, name: Rope.ROPE]
RETURNS [ok: BOOLEAN, a: PupAddress] =
CHECKED BEGIN
length: INT = name.Length[];
n, h, s1, s2: CARDINAL ← 0;
bar: BOOLEANFALSE;
a.socket ← soc;
ok ← FALSE;
IF length = 0 THEN RETURN;
FOR i: CARDINAL ← 0, i + 1 UNTIL i = length DO
c: CHARACTER ← name.Fetch[i];
SELECT c FROM
'| => BEGIN IF bar THEN RETURN; bar ← TRUE; s1 ← s2; s2 ← 0; END;
'# =>
BEGIN
IF bar THEN RETURN;
IF n # 0 OR s1 # 0 THEN RETURN;
n ← h;
h ← s2;
s1 ← s2 ← 0;
END;
IN ['0..'9] =>
BEGIN
IF ~bar THEN s1 ← s1*8 + s2/17777B -- 32 bit number
ELSE IF s2 > 17777B THEN RETURN;
s2 ← s2*8 + CARDINAL[c - '0];
END;
ENDCASE => RETURN;
ENDLOOP;
IF n NOT IN [0..377B] THEN RETURN;
IF h NOT IN [0..377B] THEN RETURN;
a.net ← [n];
a.host ← [h];
IF s1 # 0 OR s2 # 0 THEN a.socket ← [s1, s2];
ok ← TRUE;
END;
Inverse of PupNameLookup
PupAddressLookup: PUBLIC SAFE PROCEDURE [a: PupAddress] RETURNS[name: Rope.ROPE] =
TRUSTED BEGIN
soc: PupSocket;
b: PupBuffer ← NIL;
soc ← PupSocketMake[
PupTypes.fillInSocketID, PupTypes.fillInPupAddress, SecondsToTocks[2]];
BEGIN
ENABLE
UNWIND => -- this is the error exit
BEGIN IF b # NIL THEN ReturnFreePupBuffer[b]; PupSocketDestroy[soc]; END;
FOR try: CARDINAL IN [0..10) DO
b ← GetFreePupBuffer[];
b.pupType ← addressLookup;
b.pupID ← [try, try];
b.dest.socket ← PupTypes.miscSrvSoc;
b.source ← soc.getLocalAddress[];
b.address ← a;
SetPupContentsWords[b, SIZE[PupAddress]];
PupRouterBroadcastThis[b];
b ← NIL; -- In case we get Aborted and then UNWIND
b ← soc.get[]; -- 2 sec wait
IF b # NIL THEN
SELECT b.pupType FROM
addressIs =>
BEGIN
name ← RopeFromPup[b];
ReturnFreePupBuffer[b];
PupSocketDestroy[soc];
RETURN;
END;
nameError =>
ERROR PupNameTrouble[RopeFromPup[b], errorFromServer];
ENDCASE =>
BEGIN
IF CommFlags.doStats THEN StatsDefs.StatIncr[statMouseTrap];
ReturnFreePupBuffer[b];
b ← NIL;
END;
ENDLOOP;
ERROR PupNameTrouble["No name lookup server responded", noResponse];
END; -- of ENABLE
END;
GetMyName: PUBLIC SAFE PROCEDURE RETURNS [Rope.ROPE] =
CHECKED BEGIN RETURN[ GetHostName[AnyLocalPupAddress[PupTypes.fillInSocketID]] ] END;
GetHostName: PUBLIC SAFE PROCEDURE [who: PupAddress] RETURNS [name: Rope.ROPE] =
CHECKED BEGIN
who.socket ← [0, 0];
name ← PupAddressLookup[
who ! PupNameTrouble => BEGIN name ← PupAddressToRope[who]; CONTINUE; END];
END;
move the body of a ROPE into the body of a packet and set its length
MoveRopeToPupBuffer: PUBLIC PROCEDURE [b: PupBuffer, r: Rope.ROPE] =
{ SetPupContentsBytes[b, 0]; AppendRopeToPupBuffer[b, r] };
AppendRopeToPupBuffer: PUBLIC PROCEDURE [b: PupBuffer, r: Rope.ROPE] =
BEGIN
length: CARDINAL = GetPupContentsBytes[b];
rLength: INT = r.Length[];
dataBytesPerPup: CARDINAL ← 2*DataWordsPerPupBuffer[];
IF rLength + length > dataBytesPerPup THEN DriverDefs.Glitch[StringTooLong];
FOR i: CARDINAL IN NAT[0..rLength) DO b.pupChars[length + i] ← r.Fetch[i]; ENDLOOP;
SetPupContentsBytes[b, rLength + length];
END;
Extract a ROPE from a packet
RopeFromPup: PROCEDURE [b: PupBuffer] RETURNS [Rope.ROPE] =
BEGIN
length: INT = GetPupContentsBytes[b];
text: REF TEXT = NEW[TEXT[length]];
FOR i: INT IN [0..length) DO text[i] ← b.pupChars[i] ENDLOOP;
text.length ← length;
RETURN[Rope.FromRefText[text]]
END;
convert an address constant to a ROPE
PupAddressToRope: PUBLIC SAFE PROCEDURE [a: PupAddress] RETURNS[r: Rope.ROPE] =
TRUSTED BEGIN
Flip: PROCEDURE [PupTypes.PupSocketID] RETURNS [LONG CARDINAL] = MACHINE CODE
BEGIN PrincOps.zEXCH END;
r ← Rope.Cat[
Convert.RopeFromCard[a.net, 8, FALSE],
"#",
Convert.RopeFromCard[a.host, 8, FALSE],
"#",
Convert.RopeFromCard[Flip[a.socket], 8, FALSE]
]
END;
END.