-- File: NameConversion.mesa, Last Edit: -- MAS Apr 18, 1980 12:38 PM -- HGM August 3, 1980 5:20 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY Mopcodes: FROM "Mopcodes" USING [zEXCH], StatsDefs: FROM "StatsDefs" USING [StatIncr], CommUtilDefs: FROM "CommUtilDefs" USING [AppendChar, AppendLongNumber], PupRouterDefs: FROM "PupRouterDefs" USING [ GetPupRoutingTable, maxHop, PupRoutingTableEntry], DriverDefs: FROM "DriverDefs" USING [doStats, Glitch], PupStream: FROM "PupStream", -- EXPORTs PupDefs: FROM "PupDefs" USING [ GetFreePupBuffer, ReturnFreePupBuffer, DataWordsPerPupBuffer, GetPupContentsBytes, SetPupContentsWords, SetPupContentsBytes, UniqueLocalPupAddress, NameLookupErrorCode, PupAddress, PupBuffer, PupSocket, PupRouterBroadcastThis, PupSocketDestroy, PupSocketMake, SecondsToTocks], PupTypes: FROM "PupTypes" USING [ fillInPupAddress, fillInSocketID, miscSrvSoc, PupSocketID]; NameConversion: PROGRAM IMPORTS CommUtilDefs, StatsDefs, DriverDefs, PupRouterDefs, PupDefs EXPORTS PupStream, PupDefs = BEGIN OPEN PupDefs; PupNameTrouble: PUBLIC ERROR [e: STRING, code: NameLookupErrorCode] = CODE; StringIsNIL: PUBLIC ERROR = CODE; StringTooLong: PUBLIC ERROR = CODE; GetPupAddress: PUBLIC PROCEDURE [a: POINTER TO PupAddress, s: STRING] = BEGIN IF ~ParsePupAddressConstant[a,s] THEN PupNameLookup[a,s]; END; -- Lookup Text string as Name Via Gateways PupNameLookup: PUBLIC PROCEDURE [a: POINTER TO PupAddress, s: STRING] = BEGIN TakeTheFirst: PROCEDURE [him: PupAddress] RETURNS [BOOLEAN] = BEGIN rte: POINTER TO PupRouterDefs.PupRoutingTableEntry; IF him.net>=LENGTH[routing] THEN RETURN[FALSE]; -- skip unreachable ones rte _ @routing[him.net]; IF rte.network=NIL OR rte.hop>PupRouterDefs.maxHop THEN RETURN[FALSE]; a.net _ him.net; a.host _ him.host; IF him.socket#[0,0] THEN a.socket _ him.socket; RETURN[TRUE]; END; routing: DESCRIPTOR FOR ARRAY OF PupRouterDefs.PupRoutingTableEntry; IF s.length=2 AND s[0]='M AND s[1]='E THEN BEGIN -- special case hack me: PupAddress _ UniqueLocalPupAddress[NIL]; a.net _ me.net; a.host _ me.host; RETURN; END; routing _ PupRouterDefs.GetPupRoutingTable[]; IF EnumeratePupAddresses[s,TakeTheFirst] THEN RETURN; ERROR PupNameTrouble["No Route to that Host"L,noRoute]; END; EnumeratePupAddresses: PUBLIC PROCEDURE [ s: STRING, filter: PROCEDURE [PupAddress] RETURNS [BOOLEAN] ] RETURNS [hit: BOOLEAN] = 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; THROUGH [0..10) DO -- try a few times b _ GetFreePupBuffer[]; b.pupType _ nameLookup; b.dest.socket _ PupTypes.miscSrvSoc; b.source _ soc.getLocalAddress[]; MoveStringBodyToPupBuffer[b,s]; 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; routing: DESCRIPTOR FOR ARRAY OF PupRouterDefs.PupRoutingTableEntry; trialAddress: POINTER TO ARRAY OF PupAddress _ LOOPHOLE[@b.pupWords]; distance: ARRAY [0..maxAnswers) OF CARDINAL _ ALL[longHop]; route: POINTER TO PupRouterDefs.PupRoutingTableEntry; i, j, howMany: CARDINAL; routing _ PupRouterDefs.GetPupRoutingTable[]; howMany _ MIN[maxAnswers,GetPupContentsBytes[b]/(2*SIZE[PupAddress])]; FOR i IN [0..howMany) DO route _ @routing[trialAddress[i].net]; IF trialAddress[i].net < LENGTH[routing] AND route.network#NIL THEN distance[i] _ route.hop; ENDLOOP; hit _ FALSE; FOR j IN [0..longHop] UNTIL hit DO FOR i 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 => BEGIN error: STRING = [50]; AppendPseudoString[error,DESCRIPTOR[@b.pupBytes,GetPupContentsBytes[b]]]; ERROR PupNameTrouble[error,errorFromServer]; END; ENDCASE=> BEGIN IF DriverDefs.doStats THEN StatsDefs.StatIncr[statMouseTrap]; ReturnFreePupBuffer[b]; b _ NIL; END; ENDLOOP; ERROR PupNameTrouble["No name lookup server responded"L,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 PROCEDURE [a: POINTER TO PupAddress, s: STRING] RETURNS [BOOLEAN] = BEGIN n, h, s1, s2: CARDINAL _ 0; i: CARDINAL; c: CHARACTER; bar: BOOLEAN _ FALSE; IF s=NIL OR s.length=0 THEN RETURN[FALSE]; FOR i_0,i+1 UNTIL i=s.length DO SELECT (c_s[i]) FROM '| => BEGIN IF bar THEN RETURN[FALSE]; bar _ TRUE; s1_s2; s2_0; END; '# => BEGIN IF bar THEN RETURN[FALSE]; IF n#0 OR s1#0 THEN RETURN[FALSE]; 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[FALSE]; s2 _ s2*8+CARDINAL[c-'0]; END; ENDCASE => RETURN [FALSE]; ENDLOOP; IF n ~IN [0..377B] THEN RETURN [FALSE]; IF h ~IN [0..377B] THEN RETURN [FALSE]; a.net _ [n]; a.host _ [h]; IF s1#0 OR s2#0 THEN a.socket _ [s1,s2]; RETURN[TRUE]; END; -- Inverse of PupNameLookup PupAddressLookup: PUBLIC PROCEDURE [s: STRING, a: PupAddress] = 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; THROUGH [0..10) DO -- try a few times b _ GetFreePupBuffer[]; b.pupType _ addressLookup; 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 AppendPseudoString[s,DESCRIPTOR[@b.pupBytes,GetPupContentsBytes[b]]]; ReturnFreePupBuffer[b]; PupSocketDestroy[soc]; RETURN; END; nameError => BEGIN error: STRING = [50]; AppendPseudoString[error,DESCRIPTOR[@b.pupBytes,GetPupContentsBytes[b]]]; ERROR PupNameTrouble[error,errorFromServer]; END; ENDCASE=> BEGIN IF DriverDefs.doStats THEN StatsDefs.StatIncr[statMouseTrap]; ReturnFreePupBuffer[b]; b _ NIL; END; ENDLOOP; ERROR PupNameTrouble["No name lookup server responded"L,noResponse]; END; -- of ENABLE END; AppendMyName: PUBLIC PROCEDURE [name: STRING] = BEGIN AppendHostName[name,UniqueLocalPupAddress[NIL]]; END; AppendHostName: PUBLIC PROCEDURE [s: STRING, who: PupAddress] = BEGIN who.socket _ [0,0]; PupAddressLookup[s,who ! PupNameTrouble => BEGIN AppendPupAddress[s,who]; CONTINUE; END ]; END; Flip: PROCEDURE [PupTypes.PupSocketID] RETURNS [LONG INTEGER] = MACHINE CODE BEGIN Mopcodes.zEXCH END; AppendPupAddress: PUBLIC PROCEDURE [s: STRING, a: PupAddress] = BEGIN AppendOctal[s,a.net]; CommUtilDefs.AppendChar[s,'#]; AppendOctal[s,a.host]; CommUtilDefs.AppendChar[s,'#]; CommUtilDefs.AppendLongNumber[s,Flip[a.socket],8]; END; AppendOctal: PROCEDURE [s: STRING, n: CARDINAL] = BEGIN IF n>7 THEN AppendOctal[s,n/8]; CommUtilDefs.AppendChar[s,'0+(n MOD 8)]; END; -- move the body of a mesa STRING into the body of a packet and set its length MoveStringBodyToPupBuffer: PUBLIC PROCEDURE [b: PupBuffer, s: STRING] = BEGIN dataBytesPerPup: CARDINAL _ 2*DataWordsPerPupBuffer[]; i: CARDINAL; IF s=NIL THEN DriverDefs.Glitch[StringIsNIL]; IF s.length>dataBytesPerPup THEN DriverDefs.Glitch[StringTooLong]; FOR i IN [0..s.length) DO b.pupChars[i] _ s[i]; ENDLOOP; SetPupContentsBytes[b,s.length]; END; -- append the body of a mesa STRING into the body of a packet and set its length AppendStringBodyToPupBuffer: PUBLIC PROCEDURE [b: PupBuffer, s: STRING] = BEGIN i, length: CARDINAL; dataBytesPerPup: CARDINAL _ 2*DataWordsPerPupBuffer[]; IF s=NIL THEN DriverDefs.Glitch[StringIsNIL]; length _ GetPupContentsBytes[b]; IF (s.length+length)>dataBytesPerPup THEN DriverDefs.Glitch[StringTooLong]; FOR i IN [0..s.length) DO b.pupChars[length+i] _ s[i]; ENDLOOP; SetPupContentsBytes[b,(s.length+length)]; END; -- APPEND a pseudo string to a STRING AppendPseudoString: PROCEDURE [e: STRING, p: LONG DESCRIPTOR FOR PACKED ARRAY OF CHARACTER] = BEGIN i: CARDINAL; FOR i IN [0..MIN[e.maxlength-e.length,LENGTH[p]]) DO CommUtilDefs.AppendChar[e,p[i]]; ENDLOOP; END; END.