-- File: LocalNameConversion.mesa, Last Edit: HGM March 22, 1981 10:02 PM DIRECTORY Mopcodes USING [zEXCH], String USING [AppendChar, AppendString, AppendLongNumber, AppendOctal], PupRouterDefs USING [GetRoutingTableEntry, RoutingTableEntry], DriverDefs USING [Glitch], PupStream USING [], PupDefs USING [ NameLookupErrorCode, DataWordsPerPupBuffer, GetFreePupBuffer, ReturnFreePupBuffer, GetPupContentsBytes, SetPupContentsWords, SetPupContentsBytes, UniqueLocalPupAddress, PupRouterBroadcastThis, PupAddress, PupBuffer, PupSocket, PupSocketDestroy, PupSocketMake, SecondsToTocks], PupTypes USING [fillInSocketID, miscSrvSoc, PupSocketID]; LocalNameConversion: PROGRAM IMPORTS String, PupRouterDefs, DriverDefs, 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 our own NameServer PupNameLookup: PUBLIC PROCEDURE [a: POINTER TO PupAddress, s: STRING] = BEGIN TakeTheFirst: PROCEDURE [him: PupAddress] RETURNS [BOOLEAN] = BEGIN a.net _ him.net; a.host _ him.host; IF him.socket # [0, 0] THEN a.socket _ him.socket; RETURN[TRUE]; END; 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; 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, GetMyMiscServicesSoc[], 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..20) DO b _ GetFreePupBuffer[]; b.pupType _ nameLookup; b.pupID _ [try, try]; MoveStringBodyToPupBuffer[b, s]; IF try > 10 THEN BEGIN b.source _ soc.getLocalAddress[]; b.dest.socket _ PupTypes.miscSrvSoc; PupRouterBroadcastThis[b]; END ELSE soc.put[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; maxHops: CARDINAL = 999; trialAddress: LONG POINTER TO ARRAY OF PupAddress _ LOOPHOLE[@b.pupWords]; distance: ARRAY [0..maxAnswers) OF CARDINAL _ ALL[maxHops]; 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..maxHops) 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 => SaveFrameSpace[b]; ENDCASE => BEGIN ReturnFreePupBuffer[b]; b _ NIL; END; ENDLOOP; ERROR PupNameTrouble["No name lookup server responded"L, noResponse]; END; -- of ENABLE END; SaveFrameSpace: PROCEDURE [b: PupBuffer] = BEGIN error: STRING = [50]; AppendPseudoString[error, DESCRIPTOR[@b.pupBytes, GetPupContentsBytes[b]]]; ERROR PupNameTrouble[error, errorFromServer]; 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, GetMyMiscServicesSoc[], 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..20) DO b _ GetFreePupBuffer[]; b.pupType _ addressLookup; b.pupID _ [try, try]; b.address _ a; SetPupContentsWords[b, SIZE[PupAddress]]; IF try > 10 THEN BEGIN b.source _ soc.getLocalAddress[]; b.dest.socket _ PupTypes.miscSrvSoc; PupRouterBroadcastThis[b]; END ELSE soc.put[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 => SaveFrameSpace[b]; ENDCASE => BEGIN 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; AppendOctal: PROCEDURE [s: STRING, n: CARDINAL] = BEGIN IF n > 7 THEN AppendOctal[s, n/8]; String.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[]; IF s = NIL THEN DriverDefs.Glitch[StringIsNIL]; IF s.length > dataBytesPerPup THEN DriverDefs.Glitch[StringTooLong]; FOR i: CARDINAL 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 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: CARDINAL 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 FOR i: CARDINAL IN [0..MIN[e.maxlength - e.length, LENGTH[p]]) DO String.AppendChar[e, p[i]]; ENDLOOP; END; GetMyMiscServicesSoc: PROCEDURE RETURNS [me: PupAddress] = BEGIN me _ UniqueLocalPupAddress[NIL]; me.socket _ PupTypes.miscSrvSoc; END; AppendPupAddress: PUBLIC PROCEDURE [s: STRING, a: PupAddress] = BEGIN Flip: PROCEDURE [PupTypes.PupSocketID] RETURNS [LONG INTEGER] = MACHINE CODE BEGIN Mopcodes.zEXCH END; AppendOctal[s, a.net]; String.AppendChar[s, '#]; AppendOctal[s, a.host]; String.AppendChar[s, '#]; String.AppendLongNumber[s, Flip[a.socket], 8]; END; AppendErrorPup: PUBLIC PROCEDURE [s: STRING, b: PupDefs.PupBuffer] = BEGIN IF b.pupType = error THEN BEGIN String.AppendString[s, "[Error Pup, code="L]; String.AppendOctal[s, b.errorCode]; String.AppendString[s, ", from: "L]; AppendPupAddress[s, b.source]; String.AppendString[s, "] "L]; FOR i: CARDINAL IN [0..PupDefs.GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO String.AppendChar[s, b.errorText[i]]; ENDLOOP; END ELSE BEGIN String.AppendString[s, "[Funny PupType = "L]; String.AppendOctal[s, b.pupType]; String.AppendString[s, ", from: "L]; AppendPupAddress[s, b.source]; String.AppendString[s, "]"L]; END; END; END.