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𡤀] = {
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;
Enforce use of brackets in address type keys
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;
Enforce use of brackets in address type keys
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;
Enforce use of brackets in address type keys
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;
Enforce use of brackets in address type keys
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];
};
Enforce use of brackets in address type keys
IF cache
IN[address..downServer]
AND Rope.Fetch[key, 0] # '[
THEN
key ← Rope.Cat["[", key, "]"];
SymTab.Update[table, key, Action];
Cache housekeeping
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];
Enforce use of brackets in address type keys
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];
Enforce use of brackets in address type keys
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];
Enforce use of brackets in address type keys
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];
Enforce use of brackets in address type keys
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.