/* * free (adj.): unencumbered; not under the control of others * Written by mihi in 2004 and released into the public domain * with no warranty of any kind, either expressed or implied. * It probably won't make your computer catch on fire, or eat * your children, but it might. Use at your own risk. */ package net.i2p.client.naming; import java.util.Locale; import java.util.Map; import java.util.Properties; import net.i2p.I2PAppContext; import net.i2p.client.I2PSessionException; import net.i2p.data.Destination; import net.i2p.util.LHMCache; import net.i2p.util.SystemVersion; /** * A Dummy naming service that can only handle base64 and b32 destinations. * * @since public since 0.9.31 */ public class DummyNamingService extends NamingService { protected static final int BASE32_HASH_LENGTH = 52; // 1 + Hash.HASH_LENGTH * 8 / 5 public final static String PROP_B32 = "i2p.naming.hostsTxt.useB32"; protected static final int CACHE_MAX_SIZE = SystemVersion.isAndroid() ? 32 : 128; public static final int DEST_SIZE = 516; // Std. Base64 length (no certificate) /** * The LRU cache, with no expiration time. * Classes should take care to call removeCache() for any entries that * are invalidated. */ private static final Map<String, Destination> _cache = new LHMCache<String, Destination>(CACHE_MAX_SIZE); /** * The naming service should only be constructed and accessed through the * application context. This constructor should only be used by the * appropriate application context itself. * */ protected DummyNamingService(I2PAppContext context) { super(context); } /** * @param hostname mixed case as it could be a key * @param lookupOptions input parameter, NamingService-specific, can be null * @param storedOptions output parameter, NamingService-specific, any stored properties will be added if non-null * @return dest or null * @since 0.8.7 */ @Override public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) { Destination d = getCache(hostname); if (d != null) return d; // If it's long, assume it's a key. if (hostname.length() >= 516) { d = lookupBase64(hostname); // What the heck, cache these too if (d != null) putCache(hostname, d); return d; } // Try Base32 decoding if (hostname.length() == BASE32_HASH_LENGTH + 8 && hostname.toLowerCase(Locale.US).endsWith(".b32.i2p") && _context.getBooleanPropertyDefaultTrue(PROP_B32)) { try { d = LookupDest.lookupBase32Hash(_context, hostname.substring(0, BASE32_HASH_LENGTH)); if (d != null) { putCache(hostname, d); return d; } } catch (I2PSessionException i2pse) { _log.warn("couldn't lookup b32",i2pse); } } return null; } /** * Provide basic static caching for all services * @param s case-sensitive, could be a hostname or a full b64 string */ protected static void putCache(String s, Destination d) { if (d == null) return; synchronized (_cache) { _cache.put(s, d); } } /** * @param s case-sensitive, could be a hostname or a full b64 string * @return cached dest or null */ protected static Destination getCache(String s) { synchronized (_cache) { return _cache.get(s); } } /** * @param s case-sensitive, could be a hostname or a full b64 string * @since 0.8.7 */ protected static void removeCache(String s) { synchronized (_cache) { _cache.remove(s); } } /** @since 0.8.1 */ protected static void clearCache() { synchronized (_cache) { _cache.clear(); } } }