2006-04-05 jrandom

* Fix during the ssu handshake to avoid an unnecessary failure on
      packet retransmission (thanks ripple!)
    * Fix during the SSU handshake to use the negotiated session key asap,
      rather than using the intro key for more than we should (thanks ripple!)
    * Fixes to the message reply registry (thanks Complication!)
    * More comprehensive syndie banning (for repeated pushes)
    * Publish the router's ballpark bandwidth limit (w/in a power of 2), for
      testing purposes
    * Put a floor back on the capacity threshold, so too many failing peers
      won't cause us to pick very bad peers (unless we have very few good
      ones)
    * Bugfix to cut down on peers using introducers unneessarily (thanks
      Complication!)
    * Reduced the default streaming lib message size to fit into a single
      tunnel message, rather than require 5 tunnel messages to be transferred
      without loss before recomposition.  This reduces throughput, but should
      increase reliability, at least for the time being.
    * Misc small bugfixes in the router (thanks all!)
    * More tweaking for Syndie's CSS (thanks Doubtful Salmon!)
This commit is contained in:
jrandom
2006-04-04 12:20:32 +00:00
committed by zzz
parent 764149aef3
commit 9a820961a2
16 changed files with 196 additions and 51 deletions

View File

@ -250,7 +250,7 @@ public class ConfigNetHandler extends FormHandler {
// If hidden mode value changes, restart is required // If hidden mode value changes, restart is required
if (_hiddenMode && "false".equalsIgnoreCase(_context.getProperty(Router.PROP_HIDDEN, "false"))) { if (_hiddenMode && "false".equalsIgnoreCase(_context.getProperty(Router.PROP_HIDDEN, "false"))) {
_context.router().setConfigSetting(Router.PROP_HIDDEN, "true"); _context.router().setConfigSetting(Router.PROP_HIDDEN, "true");
_context.router().getRouterInfo().addCapability(RouterInfo.CAPABILITY_HIDDEN); _context.router().addCapabilities(_context.router().getRouterInfo());
addFormNotice("Gracefully restarting into Hidden Router Mode. Make sure you have no 0-1 length " addFormNotice("Gracefully restarting into Hidden Router Mode. Make sure you have no 0-1 length "
+ "<a href=\"configtunnels.jsp\">tunnels!</a>"); + "<a href=\"configtunnels.jsp\">tunnels!</a>");
hiddenSwitch(); hiddenSwitch();

View File

@ -101,7 +101,7 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
setMaxWindowSize(getInt(opts, PROP_MAX_WINDOW_SIZE, Connection.MAX_WINDOW_SIZE)); setMaxWindowSize(getInt(opts, PROP_MAX_WINDOW_SIZE, Connection.MAX_WINDOW_SIZE));
setConnectDelay(getInt(opts, PROP_CONNECT_DELAY, -1)); setConnectDelay(getInt(opts, PROP_CONNECT_DELAY, -1));
setProfile(getInt(opts, PROP_PROFILE, PROFILE_BULK)); setProfile(getInt(opts, PROP_PROFILE, PROFILE_BULK));
setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, 4*1024)); setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, 960)); // 960 fits inside a single tunnel message
setRTT(getInt(opts, PROP_INITIAL_RTT, 10*1000)); setRTT(getInt(opts, PROP_INITIAL_RTT, 10*1000));
setReceiveWindow(getInt(opts, PROP_INITIAL_RECEIVE_WINDOW, 1)); setReceiveWindow(getInt(opts, PROP_INITIAL_RECEIVE_WINDOW, 1));
setResendDelay(getInt(opts, PROP_INITIAL_RESEND_DELAY, 1000)); setResendDelay(getInt(opts, PROP_INITIAL_RESEND_DELAY, 1000));

View File

@ -890,6 +890,8 @@ public class BlogManager {
try { try {
BlogInfo info = new BlogInfo(); BlogInfo info = new BlogInfo();
info.load(metadataStream); info.load(metadataStream);
if (isBanned(info.getKey().calculateHash()))
return false;
return _archive.storeBlogInfo(info); return _archive.storeBlogInfo(info);
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error importing meta", ioe); _log.error("Error importing meta", ioe);
@ -906,6 +908,8 @@ public class BlogManager {
try { try {
EntryContainer c = new EntryContainer(); EntryContainer c = new EntryContainer();
c.load(entryStream); c.load(entryStream);
if (isBanned(c.getURI().getKeyHash()))
return false;
return _archive.storeEntry(c); return _archive.storeEntry(c);
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error importing entry", ioe); _log.error("Error importing entry", ioe);

View File

@ -134,9 +134,9 @@ select {
display: inline; display: inline;
} }
.controlBar { .controlBar {
margin: 0em; border-bottom: thick double #CCF;
padding: 0em; border-left: medium solid #CCF;
// border: medium solid #DDF; border-right: medium solid #CCF;
background-color: #EEF; background-color: #EEF;
color: inherit; color: inherit;
font-size: small; font-size: small;

View File

@ -1,4 +1,25 @@
$Id: history.txt,v 1.442 2006/04/01 14:05:37 jrandom Exp $ $Id: history.txt,v 1.443 2006/04/03 05:07:24 jrandom Exp $
2006-04-05 jrandom
* Fix during the ssu handshake to avoid an unnecessary failure on
packet retransmission (thanks ripple!)
* Fix during the SSU handshake to use the negotiated session key asap,
rather than using the intro key for more than we should (thanks ripple!)
* Fixes to the message reply registry (thanks Complication!)
* More comprehensive syndie banning (for repeated pushes)
* Publish the router's ballpark bandwidth limit (w/in a power of 2), for
testing purposes
* Put a floor back on the capacity threshold, so too many failing peers
won't cause us to pick very bad peers (unless we have very few good
ones)
* Bugfix to cut down on peers using introducers unneessarily (thanks
Complication!)
* Reduced the default streaming lib message size to fit into a single
tunnel message, rather than require 5 tunnel messages to be transferred
without loss before recomposition. This reduces throughput, but should
increase reliability, at least for the time being.
* Misc small bugfixes in the router (thanks all!)
* More tweaking for Syndie's CSS (thanks Doubtful Salmon!)
2006-04-01 jrandom 2006-04-01 jrandom
* Take out the router watchdog's teeth (don't restart on leaseset failure) * Take out the router watchdog's teeth (don't restart on leaseset failure)

View File

@ -323,13 +323,8 @@ public class Router {
stats.setProperty(RouterInfo.PROP_NETWORK_ID, NETWORK_ID+""); stats.setProperty(RouterInfo.PROP_NETWORK_ID, NETWORK_ID+"");
ri.setOptions(stats); ri.setOptions(stats);
ri.setAddresses(_context.commSystem().createAddresses()); ri.setAddresses(_context.commSystem().createAddresses());
if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context))
ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL);
if("true".equalsIgnoreCase(_context.getProperty(Router.PROP_HIDDEN, "false"))) {
ri.addCapability(RouterInfo.CAPABILITY_HIDDEN);
}
addReachabilityCapability(ri); addCapabilities(ri);
SigningPrivateKey key = _context.keyManager().getSigningPrivateKey(); SigningPrivateKey key = _context.keyManager().getSigningPrivateKey();
if (key == null) { if (key == null) {
_log.log(Log.CRIT, "Internal error - signing private key not known? wtf"); _log.log(Log.CRIT, "Internal error - signing private key not known? wtf");
@ -358,15 +353,43 @@ public class Router {
} }
} }
// publicize our ballpark capacity - this does not affect anything at
// the moment
public static final char CAPABILITY_BW16 = 'K';
public static final char CAPABILITY_BW32 = 'L';
public static final char CAPABILITY_BW64 = 'M';
public static final char CAPABILITY_BW128 = 'N';
public static final char CAPABILITY_BW256 = 'O';
public static final char CAPABILITY_REACHABLE = 'R'; public static final char CAPABILITY_REACHABLE = 'R';
public static final char CAPABILITY_UNREACHABLE = 'U'; public static final char CAPABILITY_UNREACHABLE = 'U';
public static final String PROP_FORCE_UNREACHABLE = "router.forceUnreachable"; public static final String PROP_FORCE_UNREACHABLE = "router.forceUnreachable";
public static final char CAPABILITY_NEW_TUNNEL = 'T'; public static final char CAPABILITY_NEW_TUNNEL = 'T';
public void addReachabilityCapability(RouterInfo ri) { public void addCapabilities(RouterInfo ri) {
// routers who can understand TunnelBuildMessages int bwLim = Math.min(_context.bandwidthLimiter().getInboundKBytesPerSecond(),
////ri.addCapability(CAPABILITY_NEW_TUNNEL); _context.bandwidthLimiter().getInboundKBytesPerSecond());
if (_log.shouldLog(Log.WARN))
_log.warn("Adding capabilities w/ bw limit @ " + bwLim, new Exception("caps"));
if (bwLim <= 16) {
ri.addCapability(CAPABILITY_BW16);
} else if (bwLim <= 32) {
ri.addCapability(CAPABILITY_BW32);
} else if (bwLim <= 64) {
ri.addCapability(CAPABILITY_BW64);
} else if (bwLim <= 128) {
ri.addCapability(CAPABILITY_BW128);
} else { // ok, more than 128KBps... aka "lots"
ri.addCapability(CAPABILITY_BW256);
}
if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context))
ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL);
if("true".equalsIgnoreCase(_context.getProperty(Router.PROP_HIDDEN, "false")))
ri.addCapability(RouterInfo.CAPABILITY_HIDDEN);
String forceUnreachable = _context.getProperty(PROP_FORCE_UNREACHABLE); String forceUnreachable = _context.getProperty(PROP_FORCE_UNREACHABLE);
if ( (forceUnreachable != null) && ("true".equalsIgnoreCase(forceUnreachable)) ) { if ( (forceUnreachable != null) && ("true".equalsIgnoreCase(forceUnreachable)) ) {

View File

@ -45,13 +45,8 @@ public class PublishLocalRouterInfoJob extends JobImpl {
ri.setPublished(getContext().clock().now()); ri.setPublished(getContext().clock().now());
ri.setOptions(stats); ri.setOptions(stats);
ri.setAddresses(getContext().commSystem().createAddresses()); ri.setAddresses(getContext().commSystem().createAddresses());
if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext()))
ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL);
if ("true".equalsIgnoreCase(getContext().getProperty(Router.PROP_HIDDEN, "false"))) getContext().router().addCapabilities(ri);
ri.addCapability(RouterInfo.CAPABILITY_HIDDEN);
getContext().router().addReachabilityCapability(ri);
SigningPrivateKey key = getContext().keyManager().getSigningPrivateKey(); SigningPrivateKey key = getContext().keyManager().getSigningPrivateKey();
if (key == null) { if (key == null) {
_log.log(Log.CRIT, "Internal error - signing private key not known? rescheduling publish for 30s"); _log.log(Log.CRIT, "Internal error - signing private key not known? rescheduling publish for 30s");

View File

@ -682,6 +682,12 @@ public class ProfileOrganizer {
+ "], but there aren't enough of them " + numExceedingMean); + "], but there aren't enough of them " + numExceedingMean);
_thresholdCapacityValue = Math.max(thresholdAtMinHighCap, thresholdAtLowest); _thresholdCapacityValue = Math.max(thresholdAtMinHighCap, thresholdAtLowest);
} }
// the base growth factor is the value we give to new routers that we don't
// know anything about. dont go under that limit unless you want to expose
// the selection to simple ident flooding attacks
if (_thresholdCapacityValue <= CapacityCalculator.GROWTH_FACTOR)
_thresholdCapacityValue = CapacityCalculator.GROWTH_FACTOR + 0.0001;
} }
/** /**

View File

@ -54,12 +54,8 @@ public class CreateRouterInfoJob extends JobImpl {
info.setAddresses(getContext().commSystem().createAddresses()); info.setAddresses(getContext().commSystem().createAddresses());
Properties stats = getContext().statPublisher().publishStatistics(); Properties stats = getContext().statPublisher().publishStatistics();
stats.setProperty(RouterInfo.PROP_NETWORK_ID, Router.NETWORK_ID+""); stats.setProperty(RouterInfo.PROP_NETWORK_ID, Router.NETWORK_ID+"");
getContext().router().addReachabilityCapability(info); getContext().router().addCapabilities(info);
info.setOptions(stats); info.setOptions(stats);
if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext()))
info.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL);
if ("true".equalsIgnoreCase(getContext().getProperty(Router.PROP_HIDDEN, "false")))
info.addCapability(RouterInfo.CAPABILITY_HIDDEN);
info.setPeers(new HashSet()); info.setPeers(new HashSet());
info.setPublished(getCurrentPublishDate(getContext())); info.setPublished(getCurrentPublishDate(getContext()));
RouterIdentity ident = new RouterIdentity(); RouterIdentity ident = new RouterIdentity();

View File

@ -128,14 +128,7 @@ public class RebuildRouterInfoJob extends JobImpl {
Properties stats = getContext().statPublisher().publishStatistics(); Properties stats = getContext().statPublisher().publishStatistics();
stats.setProperty(RouterInfo.PROP_NETWORK_ID, ""+Router.NETWORK_ID); stats.setProperty(RouterInfo.PROP_NETWORK_ID, ""+Router.NETWORK_ID);
info.setOptions(stats); info.setOptions(stats);
if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext())) getContext().router().addCapabilities(info);
info.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL);
// Set caps=H for hidden mode routers
if ("true".equalsIgnoreCase(getContext().getProperty(Router.PROP_HIDDEN, "false")))
info.addCapability(RouterInfo.CAPABILITY_HIDDEN);
getContext().router().addReachabilityCapability(info);
// info.setPeers(new HashSet()); // this would have the trusted peers // info.setPeers(new HashSet()); // this would have the trusted peers
info.setPublished(CreateRouterInfoJob.getCurrentPublishDate(getContext())); info.setPublished(CreateRouterInfoJob.getCurrentPublishDate(getContext()));

View File

@ -25,7 +25,7 @@ public class OutboundMessageRegistry {
private Log _log; private Log _log;
/** list of currently active MessageSelector instances */ /** list of currently active MessageSelector instances */
private List _selectors; private List _selectors;
/** map of active MessageSelector to the OutNetMessage causing it (for quick removal) */ /** map of active MessageSelector to either an OutNetMessage or a List of OutNetMessages causing it (for quick removal) */
private Map _selectorToMessage; private Map _selectorToMessage;
/** set of active OutNetMessage (for quick removal and selector fetching) */ /** set of active OutNetMessage (for quick removal and selector fetching) */
private Set _activeMessages; private Set _activeMessages;
@ -61,6 +61,8 @@ public class OutboundMessageRegistry {
synchronized (_selectors) { synchronized (_selectors) {
for (int i = 0; i < _selectors.size(); i++) { for (int i = 0; i < _selectors.size(); i++) {
MessageSelector sel = (MessageSelector)_selectors.get(i); MessageSelector sel = (MessageSelector)_selectors.get(i);
if (sel == null)
continue;
boolean isMatch = sel.isMatch(message); boolean isMatch = sel.isMatch(message);
if (isMatch) { if (isMatch) {
if (matchedSelectors == null) matchedSelectors = new ArrayList(1); if (matchedSelectors == null) matchedSelectors = new ArrayList(1);
@ -82,19 +84,36 @@ public class OutboundMessageRegistry {
MessageSelector sel = (MessageSelector)matchedSelectors.get(i); MessageSelector sel = (MessageSelector)matchedSelectors.get(i);
boolean removed = false; boolean removed = false;
OutNetMessage msg = null; OutNetMessage msg = null;
List msgs = null;
synchronized (_selectorToMessage) { synchronized (_selectorToMessage) {
Object o = null;
if ( (removedSelectors != null) && (removedSelectors.contains(sel)) ) { if ( (removedSelectors != null) && (removedSelectors.contains(sel)) ) {
msg = (OutNetMessage)_selectorToMessage.remove(sel); o = _selectorToMessage.remove(sel);
removed = true; removed = true;
} else { } else {
msg = (OutNetMessage)_selectorToMessage.get(sel); o = _selectorToMessage.get(sel);
}
if (o instanceof OutNetMessage) {
msg = (OutNetMessage)o;
if (msg != null)
rv.add(msg);
} else if (o instanceof List) {
msgs = (List)o;
if (msgs != null)
for (int j = 0; j < msgs.size(); j++)
rv.add(msgs.get(j));
} }
if (msg != null)
rv.add(msg);
} }
if (removed && msg != null) { if (removed) {
synchronized (_activeMessages) { if (msg != null) {
_activeMessages.remove(msg); synchronized (_activeMessages) {
_activeMessages.remove(msg);
}
} else if (msgs != null) {
synchronized (_activeMessages) {
_activeMessages.removeAll(msgs);
}
} }
} }
} }
@ -128,7 +147,24 @@ public class OutboundMessageRegistry {
if (!_activeMessages.add(msg)) if (!_activeMessages.add(msg))
return; // dont add dups return; // dont add dups
} }
synchronized (_selectorToMessage) { _selectorToMessage.put(sel, msg); } synchronized (_selectorToMessage) {
Object oldMsg = _selectorToMessage.put(sel, msg);
if (oldMsg != null) {
List multi = null;
if (oldMsg instanceof OutNetMessage) {
multi = new ArrayList(4);
multi.add(oldMsg);
multi.add(msg);
_selectorToMessage.put(sel, multi);
} else if (oldMsg instanceof List) {
multi = (List)oldMsg;
multi.add(msg);
_selectorToMessage.put(sel, multi);
}
if (_log.shouldLog(Log.WARN))
_log.warn("a single message selector [" + sel + "] with multiple messages ("+ multi + ")");
}
}
synchronized (_selectors) { _selectors.add(sel); } synchronized (_selectors) { _selectors.add(sel); }
_cleanupTask.scheduleExpiration(sel); _cleanupTask.scheduleExpiration(sel);
@ -136,9 +172,22 @@ public class OutboundMessageRegistry {
public void unregisterPending(OutNetMessage msg) { public void unregisterPending(OutNetMessage msg) {
MessageSelector sel = msg.getReplySelector(); MessageSelector sel = msg.getReplySelector();
// remember, order matters boolean stillActive = false;
synchronized (_selectors) { _selectors.add(sel); } synchronized (_selectorToMessage) {
synchronized (_selectorToMessage) { _selectorToMessage.put(sel, msg); } Object old = _selectorToMessage.remove(sel);
if (old != null) {
if (old instanceof List) {
List l = (List)old;
l.remove(msg);
if (l.size() > 0) {
_selectorToMessage.put(sel, l);
stillActive = true;
}
}
}
}
if (!stillActive)
synchronized (_selectors) { _selectors.remove(sel); }
synchronized (_activeMessages) { _activeMessages.remove(msg); } synchronized (_activeMessages) { _activeMessages.remove(msg); }
} }
@ -156,6 +205,7 @@ public class OutboundMessageRegistry {
synchronized (_selectors) { synchronized (_selectors) {
for (int i = 0; i < _selectors.size(); i++) { for (int i = 0; i < _selectors.size(); i++) {
MessageSelector sel = (MessageSelector)_selectors.get(i); MessageSelector sel = (MessageSelector)_selectors.get(i);
if (sel == null) continue;
long expiration = sel.getExpiration(); long expiration = sel.getExpiration();
if (expiration <= now) { if (expiration <= now) {
_removing.add(sel); _removing.add(sel);
@ -170,8 +220,13 @@ public class OutboundMessageRegistry {
for (int i = 0; i < _removing.size(); i++) { for (int i = 0; i < _removing.size(); i++) {
MessageSelector sel = (MessageSelector)_removing.get(i); MessageSelector sel = (MessageSelector)_removing.get(i);
OutNetMessage msg = null; OutNetMessage msg = null;
List msgs = null;
synchronized (_selectorToMessage) { synchronized (_selectorToMessage) {
msg = (OutNetMessage)_selectorToMessage.remove(sel); Object o = _selectorToMessage.remove(sel);
if (o instanceof OutNetMessage)
msg = (OutNetMessage)o;
else if (o instanceof List)
msgs = (List)o;
} }
if (msg != null) { if (msg != null) {
synchronized (_activeMessages) { synchronized (_activeMessages) {
@ -180,6 +235,16 @@ public class OutboundMessageRegistry {
Job fail = msg.getOnFailedReplyJob(); Job fail = msg.getOnFailedReplyJob();
if (fail != null) if (fail != null)
_context.jobQueue().addJob(fail); _context.jobQueue().addJob(fail);
} else if (msgs != null) {
synchronized (_activeMessages) {
_activeMessages.removeAll(msgs);
}
for (int j = 0; j < msgs.size(); j++) {
msg = (OutNetMessage)msgs.get(i);
Job fail = msg.getOnFailedReplyJob();
if (fail != null)
_context.jobQueue().addJob(fail);
}
} }
} }
_removing.clear(); _removing.clear();

View File

@ -552,7 +552,11 @@ public class EstablishmentManager {
// offer to relay // offer to relay
// (perhaps we should check our bw usage and/or how many peers we are // (perhaps we should check our bw usage and/or how many peers we are
// already offering introducing?) // already offering introducing?)
state.setSentRelayTag(_context.random().nextLong(MAX_TAG_VALUE)); if (state.getSentRelayTag() < 0) {
state.setSentRelayTag(_context.random().nextLong(MAX_TAG_VALUE));
} else {
// don't change it, since we've already prepared our sig
}
} else { } else {
// don't offer to relay // don't offer to relay
state.setSentRelayTag(0); state.setSentRelayTag(0);

View File

@ -567,7 +567,7 @@ public class PacketBuilder {
if ( (off % 16) != 0) if ( (off % 16) != 0)
off += 16 - (off % 16); off += 16 - (off % 16);
packet.getPacket().setLength(off); packet.getPacket().setLength(off);
authenticate(packet, state.getIntroKey(), state.getIntroKey()); authenticate(packet, state.getCipherKey(), state.getMACKey());
} }
setTo(packet, to, state.getSentPort()); setTo(packet, to, state.getSentPort());

View File

@ -337,6 +337,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if ( (_externalListenHost == null) || if ( (_externalListenHost == null) ||
(!eq(_externalListenHost.getAddress(), _externalListenPort, ourIP, ourPort)) ) { (!eq(_externalListenHost.getAddress(), _externalListenPort, ourIP, ourPort)) ) {
if ( (_reachabilityStatus == CommSystemFacade.STATUS_UNKNOWN) || if ( (_reachabilityStatus == CommSystemFacade.STATUS_UNKNOWN) ||
(_externalListenHost == null) || (_externalListenPort <= 0) ||
(_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) { (_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) {
// they told us something different and our tests are either old or failing // they told us something different and our tests are either old or failing
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
@ -358,7 +359,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// so lets test again // so lets test again
fireTest = true; fireTest = true;
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Different address, but we're fine.."); _log.info("Different address, but we're fine.. (" + _reachabilityStatus + ")");
} }
} else { } else {
// matched what we expect // matched what we expect

View File

@ -3,6 +3,8 @@ package net.i2p.router.tunnel.pool;
import java.util.*; import java.util.*;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.TunnelPoolSettings; import net.i2p.router.TunnelPoolSettings;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
import net.i2p.util.Log; import net.i2p.util.Log;
/** /**
@ -30,7 +32,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
Set exclude = getExclude(ctx, settings.isInbound(), settings.isExploratory()); Set exclude = getExclude(ctx, settings.isInbound(), settings.isExploratory());
exclude.add(ctx.routerHash()); exclude.add(ctx.routerHash());
HashSet matches = new HashSet(length); HashSet matches = new HashSet(length);
boolean exploreHighCap = Boolean.valueOf(ctx.getProperty("router.exploreHighCapacity", "false")).booleanValue(); boolean exploreHighCap = shouldPickHighCap(ctx);
if (exploreHighCap) if (exploreHighCap)
ctx.profileOrganizer().selectHighCapacityPeers(length, exclude, matches); ctx.profileOrganizer().selectHighCapacityPeers(length, exclude, matches);
else else
@ -48,4 +50,38 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
rv.add(ctx.routerHash()); rv.add(ctx.routerHash());
return rv; return rv;
} }
private boolean shouldPickHighCap(RouterContext ctx) {
if (Boolean.valueOf(ctx.getProperty("router.exploreHighCapacity", "false")).booleanValue())
return true;
// no need to explore too wildly at first
if (ctx.router().getUptime() <= 10*1000)
return true;
// ok, if we aren't explicitly asking for it, we should try to pick peers
// randomly from the 'not failing' pool. However, if we are having a
// hard time building exploratory tunnels, lets fall back again on the
// high capacity peers, at least for a little bit.
int failPct = getExploratoryFailPercentage(ctx);
return (failPct >= ctx.random().nextInt(100));
}
private int getExploratoryFailPercentage(RouterContext ctx) {
int timeout = getEvents(ctx, "tunnel.buildExploratoryExpire", 10*60*1000);
int reject = getEvents(ctx, "tunnel.buildExploratoryReject", 10*60*1000);
int accept = getEvents(ctx, "tunnel.buildExploratorySuccess", 10*60*1000);
if (accept + reject + timeout <= 0)
return 0;
double pct = (double)(reject + timeout) / (accept + reject + timeout);
return (int)(100 * pct);
}
private int getEvents(RouterContext ctx, String stat, long period) {
RateStat rs = ctx.statManager().getRate(stat);
if (rs == null)
return 0;
Rate r = rs.getRate(period);
if (r == null)
return 0;
return (int)r.getLastEventCount();
}
} }

View File

@ -601,6 +601,7 @@ public class TunnelPool {
peers.add(_context.routerHash()); peers.add(_context.routerHash());
} }
PooledTunnelCreatorConfig cfg = new PooledTunnelCreatorConfig(_context, peers.size(), settings.isInbound(), settings.getDestination()); PooledTunnelCreatorConfig cfg = new PooledTunnelCreatorConfig(_context, peers.size(), settings.isInbound(), settings.getDestination());
cfg.setTunnelPool(this);
// peers[] is ordered endpoint first, but cfg.getPeer() is ordered gateway first // peers[] is ordered endpoint first, but cfg.getPeer() is ordered gateway first
for (int i = 0; i < peers.size(); i++) { for (int i = 0; i < peers.size(); i++) {
int j = peers.size() - 1 - i; int j = peers.size() - 1 - i;