-- Copyright (C) 1983 by Xerox Corporation. All rights reserved. -- LocalNameConversion.mesa, HGM, 24-Sep-83 15:21:44 DIRECTORY Mopcodes USING [zEXCH], String USING [AppendChar, AppendString, AppendLongNumber, AppendOctal], Buffer USING [AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer], Driver USING [Glitch], PupDefs USING [ NameLookupErrorCode, DataWordsPerPupBuffer, GetPupContentsBytes, SetPupContentsWords, SetPupContentsBytes, UniqueLocalPupAddress, PupRouterBroadcastThis, PupAddress, PupBuffer, PupSocket, PupSocketDestroy, PupSocketMake, SecondsToTocks], PupRouterDefs USING [GetRoutingTableEntry, RoutingTableEntry], PupStream USING [], PupTypes USING [fillInSocketID, miscSrvSoc, PupSocketID]; LocalNameConversion: PROGRAM IMPORTS String, Buffer, Driver, PupDefs, PupRouterDefs EXPORTS PupStream, PupDefs = BEGIN OPEN PupDefs; PupNameTrouble: PUBLIC ERROR [e: LONG STRING, code: NameLookupErrorCode] = CODE; StringIsNIL: PUBLIC ERROR = CODE; StringTooLong: PUBLIC ERROR = CODE; GetPupAddress: PUBLIC PROCEDURE [ a: LONG POINTER TO PupAddress, s: LONG STRING] = BEGIN IF ~ParsePupAddressConstant[a, s] THEN PupNameLookup[a, s]; END; -- Lookup Text string as Name Via our own NameServer PupNameLookup: PUBLIC PROCEDURE [ a: LONG POINTER TO PupAddress, s: LONG 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: LONG STRING, filter: PROCEDURE [PupAddress] RETURNS [BOOLEAN]] RETURNS [hit: BOOLEAN] = BEGIN pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 10]; soc: PupSocket ← PupSocketMake[ PupTypes.fillInSocketID, GetMyMiscServicesSoc[], SecondsToTocks[2]]; b: PupBuffer ← NIL; BEGIN ENABLE UNWIND => -- this is the error exit BEGIN IF b # NIL THEN Buffer.ReturnBuffer[b]; PupSocketDestroy[soc]; Buffer.DestroyPool[pool]; END; FOR try: CARDINAL IN [0..20) DO b ← Buffer.GetBuffer[pup, pool, send]; b.pup.pupType ← nameLookup; b.pup.pupID ← [try, try]; MoveStringBodyToPupBuffer[b, s]; IF try > 10 THEN BEGIN b.pup.source ← soc.getLocalAddress[]; b.pup.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.pup.pupType FROM nameIs => BEGIN maxAnswers: CARDINAL = 35; maxHops: CARDINAL = 999; trialAddress: LONG POINTER TO ARRAY OF PupAddress ← LOOPHOLE[@b.pup.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; Buffer.ReturnBuffer[b]; PupSocketDestroy[soc]; Buffer.DestroyPool[pool]; RETURN; END; nameError => SaveFrameSpace[b]; ENDCASE => BEGIN Buffer.ReturnBuffer[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.pup.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: LONG POINTER TO PupAddress, s: LONG 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: LONG STRING, a: PupAddress] = BEGIN pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 10]; soc: PupSocket ← PupSocketMake[ PupTypes.fillInSocketID, GetMyMiscServicesSoc[], SecondsToTocks[2]]; b: PupBuffer ← NIL; BEGIN ENABLE UNWIND => -- this is the error exit BEGIN IF b # NIL THEN Buffer.ReturnBuffer[b]; PupSocketDestroy[soc]; Buffer.DestroyPool[pool]; END; FOR try: CARDINAL IN [0..20) DO b ← Buffer.GetBuffer[pup, pool, send]; b.pup.pupType ← addressLookup; b.pup.pupID ← [try, try]; b.pup.address ← a; SetPupContentsWords[b, SIZE[PupAddress]]; IF try > 10 THEN BEGIN b.pup.source ← soc.getLocalAddress[]; b.pup.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.pup.pupType FROM addressIs => BEGIN AppendPseudoString[ s, DESCRIPTOR[@b.pup.pupBytes, GetPupContentsBytes[b]]]; Buffer.ReturnBuffer[b]; PupSocketDestroy[soc]; Buffer.DestroyPool[pool]; RETURN; END; nameError => SaveFrameSpace[b]; ENDCASE => BEGIN Buffer.ReturnBuffer[b]; b ← NIL; END; ENDLOOP; ERROR PupNameTrouble["No name lookup server responded"L, noResponse]; END; -- of ENABLE END; AppendMyName: PUBLIC PROCEDURE [name: LONG STRING] = BEGIN AppendHostName[name, UniqueLocalPupAddress[NIL]]; END; AppendHostName: PUBLIC PROCEDURE [s: LONG STRING, who: PupAddress] = BEGIN who.socket ← [0, 0]; PupAddressLookup[ s, who ! PupNameTrouble => BEGIN AppendPupAddress[s, who]; CONTINUE; END]; END; AppendOctal: PROCEDURE [s: LONG 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: LONG STRING] = BEGIN dataBytesPerPup: CARDINAL ← 2*DataWordsPerPupBuffer[]; IF s = NIL THEN Driver.Glitch[StringIsNIL]; IF s.length > dataBytesPerPup THEN Driver.Glitch[StringTooLong]; FOR i: CARDINAL IN [0..s.length) DO b.pup.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: LONG STRING] = BEGIN length: CARDINAL; dataBytesPerPup: CARDINAL ← 2*DataWordsPerPupBuffer[]; IF s = NIL THEN Driver.Glitch[StringIsNIL]; length ← GetPupContentsBytes[b]; IF (s.length + length) > dataBytesPerPup THEN Driver.Glitch[StringTooLong]; FOR i: CARDINAL IN [0..s.length) DO b.pup.pupChars[length + i] ← s[i]; ENDLOOP; SetPupContentsBytes[b, (s.length + length)]; END; -- APPEND a pseudo string to a LONG STRING AppendPseudoString: PROCEDURE [ e: LONG 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: LONG 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: LONG STRING, b: PupDefs.PupBuffer] = BEGIN IF b.pup.pupType = error THEN BEGIN String.AppendString[s, "[Error Pup, code="L]; String.AppendOctal[s, b.pup.errorCode]; String.AppendString[s, ", from: "L]; AppendPupAddress[s, b.pup.source]; String.AppendString[s, "] "L]; FOR i: CARDINAL IN [0..PupDefs.GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO String.AppendChar[s, b.pup.errorText[i]]; ENDLOOP; END ELSE BEGIN String.AppendString[s, "[Funny PupType = "L]; String.AppendOctal[s, b.pup.pupType]; String.AppendString[s, ", from: "L]; AppendPupAddress[s, b.pup.source]; String.AppendString[s, "]"L]; END; END; END.