<> <> <> <> DIRECTORY BasicTime USING [GMT, Now, Period, Update], Rope USING [Cat, Equal, Length, Match, ROPE], IPDefs USING [Address], IPNameCache, IPNameSupport USING [MakeAddressInList, MakeRopeInList]; IPNameCacheImpl: CEDAR MONITOR IMPORTS BasicTime, Rope, IPNameSupport EXPORTS IPNameCache = BEGIN OPEN IPNameCache; ROPE: TYPE = Rope.ROPE; <<-- noticeable default ttl>> ttlDefault: INT = 3333; ZapWholeCache: PUBLIC ENTRY PROC = { names _ NIL; aliases _ NIL; mxList _ NIL; bogusAddresses _ NIL; bogusNames _ NIL; addresses _ NIL; downNames _ NIL; downAddresses _ NIL; downServers _ NIL; zones _ NIL; histograms _ NIL; }; <<>> <> names: LIST OF NameEntry _ NIL; GetNames: PUBLIC ENTRY PROC RETURNS [LIST OF NameEntry] = { RETURN[names]; }; NameLookup: PUBLIC ENTRY PROC [name: ROPE] RETURNS [entry: NameEntry] = {RETURN[NameLookupInternal[name]]}; NameLookupInternal: PROC [name: ROPE] RETURNS [entry: NameEntry] = { FOR list: LIST OF NameEntry _ names, list.rest UNTIL list = NIL DO entry _ list.first; IF Rope.Equal[entry.name, name, FALSE] THEN { entry.referenced _ BasicTime.Now[]; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateName: PUBLIC ENTRY PROC [ name: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: NameEntry] = { entry _ NameLookupInternal[name]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN entry.authoritative _ FALSE; IF entry.authoritative AND ~authoritative THEN RETURN[NIL]; IF ~entry.authoritative AND authoritative THEN { <> entry.addresses _ NIL; }; entry.source _ source; entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; entry.authoritative _ authoritative; RETURN[entry]; }; entry _ MakeNameEntry[source, ttl, authoritative]; entry.name _ name; RETURN[entry]; }; MakeNameEntry: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: NameEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[NameRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl, source: source, authoritative: authoritative ]; names _ CONS[entry, names]; }; AddAddressToName: PUBLIC ENTRY PROC [entry: NameEntry, address: IPDefs.Address] = { entry.addresses _ IPNameSupport.MakeAddressInList[entry.addresses, address]; }; <<>> <> aliases: LIST OF AliasEntry _ NIL; GetAliases: PUBLIC ENTRY PROC RETURNS [LIST OF AliasEntry] = { RETURN[aliases]; }; AliasLookup: PUBLIC ENTRY PROC [alias: ROPE] RETURNS [entry: AliasEntry] = {RETURN[AliasLookupInternal[alias]]}; AliasLookupInternal: PROC [alias: ROPE] RETURNS [entry: AliasEntry] = { FOR list: LIST OF AliasEntry _ aliases, list.rest UNTIL list = NIL DO entry _ list.first; IF Rope.Equal[entry.alias, alias, FALSE] THEN { entry.referenced _ BasicTime.Now[]; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateAlias: PUBLIC ENTRY PROC [ alias: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: AliasEntry] = { entry _ AliasLookupInternal[alias]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN entry.authoritative _ FALSE; IF entry.authoritative AND ~authoritative THEN RETURN[NIL]; IF ~entry.authoritative AND authoritative THEN { <> entry.name _ NIL; }; entry.source _ source; entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; entry.authoritative _ authoritative; RETURN[entry]; }; entry _ MakeAliasEntry[source, ttl, authoritative]; entry.alias _ alias; RETURN[entry]; }; MakeAliasEntry: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: AliasEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[AliasRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl, source: source, authoritative: authoritative ]; aliases _ CONS[entry, aliases]; }; AddNameToAlias: PUBLIC ENTRY PROC [entry: AliasEntry, name: ROPE] = { entry.name _ name; }; <> mxList: LIST OF MXEntry _ NIL; GetMXList: PUBLIC ENTRY PROC RETURNS [LIST OF MXEntry] = { RETURN[mxList]; }; MXLookup: PUBLIC ENTRY PROC [name: ROPE] RETURNS [entry: MXEntry] = {RETURN[MXLookupInternal[name]]}; MXLookupInternal: PROC [name: ROPE] RETURNS [entry: MXEntry] = { FOR list: LIST OF MXEntry _ mxList, list.rest UNTIL list = NIL DO entry _ list.first; IF Rope.Equal[entry.name, name, FALSE] THEN { entry.referenced _ BasicTime.Now[]; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateMX: PUBLIC ENTRY PROC [ name: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: MXEntry] = { entry _ MXLookupInternal[name]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN entry.authoritative _ FALSE; IF entry.authoritative AND ~authoritative THEN RETURN[NIL]; IF ~entry.authoritative AND authoritative THEN { <> entry.mxHosts _ NIL; }; entry.source _ source; entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; entry.authoritative _ authoritative; RETURN[entry]; }; entry _ MakeMXEntry[source, ttl, authoritative]; entry.name _ name; RETURN[entry]; }; MakeMXEntry: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: MXEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[MXRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl, source: source, authoritative: authoritative ]; mxList _ CONS[entry, mxList]; }; AddHostToMX: PUBLIC ENTRY PROC [entry: MXEntry, hostInfo: MXHostInfo] = { IF ~AlreadyInMXList[entry.mxHosts, hostInfo] THEN entry.mxHosts _ CONS[hostInfo, entry.mxHosts]; }; AlreadyInMXList: PROC[mxHosts: LIST OF MXHostInfo, hostInfo: MXHostInfo] RETURNS[BOOL] = { FOR list: LIST OF MXHostInfo _ mxHosts, list.rest UNTIL list = NIL DO IF Rope.Equal[list.first.host, hostInfo.host, FALSE] AND list.first.preference = hostInfo.preference THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; <> bogusNames: LIST OF BogusNameEntry _ NIL; GetBogusNames: PUBLIC ENTRY PROC RETURNS [LIST OF BogusNameEntry] = { RETURN[bogusNames]; }; BogusNameLookup: PUBLIC ENTRY PROC [bogus: ROPE] RETURNS [entry: BogusNameEntry] = {RETURN[BogusNameLookupInternal[bogus]]}; BogusNameLookupInternal: PROC [bogus: ROPE] RETURNS [entry: BogusNameEntry] = { FOR list: LIST OF BogusNameEntry _ bogusNames, list.rest UNTIL list = NIL DO entry _ list.first; IF Rope.Equal[entry.bogus, bogus, FALSE] THEN { entry.referenced _ BasicTime.Now[]; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateBogusName: PUBLIC ENTRY PROC [ bogus: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: BogusNameEntry] = { entry _ BogusNameLookupInternal[bogus]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN entry.authoritative _ FALSE; IF entry.authoritative AND ~authoritative THEN RETURN[NIL]; IF ~entry.authoritative AND authoritative THEN { <> NULL; }; entry.source _ source; entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; entry.authoritative _ authoritative; RETURN[entry]; }; entry _ MakeBogusName[source, ttl, authoritative]; entry.bogus _ bogus; RETURN[entry]; }; MakeBogusName: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: BogusNameEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[BogusNameRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl, source: source, authoritative: authoritative ]; bogusNames _ CONS[entry, bogusNames]; }; <> downNames: LIST OF DownNameEntry _ NIL; GetDownNames: PUBLIC ENTRY PROC RETURNS [LIST OF DownNameEntry] = { RETURN[downNames]; }; DownNameLookup: PUBLIC ENTRY PROC [name: ROPE] RETURNS [entry: DownNameEntry] = { entry _ DownNameLookupInternal[name]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN RETURN[NIL];}; -- Don't show expired items RETURN[entry]}; DownNameLookupInternal: PROC [name: ROPE] RETURNS [entry: DownNameEntry] = { FOR list: LIST OF DownNameEntry _ downNames, list.rest UNTIL list = NIL DO entry _ list.first; IF Rope.Equal[entry.name, name, FALSE] THEN { entry.referenced _ BasicTime.Now[]; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateDownName: PUBLIC ENTRY PROC [ name: ROPE, ttl: INT] RETURNS [entry: DownNameEntry] = { entry _ DownNameLookupInternal[name]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl > -10 THEN RETURN[NIL]; -- Discard old info entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; RETURN[entry]; }; entry _ MakeDownName[ttl]; entry.name _ name; RETURN[entry]; }; MakeDownName: PROC [ttl: INT] RETURNS [entry: DownNameEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[DownNameRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl ]; downNames _ CONS[entry, downNames]; }; <
> addresses: LIST OF AddressEntry _ NIL; GetAddresses: PUBLIC ENTRY PROC RETURNS [LIST OF AddressEntry] = { RETURN[addresses]; }; AddressLookup: PUBLIC ENTRY PROC [address: IPDefs.Address] RETURNS [entry: AddressEntry] = {RETURN[AddressLookupInternal[address]]}; AddressLookupInternal: PROC [address: IPDefs.Address] RETURNS [entry: AddressEntry] = { FOR list: LIST OF AddressEntry _ addresses, list.rest UNTIL list = NIL DO entry _ list.first; IF entry.address = address THEN { entry.referenced _ BasicTime.Now[]; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateAddress: PUBLIC ENTRY PROC [ address: IPDefs.Address, source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: AddressEntry] = { entry _ AddressLookupInternal[address]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN entry.authoritative _ FALSE; IF entry.authoritative AND ~authoritative THEN RETURN[NIL]; IF ~entry.authoritative AND authoritative THEN { <> entry.names _ NIL; }; entry.source _ source; entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; entry.authoritative _ authoritative; RETURN[entry]; }; entry _ MakeAddressEntry[source, ttl, authoritative]; entry.address _ address; RETURN[entry]; }; MakeAddressEntry: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: AddressEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[AddressRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl, source: source, authoritative: authoritative]; addresses _ CONS[entry, addresses]; }; AddNameToAddress: PUBLIC ENTRY PROC [entry: AddressEntry, name: ROPE] = { entry.names _ IPNameSupport.MakeRopeInList[entry.names, name]; }; <<>> <> bogusAddresses: LIST OF BogusAddressEntry _ NIL; GetBogusAddresses: PUBLIC ENTRY PROC RETURNS [LIST OF BogusAddressEntry] = { RETURN[bogusAddresses]; }; BogusAddressLookup: PUBLIC ENTRY PROC [bogus: IPDefs.Address] RETURNS [entry: BogusAddressEntry] = {RETURN[BogusAddressLookupInternal[bogus]]}; BogusAddressLookupInternal: PROC [bogus: IPDefs.Address] RETURNS [entry: BogusAddressEntry] = { FOR list: LIST OF BogusAddressEntry _ bogusAddresses, list.rest UNTIL list = NIL DO entry _ list.first; IF entry.bogus = bogus THEN { entry.referenced _ BasicTime.Now[]; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateBogusAddress: PUBLIC ENTRY PROC [ bogus: IPDefs.Address, source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: BogusAddressEntry] = { entry _ BogusAddressLookupInternal[bogus]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN entry.authoritative _ FALSE; IF entry.authoritative AND ~authoritative THEN RETURN[NIL]; IF ~entry.authoritative AND authoritative THEN { <> NULL; }; entry.source _ source; entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; entry.authoritative _ authoritative; RETURN[entry]; }; entry _ MakeBogusAddress[source, ttl, authoritative]; entry.bogus _ bogus; RETURN[entry]; }; MakeBogusAddress: PROC [ source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: BogusAddressEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[BogusAddressRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl, source: source, authoritative: authoritative, bogus: TRASH ]; bogusAddresses _ CONS[entry, bogusAddresses]; }; <> downAddresses: LIST OF DownAddressEntry _ NIL; GetDownAddresses: PUBLIC ENTRY PROC RETURNS [LIST OF DownAddressEntry] = { RETURN[downAddresses]; }; DownAddressLookup: PUBLIC ENTRY PROC [address: IPDefs.Address] RETURNS [entry: DownAddressEntry] = { entry _ DownAddressLookupInternal[address]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN RETURN[NIL];}; -- Don't show expired items RETURN[entry]}; DownAddressLookupInternal: PROC [address: IPDefs.Address] RETURNS [entry: DownAddressEntry] = { FOR list: LIST OF DownAddressEntry _ downAddresses, list.rest UNTIL list = NIL DO entry _ list.first; IF entry.address = address THEN { entry.referenced _ BasicTime.Now[]; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateDownAddress: PUBLIC ENTRY PROC [address: IPDefs.Address, ttl: INT] RETURNS [entry: DownAddressEntry] = { entry _ DownAddressLookupInternal[address]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl > -10 THEN RETURN[NIL]; -- Discard old info entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; RETURN[entry]; }; entry _ MakeDownAddress[ttl]; entry.address _ address; RETURN[entry]; }; MakeDownAddress: PROC [ttl: INT] RETURNS [entry: DownAddressEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[DownAddressRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl, address: TRASH ]; downAddresses _ CONS[entry, downAddresses]; }; <> <<>> downServers: LIST OF DownServerEntry _ NIL; GetDownServers: PUBLIC ENTRY PROC RETURNS [LIST OF DownServerEntry] = { RETURN[downServers]; }; DownServerLookup: PUBLIC ENTRY PROC [address: IPDefs.Address] RETURNS [entry: DownServerEntry] = { entry _ DownServerLookupInternal[address]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN RETURN[NIL];}; -- Don't show expired items RETURN[entry]}; DownServerLookupInternal: PROC [address: IPDefs.Address] RETURNS [entry: DownServerEntry] = { FOR list: LIST OF DownServerEntry _ downServers, list.rest UNTIL list = NIL DO entry _ list.first; IF entry.address = address THEN { entry.referenced _ BasicTime.Now[]; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateDownServer: PUBLIC ENTRY PROC [ address: IPDefs.Address, ttl: INT] RETURNS [entry: DownServerEntry] = { entry _ DownServerLookupInternal[address]; IF entry # NIL THEN { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT = BasicTime.Period[from: now, to: entry.expires]; IF thisTtl > -10 THEN RETURN[NIL]; -- Discard old info entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; RETURN[entry]; }; entry _ MakeDownServer[ttl]; entry.address _ address; RETURN[entry]; }; MakeDownServer: PROC [ttl: INT] RETURNS [entry: DownServerEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[DownServerRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl, address: TRASH ]; downServers _ CONS[entry, downServers]; }; <> zones: LIST OF ZoneEntry _ NIL; GetZones: PUBLIC ENTRY PROC RETURNS [LIST OF ZoneEntry] = { RETURN[zones]; }; GetZone: PUBLIC ENTRY PROC [name: ROPE] RETURNS [entry: ZoneEntry] = { bestEntry: ZoneEntry _ NIL; FOR list: LIST OF ZoneEntry _ zones, list.rest UNTIL list = NIL DO entry _ list.first; IF Rope.Match[Rope.Cat["*", entry.zone], name, FALSE] THEN { IF bestEntry = NIL THEN bestEntry _ entry ELSE IF Rope.Length[bestEntry.zone] < Rope.Length[entry.zone] THEN bestEntry _ entry}; ENDLOOP; IF bestEntry # NIL THEN bestEntry.zoneLookup _ bestEntry.zoneLookup + 1; RETURN[bestEntry]; }; ZoneLookup: PUBLIC ENTRY PROC [zone: ROPE] RETURNS [entry: ZoneEntry] = { RETURN[ZoneLookupInternal[zone]]; }; ZoneLookupInternal: PROC [zone: ROPE] RETURNS [entry: ZoneEntry] = { FOR list: LIST OF ZoneEntry _ zones, list.rest UNTIL list = NIL DO entry _ list.first; IF Rope.Equal[entry.zone, zone, FALSE] THEN { entry.zoneLookup _ entry.zoneLookup + 1; RETURN; }; ENDLOOP; RETURN[NIL]; }; UpdateZone: PUBLIC ENTRY PROC [ name: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: ZoneEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; thisTtl: INT; entry _ ZoneLookupInternal[name]; IF entry # NIL THEN { thisTtl _ BasicTime.Period[from: now, to: entry.expires]; IF thisTtl < -10 THEN entry.authoritative _ FALSE; IF entry.authoritative AND ~authoritative THEN RETURN[NIL]; IF ~entry.authoritative AND authoritative THEN { <> entry.servers _ NIL; }; entry.source _ source; entry.loaded _ now; entry.referenced _ now; entry.expires _ BasicTime.Update[now, ttl]; entry.ttl _ ttl; entry.authoritative _ authoritative; entry.zone _ name; RETURN[entry]; }; entry _ MakeZoneEntry[source, ttl, authoritative]; entry.zone _ name; RETURN[entry]; }; AddServer: PUBLIC ENTRY PROC [entry: ZoneEntry, server: ROPE] = { entry.servers _ IPNameSupport.MakeRopeInList[entry.servers, server]; }; MakeZoneEntry: PROC [source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: ZoneEntry] = { now: BasicTime.GMT _ BasicTime.Now[]; expires: INT _ ttl; IF expires = 0 THEN expires _ ttlDefault; entry _ NEW[ZoneRecord]; entry^ _ [ loaded: now, referenced: now, expires: BasicTime.Update[now, expires], ttl: ttl, source: source, authoritative: authoritative ]; zones _ CONS[entry, zones]; }; histograms: LIST OF HistogramEntry _ NIL; GetHistograms: PUBLIC ENTRY PROC RETURNS [LIST OF HistogramEntry] = { RETURN[histograms]; }; AddToCacheHits: PUBLIC ENTRY PROC [server: IPDefs.Address, type: IPNameCache.CacheType] = { histogram: HistogramEntry _ FindHistogram[server]; histogram.cacheHits[type] _ histogram.cacheHits[type].SUCC; }; AddToProbes: PUBLIC ENTRY PROC [server: IPDefs.Address, type: IPNameCache.ProbeType] = { histogram: HistogramEntry _ FindHistogram[server]; histogram.probes[type] _ histogram.probes[type].SUCC; }; AddToLost: PUBLIC ENTRY PROC [server: IPDefs.Address] = { histogram: HistogramEntry _ FindHistogram[server]; histogram.lost _ histogram.lost.SUCC; }; AddToCounter: PUBLIC ENTRY PROC [server: IPDefs.Address, ms: INT] = { histogram: HistogramEntry _ FindHistogram[server]; index: INT; ms _ ms + IPNameCache.histogramSlotSize - 1; index _ ms/IPNameCache.histogramSlotSize; IF index >= IPNameCache.histogramSlots THEN index _ IPNameCache.histogramSlots-1; histogram.counters[index] _ histogram.counters[index].SUCC; }; FindHistogram: PROC [server: IPDefs.Address] RETURNS[ histogram: HistogramEntry] = { FOR list: LIST OF HistogramEntry _ histograms, list.rest UNTIL list = NIL DO histogram _ list.first; IF histogram.server = server THEN EXIT; REPEAT FINISHED => { histogram _ NEW[HistogramRecord]; histogram^ _ [ server: server, counters: ALL[0] ]; histograms _ CONS[histogram, histograms]; }; ENDLOOP; }; END.