<> <> <> <> <> 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; <> 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 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 => 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; <> <> <> 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: BOOLEAN _ FALSE; 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; <> 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; <> 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; <> 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; <> 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.