-- File: NameConversion.mesa, Last Edit: HGM March 22, 1981 9:54 PM DIRECTORY Mopcodes USING [zEXCH], String USING [AppendChar, AppendString, AppendOctal, AppendLongNumber], StatsDefs USING [StatIncr], PupRouterDefs USING [GetRoutingTableEntry, RoutingTableEntry, maxHop], CommFlags USING [doStats], DriverDefs USING [Glitch], PupStream USING [], PupDefs USING [ GetFreePupBuffer, ReturnFreePupBuffer, DataWordsPerPupBuffer, GetPupContentsBytes, SetPupContentsWords, SetPupContentsBytes, UniqueLocalPupAddress, NameLookupErrorCode, PupAddress, PupBuffer, PupSocket, PupRouterBroadcastThis, PupSocketDestroy, PupSocketMake, SecondsToTocks], PupTypes USING [fillInPupAddress, fillInSocketID, miscSrvSoc, PupSocketID]; NameConversion: PROGRAM IMPORTS String, StatsDefs, DriverDefs, PupRouterDefs, PupDefs EXPORTS PupDefs, PupStream = 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: 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; 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, 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[]; 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; trialAddress: LONG POINTER TO ARRAY OF PupAddress ← LOOPHOLE[@b.pupWords]; distance: ARRAY [0..maxAnswers) OF CARDINAL ← ALL[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 => SaveFrameSpace[b]; ENDCASE => BEGIN IF CommFlags.doStats THEN StatsDefs.StatIncr[statMouseTrap]; 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; bar: BOOLEAN ← FALSE; IF s = NIL OR s.length = 0 THEN RETURN[FALSE]; FOR i: CARDINAL ← 0, i + 1 UNTIL i = s.length DO c: CHARACTER; 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; 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 AppendPseudoString[ s, DESCRIPTOR[@b.pupBytes, GetPupContentsBytes[b]]]; ReturnFreePupBuffer[b]; PupSocketDestroy[soc]; RETURN; END; nameError => SaveFrameSpace[b]; ENDCASE => BEGIN IF CommFlags.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; 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[]; 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 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; 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.