diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index f8177c2810..f45327e93c 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHashMap; import net.i2p.I2PAppContext; import net.i2p.I2PException; +import net.i2p.client.I2PSession; import net.i2p.client.naming.NamingService; import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PSocketManager; @@ -34,6 +35,7 @@ import net.i2p.data.Base64; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; +import net.i2p.data.Hash; import net.i2p.util.EventDispatcher; import net.i2p.util.FileUtil; import net.i2p.util.Log; @@ -799,7 +801,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn // If the host is "i2p", the getHostName() lookup failed, don't try to // look it up again as the naming service does not do negative caching // so it will be slow. - Destination clientDest; + Destination clientDest = null; String addressHelper = addressHelpers.get(destination.toLowerCase()); if (addressHelper != null) { clientDest = _context.namingService().lookup(addressHelper); @@ -808,6 +810,21 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn addressHelpers.remove(destination.toLowerCase()); } else if ("i2p".equals(host)) { clientDest = null; + } else if (destination.length() == 60 && destination.toLowerCase().endsWith(".b32.i2p")) { + // use existing session to look up for efficiency + verifySocketManager(); + I2PSession sess = sockMgr.getSession(); + if (sess != null && !sess.isClosed()) { + byte[] hData = Base32.decode(destination.substring(0, 52)); + if (hData != null) { + if (_log.shouldLog(Log.INFO)) + _log.info("lookup in-session " + destination); + Hash hash = Hash.create(hData); + clientDest = sess.lookupDest(hash, 20*1000); + } + } else { + clientDest = _context.namingService().lookup(destination); + } } else { clientDest = _context.namingService().lookup(destination); } @@ -822,7 +839,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN); else if (ahelperPresent) header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN); - else if (destination.length() == 60 && destination.endsWith(".b32.i2p")) + else if (destination.length() == 60 && destination.toLowerCase().endsWith(".b32.i2p")) header = getErrorPage("dnf", ERR_DESTINATION_UNKNOWN); else { header = getErrorPage("dnfh", ERR_DESTINATION_UNKNOWN); diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index 04dde2050e..d43058db66 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -18,6 +18,7 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; @@ -140,6 +141,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa private long _lastActivity; private boolean _isReduced; + /** + * @since 0.8.9 + */ + private static final LookupCache _lookupCache = new LookupCache(16); + /** SSL interface (only) @since 0.8.3 */ protected static final String PROP_ENABLE_SSL = "i2cp.SSL"; @@ -809,6 +815,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa /** called by the message handler */ void destReceived(Destination d) { Hash h = d.calculateHash(); + synchronized (_lookupCache) { + _lookupCache.put(h, d); + } for (LookupWaiter w : _pendingLookups) { if (w.hash.equals(h)) { w.destination = d; @@ -872,6 +881,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa * @return null on failure */ public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException { + synchronized (_lookupCache) { + Destination rv = _lookupCache.get(h); + if (rv != null) + return rv; + } if (_closed) return null; LookupWaiter waiter = new LookupWaiter(h); @@ -952,4 +966,21 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa buf.append(getPrefix()); return buf.toString(); } + + /** + * @since 0.8.9 + */ + private static class LookupCache extends LinkedHashMap { + private final int _max; + + public LookupCache(int max) { + super(max, 0.75f, true); + _max = max; + } + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > _max; + } + } } diff --git a/core/java/src/net/i2p/client/naming/LookupDest.java b/core/java/src/net/i2p/client/naming/LookupDest.java index e412f20eda..c8b960cc6c 100644 --- a/core/java/src/net/i2p/client/naming/LookupDest.java +++ b/core/java/src/net/i2p/client/naming/LookupDest.java @@ -21,7 +21,8 @@ import net.i2p.data.Hash; * Obviously this can take a while. * * All calls are blocking and return null on failure. - * Timeout is set to 10 seconds in I2PSimpleSession. + * Timeout is 15 seconds. + * To do: Add methods that allow specifying the timeout. * * As of 0.8.3, standard I2PSessions support lookups, * including multiple lookups in parallel, and overriding @@ -32,6 +33,8 @@ import net.i2p.data.Hash; */ class LookupDest { + private static final long DEFAULT_TIMEOUT = 15*1000; + protected LookupDest(I2PAppContext context) {} /** @param key 52 chars (do not include the .b32.i2p suffix) */ @@ -67,7 +70,7 @@ class LookupDest { opts.put(I2PClient.PROP_TCP_PORT, s); I2PSession session = client.createSession(null, opts); session.connect(); - rv = session.lookupDest(key); + rv = session.lookupDest(key, DEFAULT_TIMEOUT); session.destroySession(); } catch (I2PSessionException ise) {} return rv; diff --git a/history.txt b/history.txt index f46843576b..1f5fc3c543 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,9 @@ +2011-08-30 zzz + * I2CP: Cache b32 lookups client-side + * I2PTunnelHTTPClient: Use existing session for b32 lookups + rather than a new SimpleSession + * Naming: Increase b32 lookup timeout to 15 sec. + 2011-08-29 zzz * NetDB: - Replace the old parallel lookup method with a true diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index f6e6df3a5c..4e28a2c8d2 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 4; + public final static long BUILD = 5; /** for example "-test" */ public final static String EXTRA = "";