* Tunnels:

- Don't use peers < 0.7.9 for tunnels due to the old
        message corruption bugs
      - Javadoc
      - Cleanups
This commit is contained in:
zzz
2010-10-02 14:56:45 +00:00
parent 939dcee537
commit ed4c09b456
8 changed files with 99 additions and 50 deletions

View File

@ -24,7 +24,7 @@ public class BuildMessageProcessor {
public BuildMessageProcessor(I2PAppContext ctx) {
_filter = new DecayingHashSet(ctx, 60*1000, 32, "TunnelBMP");
ctx.statManager().createRateStat("tunnel.buildRequestDup", "How frequently we get dup build request messages", "Tunnels", new long[] { 60*1000, 10*60*1000 });
ctx.statManager().createRateStat("tunnel.buildRequestDup", "How frequently we get dup build request messages", "Tunnels", new long[] { 60*60*1000 });
}
/**
* Decrypt the record targetting us, encrypting all of the other records with the included

View File

@ -15,17 +15,19 @@ import net.i2p.util.Log;
*
*/
public class InboundEndpointProcessor {
private RouterContext _context;
private Log _log;
private TunnelCreatorConfig _config;
private IVValidator _validator;
private final RouterContext _context;
private final Log _log;
private final TunnelCreatorConfig _config;
private final IVValidator _validator;
static final boolean USE_ENCRYPTION = HopProcessor.USE_ENCRYPTION;
private static final ByteCache _cache = ByteCache.getInstance(128, HopProcessor.IV_LENGTH);
/** @deprecated unused */
public InboundEndpointProcessor(RouterContext ctx, TunnelCreatorConfig cfg) {
this(ctx, cfg, DummyValidator.getInstance());
}
public InboundEndpointProcessor(RouterContext ctx, TunnelCreatorConfig cfg, IVValidator validator) {
_context = ctx;
_log = ctx.logManager().getLog(InboundEndpointProcessor.class);
@ -84,6 +86,9 @@ public class InboundEndpointProcessor {
return true;
}
/**
* Iteratively undo the crypto that the various layers in the tunnel added.
*/
private void decrypt(RouterContext ctx, TunnelCreatorConfig cfg, byte iv[], byte orig[], int offset, int length) {
Log log = ctx.logManager().getLog(OutboundGatewayProcessor.class);
ByteArray ba = _cache.acquire();

View File

@ -14,9 +14,9 @@ import net.i2p.util.Log;
*
*/
public class OutboundGatewayProcessor {
private I2PAppContext _context;
private Log _log;
private TunnelCreatorConfig _config;
private final I2PAppContext _context;
private final Log _log;
private final TunnelCreatorConfig _config;
static final boolean USE_ENCRYPTION = HopProcessor.USE_ENCRYPTION;
private static final ByteCache _cache = ByteCache.getInstance(128, HopProcessor.IV_LENGTH);
@ -54,10 +54,8 @@ public class OutboundGatewayProcessor {
}
/**
* Undo the crypto that the various layers in the tunnel added. This is used
* by both the outbound gateway (preemptively undoing the crypto peers will add)
* and by the inbound endpoint.
*
* Iteratively undo the crypto that the various layers in the tunnel added. This is used
* by the outbound gateway (preemptively undoing the crypto peers will add).
*/
private void decrypt(I2PAppContext ctx, TunnelCreatorConfig cfg, byte iv[], byte orig[], int offset, int length) {
Log log = ctx.logManager().getLog(OutboundGatewayProcessor.class);
@ -73,6 +71,11 @@ public class OutboundGatewayProcessor {
_cache.release(ba);
}
/**
* Undo the crypto for a single hop. This is used
* by both the outbound gateway (preemptively undoing the crypto peers will add)
* and by the inbound endpoint.
*/
static void decrypt(I2PAppContext ctx, byte iv[], byte orig[], int offset, int length, byte cur[], HopConfig config) {
// update the IV for the previous (next?) hop
ctx.aes().decryptBlock(orig, offset, config.getIVKey(), orig, offset);

View File

@ -60,7 +60,6 @@ public class TunnelGateway {
_preprocessor = preprocessor;
_sender = sender;
_receiver = receiver;
_messagesSent = 0;
_flushFrequency = 500;
_delayedFlush = new DelayedFlush();
_lastFlush = _context.clock().now();
@ -128,8 +127,8 @@ public class TunnelGateway {
FlushTimer.getInstance().addEvent(_delayedFlush, delayAmount);
}
_context.statManager().addRateData("tunnel.lockedGatewayAdd", afterAdded-beforeLock, remaining);
long complete = System.currentTimeMillis();
if (_log.shouldLog(Log.DEBUG))
if (_log.shouldLog(Log.DEBUG)) {
long complete = System.currentTimeMillis();
_log.debug("Time to add the message " + msg.getUniqueId() + ": " + (complete-startAdd)
+ " delayed? " + delayedFlush + " remaining: " + remaining
+ " prepare: " + (beforeLock-startAdd)
@ -137,6 +136,7 @@ public class TunnelGateway {
+ " preprocess: " + (afterPreprocess-afterAdded)
+ " expire: " + (afterExpire-afterPreprocess)
+ " queue flush: " + (complete-afterExpire));
}
}
public int getMessagesSent() { return _messagesSent; }
@ -202,10 +202,7 @@ public class TunnelGateway {
_messageId = message.getUniqueId();
_expiration = message.getMessageExpiration();
_remaining = message.toByteArray();
_offset = 0;
_fragmentNumber = 0;
_created = now;
_messageIds = null;
}
/** may be null */
public Hash getToRouter() { return _toRouter; }

View File

@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
import net.i2p.router.TunnelPoolSettings;
@ -14,7 +15,7 @@ import net.i2p.router.TunnelPoolSettings;
*
*/
class ClientPeerSelector extends TunnelPeerSelector {
public List selectPeers(RouterContext ctx, TunnelPoolSettings settings) {
public List<Hash> selectPeers(RouterContext ctx, TunnelPoolSettings settings) {
int length = getLength(ctx, settings);
if (length < 0)
return null;
@ -31,7 +32,7 @@ class ClientPeerSelector extends TunnelPeerSelector {
ctx.profileOrganizer().selectFastPeers(length, exclude, matches, settings.getIPRestriction());
matches.remove(ctx.routerHash());
ArrayList rv = new ArrayList(matches);
ArrayList<Hash> rv = new ArrayList(matches);
if (rv.size() > 1)
orderPeers(rv, settings.getRandomKey());
if (settings.isInbound())

View File

@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
import net.i2p.router.TunnelPoolSettings;
import net.i2p.stat.Rate;
@ -17,7 +18,7 @@ import net.i2p.util.Log;
*
*/
class ExploratoryPeerSelector extends TunnelPeerSelector {
public List selectPeers(RouterContext ctx, TunnelPoolSettings settings) {
public List<Hash> selectPeers(RouterContext ctx, TunnelPoolSettings settings) {
Log l = ctx.logManager().getLog(getClass());
int length = getLength(ctx, settings);
if (length < 0) {
@ -33,7 +34,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
return rv;
}
Set exclude = getExclude(ctx, settings.isInbound(), settings.isExploratory());
Set<Hash> exclude = getExclude(ctx, settings.isInbound(), settings.isExploratory());
exclude.add(ctx.routerHash());
// Don't use ff peers for exploratory tunnels to lessen exposure to netDb searches and stores
// Hmm if they don't get explored they don't get a speed/capacity rating
@ -56,7 +57,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
l.debug("profileOrganizer.selectNotFailing(" + length + ") found " + matches);
matches.remove(ctx.routerHash());
ArrayList rv = new ArrayList(matches);
ArrayList<Hash> rv = new ArrayList(matches);
if (rv.size() > 1)
orderPeers(rv, settings.getRandomKey());
if (settings.isInbound())
@ -67,7 +68,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
}
private static final int MIN_NONFAILING_PCT = 25;
private boolean shouldPickHighCap(RouterContext ctx) {
private static boolean shouldPickHighCap(RouterContext ctx) {
if (Boolean.valueOf(ctx.getProperty("router.exploreHighCapacity", "false")).booleanValue())
return true;
// no need to explore too wildly at first
@ -86,9 +87,9 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
failPct = 100 - MIN_NONFAILING_PCT;
} else {
failPct = getExploratoryFailPercentage(ctx);
Log l = ctx.logManager().getLog(getClass());
if (l.shouldLog(Log.DEBUG))
l.debug("Normalized Fail pct: " + failPct);
//Log l = ctx.logManager().getLog(getClass());
//if (l.shouldLog(Log.DEBUG))
// l.debug("Normalized Fail pct: " + failPct);
// always try a little, this helps keep the failPct stat accurate too
if (failPct > 100 - MIN_NONFAILING_PCT)
failPct = 100 - MIN_NONFAILING_PCT;
@ -96,21 +97,23 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
return (failPct >= ctx.random().nextInt(100));
}
// We should really use the difference between the exploratory fail rate
// and the high capacity fail rate - but we don't have a stat for high cap,
// so use the fast (== client) fail rate, it should be close
// if the expl. and client tunnel lengths aren't too different.
// So calculate the difference between the exploratory fail rate
// and the client fail rate, normalized to 100:
// 100 * ((Efail - Cfail) / (100 - Cfail))
// Even this isn't the "true" rate for the NonFailingPeers pool, since we
// are often building exploratory tunnels using the HighCapacity pool.
private int getExploratoryFailPercentage(RouterContext ctx) {
/**
* We should really use the difference between the exploratory fail rate
* and the high capacity fail rate - but we don't have a stat for high cap,
* so use the fast (== client) fail rate, it should be close
* if the expl. and client tunnel lengths aren't too different.
* So calculate the difference between the exploratory fail rate
* and the client fail rate, normalized to 100:
* 100 * ((Efail - Cfail) / (100 - Cfail))
* Even this isn't the "true" rate for the NonFailingPeers pool, since we
* are often building exploratory tunnels using the HighCapacity pool.
*/
private static int getExploratoryFailPercentage(RouterContext ctx) {
int c = getFailPercentage(ctx, "Client");
int e = getFailPercentage(ctx, "Exploratory");
Log l = ctx.logManager().getLog(getClass());
if (l.shouldLog(Log.DEBUG))
l.debug("Client, Expl. Fail pct: " + c + ", " + e);
//Log l = ctx.logManager().getLog(getClass());
//if (l.shouldLog(Log.DEBUG))
// l.debug("Client, Expl. Fail pct: " + c + ", " + e);
if (e <= c || e <= 25) // doing very well (unlikely)
return 0;
if (c >= 90) // doing very badly
@ -118,7 +121,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
return (100 * (e-c)) / (100-c);
}
private int getFailPercentage(RouterContext ctx, String t) {
private static int getFailPercentage(RouterContext ctx, String t) {
String pfx = "tunnel.build" + t;
int timeout = getEvents(ctx, pfx + "Expire", 10*60*1000);
int reject = getEvents(ctx, pfx + "Reject", 10*60*1000);
@ -129,8 +132,8 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
return (int)(100 * pct);
}
// Use current + last to get more recent and smoother data
private int getEvents(RouterContext ctx, String stat, long period) {
/** Use current + last to get more recent and smoother data */
private static int getEvents(RouterContext ctx, String stat, long period) {
RateStat rs = ctx.statManager().getRate(stat);
if (rs == null)
return 0;

View File

@ -12,7 +12,7 @@ import net.i2p.util.Log;
/**
*
*/
public class PooledTunnelCreatorConfig extends TunnelCreatorConfig {
class PooledTunnelCreatorConfig extends TunnelCreatorConfig {
private TunnelPool _pool;
private TestJob _testJob;
// private Job _expireJob;

View File

@ -21,10 +21,13 @@ import net.i2p.router.TunnelPoolSettings;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
import net.i2p.router.networkdb.kademlia.HashDistance;
import net.i2p.util.Log;
import net.i2p.util.VersionComparator;
/**
* Coordinate the selection of peers to go into a tunnel for one particular
* pool.
*
* Todo: there's nothing non-static in here
*/
public abstract class TunnelPeerSelector {
/**
@ -36,7 +39,7 @@ public abstract class TunnelPeerSelector {
* to build through, and the settings reject 0 hop tunnels, this will
* return null.
*/
public abstract List selectPeers(RouterContext ctx, TunnelPoolSettings settings);
public abstract List<Hash> selectPeers(RouterContext ctx, TunnelPoolSettings settings);
protected int getLength(RouterContext ctx, TunnelPoolSettings settings) {
int length = settings.getLength();
@ -79,6 +82,11 @@ public abstract class TunnelPeerSelector {
return length;
}
/**
* For debugging, also possibly for restricted routes?
* Needs analysis and testing
* @return should always be false
*/
protected boolean shouldSelectExplicit(TunnelPoolSettings settings) {
if (settings.isExploratory()) return false;
Properties opts = settings.getUnknownOptions();
@ -92,7 +100,12 @@ public abstract class TunnelPeerSelector {
return false;
}
protected List selectExplicit(RouterContext ctx, TunnelPoolSettings settings, int length) {
/**
* For debugging, also possibly for restricted routes?
* Needs analysis and testing
* @return should always be false
*/
protected List<Hash> selectExplicit(RouterContext ctx, TunnelPoolSettings settings, int length) {
String peers = null;
Properties opts = settings.getUnknownOptions();
if (opts != null)
@ -102,7 +115,7 @@ public abstract class TunnelPeerSelector {
peers = I2PAppContext.getGlobalContext().getProperty("explicitPeers");
Log log = ctx.logManager().getLog(ClientPeerSelector.class);
List rv = new ArrayList();
List<Hash> rv = new ArrayList();
StringTokenizer tok = new StringTokenizer(peers, ",");
while (tok.hasMoreTokens()) {
String peerStr = tok.nextToken();
@ -156,7 +169,7 @@ public abstract class TunnelPeerSelector {
/**
* Pick peers that we want to avoid
*/
public Set getExclude(RouterContext ctx, boolean isInbound, boolean isExploratory) {
public Set<Hash> getExclude(RouterContext ctx, boolean isInbound, boolean isExploratory) {
// we may want to update this to skip 'hidden' or 'unreachable' peers, but that
// isn't safe, since they may publish one set of routerInfo to us and another to
// other peers. the defaults for filterUnreachable has always been to return false,
@ -175,11 +188,12 @@ public abstract class TunnelPeerSelector {
//
// Defaults changed to true for inbound only in filterUnreachable below.
Set peers = new HashSet(1);
Set<Hash> peers = new HashSet(1);
peers.addAll(ctx.profileOrganizer().selectPeersRecentlyRejecting());
peers.addAll(ctx.tunnelManager().selectPeersInTooManyTunnels());
// if (false && filterUnreachable(ctx, isInbound, isExploratory)) {
if (filterUnreachable(ctx, isInbound, isExploratory)) {
// NOTE: filterUnreachable returns true for inbound, false for outbound
// This is the only use for getPeersByCapability? And the whole set of datastructures in PeerManager?
List<Hash> caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE);
if (caps != null)
@ -189,6 +203,7 @@ public abstract class TunnelPeerSelector {
peers.addAll(caps);
}
if (filterSlow(ctx, isInbound, isExploratory)) {
// NOTE: filterSlow always returns true
Log log = ctx.logManager().getLog(TunnelPeerSelector.class);
char excl[] = getExcludeCaps(ctx);
if (excl != null) {
@ -301,6 +316,7 @@ public abstract class TunnelPeerSelector {
return peers;
}
/** warning, this is also called by ProfileOrganizer.isSelectable() */
public static boolean shouldExclude(RouterContext ctx, RouterInfo peer) {
Log log = ctx.logManager().getLog(TunnelPeerSelector.class);
return shouldExclude(ctx, log, peer, getExcludeCaps(ctx));
@ -318,6 +334,10 @@ public abstract class TunnelPeerSelector {
}
private static final long DONT_EXCLUDE_PERIOD = 15*60*1000;
/** 0.7.8 and earlier had major message corruption bugs */
private static final String MIN_VERSION = "0.7.9";
private static final VersionComparator _versionComparator = new VersionComparator();
private static boolean shouldExclude(RouterContext ctx, Log log, RouterInfo peer, char excl[]) {
String cap = peer.getCapabilities();
if (cap == null) {
@ -340,6 +360,13 @@ public abstract class TunnelPeerSelector {
// otherwise, it contains flags we aren't trying to focus on,
// so don't exclude it based on published capacity
// minimum version check
String v = peer.getOption("router.version");
if (v == null || _versionComparator.compare(v, MIN_VERSION) < 0)
return true;
// uptime is always spoofed to 90m, so just remove all this
/******
String val = peer.getOption("stat_uptime");
if (val != null) {
long uptimeMs = 0;
@ -390,6 +417,8 @@ public abstract class TunnelPeerSelector {
// not publishing an uptime, so exclude it
return true;
}
******/
return false;
}
private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.outboundExploratoryExcludeUnreachable";
@ -403,6 +432,10 @@ public abstract class TunnelPeerSelector {
private static final String DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "true";
private static final String DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "true";
/**
* do we want to skip peers who haven't been up for long?
* @return true for inbound, false for outbound, unless configured otherwise
*/
protected boolean filterUnreachable(RouterContext ctx, boolean isInbound, boolean isExploratory) {
boolean def = false;
String val = null;
@ -429,6 +462,10 @@ public abstract class TunnelPeerSelector {
private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_SLOW = "router.inboundExploratoryExcludeSlow";
private static final String PROP_INBOUND_CLIENT_EXCLUDE_SLOW = "router.inboundClientExcludeSlow";
/**
* do we want to skip peers that are slow?
* @return true unless configured otherwise
*/
protected boolean filterSlow(RouterContext ctx, boolean isInbound, boolean isExploratory) {
boolean def = true;
String val = null;
@ -454,7 +491,10 @@ public abstract class TunnelPeerSelector {
private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UPTIME = "router.inboundExploratoryExcludeUptime";
private static final String PROP_INBOUND_CLIENT_EXCLUDE_UPTIME = "router.inboundClientExcludeUptime";
/** do we want to skip peers who haven't been up for long? */
/**
* do we want to skip peers who haven't been up for long?
* @return true unless configured otherwise
*/
protected boolean filterUptime(RouterContext ctx, boolean isInbound, boolean isExploratory) {
boolean def = true;
String val = null;