ArpaNameCacheImpl.mesa
Copyright © 1987 by Xerox Corporation. All rights reserved.
John Larson, October 31, 1987 9:16:30 pm PST
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𡤀] = {
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: BOOLTRUE]
RETURNS [found: BOOLFALSE, expired: BOOLFALSE, 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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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: BOOLTRUE]
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 ANYNIL] 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.