<> <> <> DIRECTORY Arpa USING [Address], ArpaNameCache, ArpaNameSupport USING [AddressToRope], BasicTime USING [GMT, Now, Period, Update], Rope USING [ROPE, Cat, Fetch, IsEmpty], SymTab USING [Create, Delete, Erase, Fetch, Pairs, Ref, Update, UpdateAction, UpdateOperation, Val]; ArpaNameCacheImpl: CEDAR MONITOR IMPORTS ArpaNameSupport, BasicTime, Rope, SymTab EXPORTS ArpaNameCache = BEGIN OPEN ArpaNameCache; ROPE: TYPE = Rope.ROPE; cacheTable: ARRAY CacheType OF SymTab.Ref _ ALL[NIL]; FlushAll: PUBLIC PROC = { FOR cache: CacheType IN [CacheType.FIRST..CacheType.LAST] DO FlushCache[cache]; ENDLOOP; }; FlushCache: PUBLIC PROC[cache: CacheType] = { table: SymTab.Ref _ cacheTable[cache]; IF table # NIL THEN SymTab.Erase[table]; }; EnumerateCache: PUBLIC PROC[cache: CacheType, proc: EnumerateProc] = { table: SymTab.Ref _ cacheTable[cache]; IF table = NIL THEN RETURN; [] _ SymTab.Pairs[table, LOOPHOLE[proc]] }; CountCache: PUBLIC PROC[cache: CacheType] RETURNS[count: INT_0] = { CountProc: EnumerateProc = {count _ count +1}; EnumerateCache[cache, CountProc]; }; Delete: PUBLIC PROC[key: ROPE, cache: CacheType] = { table: SymTab.Ref _ cacheTable[cache]; IF table = NIL THEN RETURN; [] _ SymTab.Delete[table, key]; }; Fetch: PUBLIC PROC [key: ROPE, cache: CacheType, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL_FALSE, expired: BOOL_FALSE, entry: Entry_NIL] = { table: SymTab.Ref _ cacheTable[cache]; val: SymTab.Val; thisTtl: INT; now: BasicTime.GMT _ BasicTime.Now[]; IF table = NIL THEN RETURN; [found, val] _ SymTab.Fetch[table, key]; entry _ NARROW[val, Entry]; IF ~found OR entry = NIL THEN RETURN; entry.referenced _ now; thisTtl _ BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < 0 THEN { expired _ TRUE; IF ~acceptOld THEN {Delete[key, cache]; RETURN[FALSE, FALSE, NIL];}; }; }; FetchName: PUBLIC PROC [name: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: NameEntry] = { this: Entry; [found, expired, this] _ Fetch[name, name, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.NameEntry => RETURN[found, expired, e]; ENDCASE; }; FetchAlias: PUBLIC PROC [alias: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: AliasEntry] = { this: Entry; [found, expired, this] _ Fetch[alias, alias, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.AliasEntry => RETURN[found, expired, e]; ENDCASE; }; FetchMX: PUBLIC PROC [name: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: MXEntry] = { this: Entry; [found, expired, this] _ Fetch[name, mx, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.MXEntry => RETURN[found, expired, e]; ENDCASE; }; FetchZone: PUBLIC PROC [name: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: ZoneEntry] = { this: Entry; [found, expired, this] _ Fetch[name, zone, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.ZoneEntry => RETURN[found, expired, e]; ENDCASE; }; FetchSoa: PUBLIC PROC [name: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: SoaEntry] = { this: Entry; [found, expired, this] _ Fetch[name, soa, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.SoaEntry => RETURN[found, expired, e]; ENDCASE; }; FetchDownName: PUBLIC PROC [name: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: DownNameEntry] = { this: Entry; [found, expired, this] _ Fetch[name, downName, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.DownNameEntry => RETURN[found, expired, e]; ENDCASE; }; FetchBogusName: PUBLIC PROC [name: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: BogusNameEntry] = { this: Entry; [found, expired, this] _ Fetch[name, bogusName, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.BogusNameEntry => RETURN[found, expired, e]; ENDCASE; }; FetchAddress: PUBLIC PROC [addr: Arpa.Address, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: AddressEntry] = { this: Entry; key: ROPE _ ArpaNameSupport.AddressToRope[addr]; [found, expired, this] _ Fetch[key, address, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.AddressEntry => RETURN[found, expired, e]; ENDCASE; }; FetchAddressRope: PUBLIC PROC [addrRope: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: AddressEntry] = { this: Entry; <> IF Rope.Fetch[addrRope, 0] # '[ THEN addrRope _ Rope.Cat["[", addrRope, "]"]; [found, expired, this] _ Fetch[addrRope, address, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.AddressEntry => RETURN[found, expired, e]; ENDCASE; }; FetchDownAddress: PUBLIC PROC [addr: Arpa.Address, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: DownAddressEntry] = { key: ROPE _ ArpaNameSupport.AddressToRope[addr]; this: Entry; [found, expired, this] _ Fetch[key, downAddress, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.DownAddressEntry => RETURN[found, expired, e]; ENDCASE; }; FetchDownAddressRope: PUBLIC PROC [addrRope: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: DownAddressEntry] = { this: Entry; <> IF Rope.Fetch[addrRope, 0] # '[ THEN addrRope _ Rope.Cat["[", addrRope, "]"]; [found, expired, this] _ Fetch[addrRope, downAddress, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.DownAddressEntry => RETURN[found, expired, e]; ENDCASE; }; FetchBogusAddress: PUBLIC PROC [addr: Arpa.Address, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: BogusAddressEntry] = { key: ROPE _ ArpaNameSupport.AddressToRope[addr]; this: Entry; [found, expired, this] _ Fetch[key, bogusAddress, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.BogusAddressEntry => RETURN[found, expired, e]; ENDCASE; }; FetchBogusAddressRope: PUBLIC PROC [addrRope: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: BogusAddressEntry] = { this: Entry; <> IF Rope.Fetch[addrRope, 0] # '[ THEN addrRope _ Rope.Cat["[", addrRope, "]"]; [found, expired, this] _ Fetch[addrRope, bogusAddress, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.BogusAddressEntry => RETURN[found, expired, e]; ENDCASE; }; FetchDownServer: PUBLIC PROC [addr: Arpa.Address, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: DownServerEntry] = { this: Entry; key: ROPE _ ArpaNameSupport.AddressToRope[addr]; [found, expired, this] _ Fetch[key, downServer, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.DownServerEntry => RETURN[found, expired, e]; ENDCASE; }; FetchDownServerRope: PUBLIC PROC [addrRope: ROPE, acceptOld: BOOL _ TRUE] RETURNS [found: BOOL, expired: BOOL, entry: DownServerEntry] = { this: Entry; <> IF Rope.Fetch[addrRope, 0] # '[ THEN addrRope _ Rope.Cat["[", addrRope, "]"]; [found, expired, this] _ Fetch[addrRope, downServer, acceptOld]; WITH this SELECT FROM e: ArpaNameCache.DownServerEntry => RETURN[found, expired, e]; ENDCASE; }; Update: PUBLIC PROC [key: ROPE, cache: CacheType, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: Entry_NIL]= { table: SymTab.Ref _ cacheTable[cache]; now: BasicTime.GMT _ BasicTime.Now[]; expire: INT _ ttl; expired: BOOL _ FALSE; Action: SymTab.UpdateAction = { IF found THEN { thisTtl: INT; entry _ NARROW[val]; thisTtl _ BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < 0 THEN expired _ TRUE; IF entry.authoritative AND ~auth THEN {entry _ NIL; RETURN[none, NIL]}; } ELSE { entry _ NewEntry[cache]; entry.key _ key; }; entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, expire]; entry.ttl _ ttl; entry.source _ source; entry.authoritative _ auth; TRUSTED { WITH entry SELECT FROM e: NameEntry => e.addresses _ LOOPHOLE[data]; e: AliasEntry => e.canonicalName _ LOOPHOLE[data]; e: MXEntry => e.mxList _ LOOPHOLE[data]; e: ZoneEntry => e.servers _ LOOPHOLE[data]; e: AddressEntry => e.names _ LOOPHOLE[data]; e: SoaEntry => e.soaRef _ LOOPHOLE[data]; ENDCASE => NULL; new _ LOOPHOLE[entry]}; RETURN[store, new]; }; IF table = NIL THEN { cacheTable[cache] _ SymTab.Create[, FALSE]; table _ cacheTable[cache]; }; <> IF cache IN[address..downServer] AND Rope.Fetch[key, 0] # '[ THEN key _ Rope.Cat["[", key, "]"]; SymTab.Update[table, key, Action]; <> IF auth THEN { SELECT cache FROM name, alias, mx, zone, soa => {Delete[key, bogusName]; Delete[key, downName]}; bogusName => {Delete[key, name]; Delete[key, alias]; Delete[key, mx]; Delete[key, zone]; Delete[key, soa]; Delete[key, downName]}; address => {Delete[key, bogusAddress]; Delete[key, downAddress]}; bogusAddress => {Delete[key, address]; Delete[key, downAddress]}; ENDCASE; }; }; UpdateName: PUBLIC PROC [name: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: NameEntry] = { this: Entry; this _ Update[name, name, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.NameEntry => RETURN[e]; ENDCASE; }; <<>> UpdateAlias: PUBLIC PROC [alias: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: AliasEntry] = { this: Entry; this _ Update[alias, alias, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.AliasEntry => RETURN[e]; ENDCASE; }; <<>> UpdateMX: PUBLIC PROC [name: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: MXEntry] = { this: Entry; this _ Update[name, mx, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.MXEntry => RETURN[e]; ENDCASE; }; <<>> UpdateZone: PUBLIC PROC [name: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: ZoneEntry] = { this: Entry; this _ Update[name, zone, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.ZoneEntry => RETURN[e]; ENDCASE; }; <<>> UpdateSoa: PUBLIC PROC [name: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: SoaEntry] = { this: Entry; this _ Update[name, soa, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.SoaEntry => RETURN[e]; ENDCASE; }; <<>> UpdateDownName: PUBLIC PROC [name: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: DownNameEntry] = { this: Entry; this _ Update[name, downName, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.DownNameEntry => RETURN[e]; ENDCASE; }; <<>> UpdateBogusName: PUBLIC PROC [name: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: BogusNameEntry] = { this: Entry; this _ Update[name, bogusName, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.BogusNameEntry => RETURN[e]; ENDCASE; }; <<>> UpdateAddress: PUBLIC PROC [addr: Arpa.Address, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: AddressEntry] = { this: Entry; addrRope: ROPE _ ArpaNameSupport.AddressToRope[addr]; --include brackets IF Rope.IsEmpty[addrRope] THEN RETURN[NIL]; this _ Update[addrRope, address, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.AddressEntry => RETURN[e]; ENDCASE; }; UpdateAddressRope: PUBLIC PROC [addrRope: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: AddressEntry] = { this: Entry; IF Rope.IsEmpty[addrRope] THEN RETURN[NIL]; <> IF Rope.Fetch[addrRope, 0] # '[ THEN addrRope _ Rope.Cat["[", addrRope, "]"]; this _ Update[addrRope, address, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.AddressEntry => RETURN[e]; ENDCASE; }; UpdateDownAddress: PUBLIC PROC [addr: Arpa.Address, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: DownAddressEntry] = { this: Entry; addrRope: ROPE _ ArpaNameSupport.AddressToRope[addr]; --include brackets IF Rope.IsEmpty[addrRope] THEN RETURN[NIL]; this _ Update[addrRope, downAddress, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.DownAddressEntry => RETURN[e]; ENDCASE; }; UpdateDownAddressRope: PUBLIC PROC [addrRope: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: DownAddressEntry] = { this: Entry; IF Rope.IsEmpty[addrRope] THEN RETURN[NIL]; <> IF Rope.Fetch[addrRope, 0] # '[ THEN addrRope _ Rope.Cat["[", addrRope, "]"]; this _ Update[addrRope, downAddress, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.DownAddressEntry => RETURN[e]; ENDCASE; }; UpdateBogusAddress: PUBLIC PROC [addr: Arpa.Address, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: BogusAddressEntry] = { this: Entry; addrRope: ROPE _ ArpaNameSupport.AddressToRope[addr]; --include brackets IF Rope.IsEmpty[addrRope] THEN RETURN[NIL]; this _ Update[addrRope, bogusAddress, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.BogusAddressEntry => RETURN[e]; ENDCASE; }; UpdateBogusAddressRope: PUBLIC PROC [addrRope: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: BogusAddressEntry] = { this: Entry; IF Rope.IsEmpty[addrRope] THEN RETURN[NIL]; <> IF Rope.Fetch[addrRope, 0] # '[ THEN addrRope _ Rope.Cat["[", addrRope, "]"]; this _ Update[addrRope, bogusAddress, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.BogusAddressEntry => RETURN[e]; ENDCASE; }; UpdateDownServer: PUBLIC PROC [addr: Arpa.Address, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: DownServerEntry] = { this: Entry; addrRope: ROPE _ ArpaNameSupport.AddressToRope[addr]; --include brackets IF Rope.IsEmpty[addrRope] THEN RETURN[NIL]; this _ Update[addrRope, downServer, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.DownServerEntry => RETURN[e]; ENDCASE; }; UpdateDownServerRope: PUBLIC PROC [addrRope: ROPE, source: Arpa.Address, ttl: INT, auth: BOOL, data: REF ANY _ NIL] RETURNS [entry: DownServerEntry] = { this: Entry; IF Rope.IsEmpty[addrRope] THEN RETURN[NIL]; <> IF Rope.Fetch[addrRope, 0] # '[ THEN addrRope _ Rope.Cat["[", addrRope, "]"]; this _ Update[addrRope, downServer, source, ttl, auth, data]; WITH this SELECT FROM e: ArpaNameCache.DownServerEntry => RETURN[e]; ENDCASE; }; NewEntry: PROC [cache: CacheType] RETURNS [entry: Entry] ~ { RETURN[SELECT cache FROM name => NEW[name EntryRecord], alias => NEW[alias EntryRecord], mx => NEW[mx EntryRecord], zone => NEW[zone EntryRecord], address => NEW[address EntryRecord], soa => NEW[soa EntryRecord], downName => NEW[downName EntryRecord], downAddress => NEW[downAddress EntryRecord], downServer => NEW[downServer EntryRecord], bogusName => NEW[bogusName EntryRecord], bogusAddress => NEW[bogusAddress EntryRecord], ENDCASE => NIL ]; }; END.