Extracted from CommSystemFacadeImpl (2026-09-06) so the country cluster - a per-peer country cache with periodic cleanup, over-capacity eviction, strict-country gating, and startup GeoIP queueing - lives apart from the facade core. The facade retains thin delegation stubs so the public static and commSystem() APIs are unchanged.
All pure decision logic (cache eviction decisions, memory-independent helpers) is exposed as package-visible static methods so it can be tested without a running router; see CountryLookupDecisionTest.
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate classPeriodic job looking up the new routers' countries.private classThis takes too long to run on the SimpleTimer2 queue.private classCollect the IPs for all routers in the DB, and queue them for lookup, then fire off the periodic lookup task for the first time.Field Summary
FieldsModifier and TypeFieldDescriptionprivate final RouterContextThe router context.private final GeoIPThe GeoIP databases.private final LogLogger for the country lookup.private static final longAge after which a cached country expires.private final ConcurrentHashMap<Hash, String> The cached countries, by router hash.private final ConcurrentHashMap<Hash, Long> When each cached country was stored.private static final PatternPre-compiled dot split for domain parsing.private longWhen the country cache was last cleaned up.private longWhen the unknown-country entries were last purged.private static final intTime allowed for one lookup run.private static final intMost routers cached with a country.Multi-part TLD list for domain extraction.private static final intInterval between the lookup runs, re-queueing the whole net DB so peers learned after startup are resolved even if their page is never viewed explicitly.private static final intDelay before the first lookup run, hoping the router infos are read in by then, though that is not required.Constructor Summary
ConstructorsConstructorDescriptionCountryLookup(RouterContext ctx, GeoIP geoIP) Create a lookup over the netDb's router IPs, backed by the GeoIP database.Method Summary
Modifier and TypeMethodDescriptionprivate voidClean up stale entries from the country cache.(package private) static intRemove stale and unresolved ("xx") entries from the country cache.static byte[]IP address compatible with our capabilities (IPv4/IPv6).Provides country code mappings.getCountry(String ip) The two-letter country code for an IP address string.getCountry(Hash peer) Uses the transport IP first because that lookup is fast, then the IP from the netDb.private StringgetCountryFromIPAddress(String ipAddress) Convert IP string to Hash and call existing getCountry method Return two-letter country code or null if unknown.Full name for a country code, or the code if we don't know the name.static StringDomain name from a reverse DNS hostname.(package private) static byte[]getFirstValidIPOfType(RouterInfo ri, boolean wantIPv6) First valid IP of the specified type (IPv4 or IPv6).(package private) static byte[]getIP(RouterInfo ri) Return first IP (v4 or v6) we find, any transport.Country code for this router, from the GeoIP lookup.static byte[]getValidIP(RouterInfo ri) Return first valid IP (v4 or v6) we find, any transport.booleanAre we in a strict country.booleanisInStrictCountry(Hash peer) Are they in a strict country.booleanAre they in a strict country.(package private) static booleanisUnknownCountryCode(String code) True when the cache stores an unresolved-country marker ("xx").voidqueueLookup(byte[] ip) Queues a GeoIP lookup for the given IP.voidstart()Collect the IPs for all routers in the DB and queue them for lookup.(package private) static booleanCheck if we support outbound IPv4 connections.(package private) static booleanCheck if we support outbound IPv6 connections.(package private) static voidtrimToCapacity(Map<Hash, String> cache, Map<Hash, Long> timestamps, long now, long expiryMs, int maxSize) Bring an over-capacity country cache back under its size bound.
Field Details
_context
The router context._geoIP
The GeoIP databases._log
Logger for the country lookup.START_DELAY
private static final int START_DELAYDelay before the first lookup run, hoping the router infos are read in by then, though that is not required.LOOKUP_TIME
QUEUE_TIME
private static final int QUEUE_TIMEInterval between the lookup runs, re-queueing the whole net DB so peers learned after startup are resolved even if their page is never viewed explicitly.- See Also:
MAX_COUNTRY_CACHE_SIZE
private static final int MAX_COUNTRY_CACHE_SIZEMost routers cached with a country.- See Also:
COUNTRY_CACHE_EXPIRY
private static final long COUNTRY_CACHE_EXPIRYAge after which a cached country expires.- See Also:
lastUnknownPurge
private long lastUnknownPurgeWhen the unknown-country entries were last purged.lastCacheCleanup
private long lastCacheCleanupWhen the country cache was last cleaned up.countryCache
The cached countries, by router hash.countryCacheTimestamps
When each cached country was stored.DOT_SPLIT
Pre-compiled dot split for domain parsing.MULTI_PART_TLDS
Constructor Details
CountryLookup
Create a lookup over the netDb's router IPs, backed by the GeoIP database.- Parameters:
ctx- non-nullgeoIP- non-null
Method Details
start
public void start()Collect the IPs for all routers in the DB and queue them for lookup. The recurring lookup pipeline starts on the first pass only.queueLookup
public void queueLookup(byte[] ip) Queues a GeoIP lookup for the given IP.- Parameters:
ip- ipv4 or ipv6
getOurCountry
Country code for this router, from the GeoIP lookup.- Returns:
- two-letter lower-case country code or null
isInStrictCountry
public boolean isInStrictCountry()Are we in a strict country.- Returns:
- whether in strict country
isInStrictCountry
Are they in a strict country. Not recommended for our local router hash, as we may not be either in the cache or netdb, or may not be publishing an IP.- Parameters:
peer- non-null- Returns:
- whether in strict country
isInStrictCountry
Are they in a strict country.- Parameters:
ri- non-null- Returns:
- whether in strict country
getCountry
Uses the transport IP first because that lookup is fast, then the IP from the netDb. Not recommended for our local router hash, as we may not be either in the cache or netdb, or may not be publishing an IP.As of 0.9.32, works only for literal IPs, returns null for hostnames.
- Parameters:
peer- not ourselves - usegetOurCountry()for that- Returns:
- two-letter lower-case country code or xx for non-banned peers, or null otherwise
getCountry
getCountryFromIPAddress
cleanupCountryCache
private void cleanupCountryCache()Clean up stale entries from the country cache.getCountryName
getCountries
getDomain
Domain name from a reverse DNS hostname.Multi-part TLDs (co.uk, com.au, ...) are recognized so the registrable domain is returned rather than a bare second-level label.
- Parameters:
hostname- the reverse DNS host name to reduce to its registrable domain- Returns:
- domain name only from reverse dns hostname lookups
getIP
Return first IP (v4 or v6) we find, any transport. Not validated, may be local, etc.As of 0.9.32, works only for literal IPs, returns null for host names.
- Parameters:
ri- the RouterInfo whose addresses are scanned for a literal IP- Returns:
- IP or null
getValidIP
Return first valid IP (v4 or v6) we find, any transport. Local and other invalid IPs will not be returned.As of 0.9.32, works only for literal IPs, returns null for host names.
- Parameters:
ri- the RouterInfo whose addresses are scanned for a publicly routable IP- Returns:
- IP or null
getCompatibleIP
IP address compatible with our capabilities (IPv4/IPv6). Prefers IPv4 if we support it.- Parameters:
ri- RouterInfo to get IP from- Returns:
- IP or null
getFirstValidIPOfType
First valid IP of the specified type (IPv4 or IPv6).- Parameters:
ri- the RouterInfo whose addresses are scannedwantIPv6- true to accept a 16 byte address, false to accept a 4 byte one- Returns:
- the first valid IP of type
supportsIPv4
Check if we support outbound IPv4 connections.- Parameters:
ctx- the router context supplying the transport enablement properties- Returns:
- true when NTCP or UDP is enabled, so an outbound IPv4 connection is possible
supportsIPv6
Check if we support outbound IPv6 connections.- Parameters:
ctx- the router context supplying the transport enablement properties- Returns:
- true when neither NTCP nor UDP has IPv6 explicitly disabled
evictExpired
Remove stale and unresolved ("xx") entries from the country cache.An entry is expired when its timestamp is strictly older than
expiryMs; "xx" (unresolved) entries are always dropped. Called both periodically fromgetCountry(Hash)and as the first stage oftrimToCapacity(Map, Map, long, long, int)so the hot path never recomputes the loop.- Parameters:
cache- country cache to drain (entries removed in place)timestamps- parallel timestamp map for the same keysnow- cache age reference in millisexpiryMs- age threshold in millis (strict>)- Returns:
- number of entries removed
trimToCapacity
static void trimToCapacity(Map<Hash, String> cache, Map<Hash, Long> timestamps, long now, long expiryMs, int maxSize) Bring an over-capacity country cache back under its size bound.First advances the expired-entry pass via
evictExpired(Map, Map, long, long); if still at or abovemaxSize, drops the oldest quarter by timestamp. The redundant removeIf()/stream cascade in the original facade is preserved, so hot-path behavior (evict expired first, then oldest) is unchanged.- Parameters:
cache- country cache to shrink (entries removed in place)timestamps- parallel timestamp map for the same keysnow- cache age reference in millisexpiryMs- age threshold in millis for the expired-entry passmaxSize- size bound that triggers trimming
isUnknownCountryCode
True when the cache stores an unresolved-country marker ("xx").- Parameters:
code- the cached country name to test- Returns:
- true for the unresolved "xx" marker, and for a null code