forked from I2P_Developers/i2p.i2p
2005-02-22 jrandom
* Reworked the tunnel (re)building process to remove the tokens and
provide cleaner controls on the tunnels built.
* Fixed situations where the timestamper wanted to test more servers than
were provided (thanks Tracker!)
* Get rid of the dead SAM sessions by using the streaming lib's callbacks
(thanks Tracker!)
This commit is contained in:
@@ -132,6 +132,8 @@ public class SAMStreamSession {
|
|||||||
if (socketMgr == null) {
|
if (socketMgr == null) {
|
||||||
throw new SAMException("Error creating I2PSocketManager");
|
throw new SAMException("Error creating I2PSocketManager");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socketMgr.addDisconnectListener(new DisconnectListener());
|
||||||
|
|
||||||
forceFlush = Boolean.valueOf(allprops.getProperty(PROP_FORCE_FLUSH, DEFAULT_FORCE_FLUSH)).booleanValue();
|
forceFlush = Boolean.valueOf(allprops.getProperty(PROP_FORCE_FLUSH, DEFAULT_FORCE_FLUSH)).booleanValue();
|
||||||
|
|
||||||
@@ -156,6 +158,12 @@ public class SAMStreamSession {
|
|||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class DisconnectListener implements I2PSocketManager.DisconnectListener {
|
||||||
|
public void sessionDisconnected() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the SAM STREAM session Destination.
|
* Get the SAM STREAM session Destination.
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ public class Timestamper implements Runnable {
|
|||||||
* True if the time was queried successfully, false if it couldn't be
|
* True if the time was queried successfully, false if it couldn't be
|
||||||
*/
|
*/
|
||||||
private boolean queryTime(String serverList[]) throws IllegalArgumentException {
|
private boolean queryTime(String serverList[]) throws IllegalArgumentException {
|
||||||
long found[] = new long[serverList.length];
|
long found[] = new long[_concurringServers];
|
||||||
long localTime = -1;
|
long localTime = -1;
|
||||||
long now = -1;
|
long now = -1;
|
||||||
long expectedDelta = 0;
|
long expectedDelta = 0;
|
||||||
|
|||||||
10
history.txt
10
history.txt
@@ -1,4 +1,12 @@
|
|||||||
$Id: history.txt,v 1.151 2005/02/22 02:07:34 jrandom Exp $
|
$Id: history.txt,v 1.152 2005/02/22 18:13:00 jrandom Exp $
|
||||||
|
|
||||||
|
2005-02-22 jrandom
|
||||||
|
* Reworked the tunnel (re)building process to remove the tokens and
|
||||||
|
provide cleaner controls on the tunnels built.
|
||||||
|
* Fixed situations where the timestamper wanted to test more servers than
|
||||||
|
were provided (thanks Tracker!)
|
||||||
|
* Get rid of the dead SAM sessions by using the streaming lib's callbacks
|
||||||
|
(thanks Tracker!)
|
||||||
|
|
||||||
2005-02-22 jrandom
|
2005-02-22 jrandom
|
||||||
* Temporary workaround for the I2CP disconnect bug (have the streaminglib
|
* Temporary workaround for the I2CP disconnect bug (have the streaminglib
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RouterVersion {
|
public class RouterVersion {
|
||||||
public final static String ID = "$Revision: 1.146 $ $Date: 2005/02/22 02:07:33 $";
|
public final static String ID = "$Revision: 1.147 $ $Date: 2005/02/22 17:58:22 $";
|
||||||
public final static String VERSION = "0.5";
|
public final static String VERSION = "0.5";
|
||||||
public final static long BUILD = 5;
|
public final static long BUILD = 6;
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
System.out.println("I2P Router version: " + VERSION);
|
System.out.println("I2P Router version: " + VERSION);
|
||||||
System.out.println("Router ID: " + RouterVersion.ID);
|
System.out.println("Router ID: " + RouterVersion.ID);
|
||||||
|
|||||||
@@ -8,13 +8,11 @@ import net.i2p.router.tunnel.TunnelCreatorConfig;
|
|||||||
class ExpireJob extends JobImpl {
|
class ExpireJob extends JobImpl {
|
||||||
private TunnelPool _pool;
|
private TunnelPool _pool;
|
||||||
private TunnelCreatorConfig _cfg;
|
private TunnelCreatorConfig _cfg;
|
||||||
private Object _buildToken;
|
|
||||||
private boolean _leaseUpdated;
|
private boolean _leaseUpdated;
|
||||||
public ExpireJob(RouterContext ctx, TunnelCreatorConfig cfg, TunnelPool pool, Object buildToken) {
|
public ExpireJob(RouterContext ctx, TunnelCreatorConfig cfg, TunnelPool pool) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
_pool = pool;
|
_pool = pool;
|
||||||
_cfg = cfg;
|
_cfg = cfg;
|
||||||
_buildToken = buildToken;
|
|
||||||
_leaseUpdated = false;
|
_leaseUpdated = false;
|
||||||
// give 'em some extra time before dropping 'em
|
// give 'em some extra time before dropping 'em
|
||||||
getTiming().setStartAfter(cfg.getExpiration()); // + Router.CLOCK_FUDGE_FACTOR);
|
getTiming().setStartAfter(cfg.getExpiration()); // + Router.CLOCK_FUDGE_FACTOR);
|
||||||
|
|||||||
@@ -13,17 +13,13 @@ import net.i2p.util.Log;
|
|||||||
class OnCreatedJob extends JobImpl {
|
class OnCreatedJob extends JobImpl {
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private TunnelPool _pool;
|
private TunnelPool _pool;
|
||||||
private Object _buildToken;
|
|
||||||
private PooledTunnelCreatorConfig _cfg;
|
private PooledTunnelCreatorConfig _cfg;
|
||||||
private boolean _fake;
|
|
||||||
|
|
||||||
public OnCreatedJob(RouterContext ctx, TunnelPool pool, PooledTunnelCreatorConfig cfg, boolean fake, Object buildToken) {
|
public OnCreatedJob(RouterContext ctx, TunnelPool pool, PooledTunnelCreatorConfig cfg) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
_log = ctx.logManager().getLog(OnCreatedJob.class);
|
_log = ctx.logManager().getLog(OnCreatedJob.class);
|
||||||
_pool = pool;
|
_pool = pool;
|
||||||
_cfg = cfg;
|
_cfg = cfg;
|
||||||
_fake = fake;
|
|
||||||
_buildToken = buildToken;
|
|
||||||
}
|
}
|
||||||
public String getName() { return "Tunnel built"; }
|
public String getName() { return "Tunnel built"; }
|
||||||
public void runJob() {
|
public void runJob() {
|
||||||
@@ -34,17 +30,16 @@ class OnCreatedJob extends JobImpl {
|
|||||||
getContext().tunnelDispatcher().joinOutbound(_cfg);
|
getContext().tunnelDispatcher().joinOutbound(_cfg);
|
||||||
}
|
}
|
||||||
_pool.addTunnel(_cfg);
|
_pool.addTunnel(_cfg);
|
||||||
TestJob testJob = (_cfg.getLength() > 1 ? new TestJob(getContext(), _cfg, _pool, _buildToken) : null);
|
TestJob testJob = (_cfg.getLength() > 1 ? new TestJob(getContext(), _cfg, _pool) : null);
|
||||||
RebuildJob rebuildJob = (_fake ? null : new RebuildJob(getContext(), _cfg, _pool, _buildToken));
|
RebuildJob rebuildJob = new RebuildJob(getContext(), _cfg, _pool);
|
||||||
ExpireJob expireJob = new ExpireJob(getContext(), _cfg, _pool, _buildToken);
|
ExpireJob expireJob = new ExpireJob(getContext(), _cfg, _pool);
|
||||||
_cfg.setTunnelPool(_pool);
|
_cfg.setTunnelPool(_pool);
|
||||||
_cfg.setTestJob(testJob);
|
_cfg.setTestJob(testJob);
|
||||||
_cfg.setRebuildJob(rebuildJob);
|
_cfg.setRebuildJob(rebuildJob);
|
||||||
_cfg.setExpireJob(expireJob);
|
_cfg.setExpireJob(expireJob);
|
||||||
if (_cfg.getLength() > 1) // no need to test 0 hop tunnels
|
if (_cfg.getLength() > 1) // no need to test 0 hop tunnels
|
||||||
getContext().jobQueue().addJob(testJob);
|
getContext().jobQueue().addJob(testJob);
|
||||||
if (!_fake) // if we built a 0 hop tunnel in response to a failure, don't rebuild
|
getContext().jobQueue().addJob(rebuildJob); // always try to rebuild (ignored if too many)
|
||||||
getContext().jobQueue().addJob(rebuildJob);
|
|
||||||
getContext().jobQueue().addJob(expireJob);
|
getContext().jobQueue().addJob(expireJob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,20 +11,18 @@ import net.i2p.router.tunnel.TunnelCreatorConfig;
|
|||||||
*/
|
*/
|
||||||
class RebuildJob extends JobImpl {
|
class RebuildJob extends JobImpl {
|
||||||
private TunnelPool _pool;
|
private TunnelPool _pool;
|
||||||
private Object _buildToken;
|
|
||||||
private TunnelCreatorConfig _cfg;
|
private TunnelCreatorConfig _cfg;
|
||||||
|
|
||||||
public RebuildJob(RouterContext ctx, TunnelCreatorConfig cfg, TunnelPool pool, Object buildToken) {
|
public RebuildJob(RouterContext ctx, TunnelCreatorConfig cfg, TunnelPool pool) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
_pool = pool;
|
_pool = pool;
|
||||||
_cfg = cfg;
|
_cfg = cfg;
|
||||||
_buildToken = buildToken;
|
|
||||||
long rebuildOn = cfg.getExpiration() - pool.getSettings().getRebuildPeriod();
|
long rebuildOn = cfg.getExpiration() - pool.getSettings().getRebuildPeriod();
|
||||||
rebuildOn -= ctx.random().nextInt(pool.getSettings().getRebuildPeriod()*2);
|
rebuildOn -= ctx.random().nextInt(pool.getSettings().getRebuildPeriod()*2);
|
||||||
getTiming().setStartAfter(rebuildOn);
|
getTiming().setStartAfter(rebuildOn);
|
||||||
}
|
}
|
||||||
public String getName() { return "Rebuild tunnel"; }
|
public String getName() { return "Rebuild tunnel"; }
|
||||||
public void runJob() {
|
public void runJob() {
|
||||||
_pool.getBuilder().buildTunnel(getContext(), _pool, _buildToken);
|
_pool.getBuilder().buildTunnel(getContext(), _pool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,19 +24,17 @@ import net.i2p.util.Log;
|
|||||||
class TestJob extends JobImpl {
|
class TestJob extends JobImpl {
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private TunnelPool _pool;
|
private TunnelPool _pool;
|
||||||
private Object _buildToken;
|
|
||||||
private PooledTunnelCreatorConfig _cfg;
|
private PooledTunnelCreatorConfig _cfg;
|
||||||
private boolean _found;
|
private boolean _found;
|
||||||
|
|
||||||
/** base to randomize the test delay on */
|
/** base to randomize the test delay on */
|
||||||
private static final int TEST_DELAY = 60*1000;
|
private static final int TEST_DELAY = 60*1000;
|
||||||
|
|
||||||
public TestJob(RouterContext ctx, PooledTunnelCreatorConfig cfg, TunnelPool pool, Object buildToken) {
|
public TestJob(RouterContext ctx, PooledTunnelCreatorConfig cfg, TunnelPool pool) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
_log = ctx.logManager().getLog(TestJob.class);
|
_log = ctx.logManager().getLog(TestJob.class);
|
||||||
_pool = pool;
|
_pool = pool;
|
||||||
_cfg = cfg;
|
_cfg = cfg;
|
||||||
_buildToken = buildToken;
|
|
||||||
getTiming().setStartAfter(getDelay() + ctx.clock().now());
|
getTiming().setStartAfter(getDelay() + ctx.clock().now());
|
||||||
ctx.statManager().createRateStat("tunnel.testFailedTime", "How long did the failure take (max of 60s for full timeout)?", "Tunnels",
|
ctx.statManager().createRateStat("tunnel.testFailedTime", "How long did the failure take (max of 60s for full timeout)?", "Tunnels",
|
||||||
new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l });
|
new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l });
|
||||||
|
|||||||
@@ -27,50 +27,42 @@ public class TunnelBuilder {
|
|||||||
* jobs are built. This call does not block.
|
* jobs are built. This call does not block.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void buildTunnel(RouterContext ctx, TunnelPool pool, Object poolToken) {
|
public void buildTunnel(RouterContext ctx, TunnelPool pool) {
|
||||||
buildTunnel(ctx, pool, false, poolToken);
|
buildTunnel(ctx, pool, false);
|
||||||
}
|
}
|
||||||
public void buildTunnel(RouterContext ctx, TunnelPool pool, boolean fake, Object poolToken) {
|
public void buildTunnel(RouterContext ctx, TunnelPool pool, boolean zeroHop) {
|
||||||
if (!pool.keepBuilding(poolToken))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// this is probably overkill (ya think?)
|
// this is probably overkill (ya think?)
|
||||||
pool.refreshSettings();
|
pool.refreshSettings();
|
||||||
|
|
||||||
PooledTunnelCreatorConfig cfg = configTunnel(ctx, pool, fake);
|
PooledTunnelCreatorConfig cfg = configTunnel(ctx, pool, zeroHop);
|
||||||
if ( (cfg == null) && (!fake) ) {
|
if (cfg == null) {
|
||||||
RetryJob j = new RetryJob(ctx, pool, poolToken);
|
RetryJob j = new RetryJob(ctx, pool);
|
||||||
j.getTiming().setStartAfter(ctx.clock().now() + ctx.random().nextInt(30*1000));
|
j.getTiming().setStartAfter(ctx.clock().now() + ctx.random().nextInt(30*1000));
|
||||||
ctx.jobQueue().addJob(j);
|
ctx.jobQueue().addJob(j);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OnCreatedJob onCreated = new OnCreatedJob(ctx, pool, cfg, fake, poolToken);
|
OnCreatedJob onCreated = new OnCreatedJob(ctx, pool, cfg);
|
||||||
RetryJob onFailed= (fake ? null : new RetryJob(ctx, pool, poolToken));
|
RetryJob onFailed= (zeroHop ? null : new RetryJob(ctx, pool));
|
||||||
// queue up a job to request the endpoint to join the tunnel, which then
|
// queue up a job to request the endpoint to join the tunnel, which then
|
||||||
// requeues up another job for earlier hops, etc, until it reaches the
|
// requeues up another job for earlier hops, etc, until it reaches the
|
||||||
// gateway. after the gateway is confirmed, onCreated is fired
|
// gateway. after the gateway is confirmed, onCreated is fired
|
||||||
RequestTunnelJob req = new RequestTunnelJob(ctx, cfg, onCreated, onFailed, cfg.getLength()-1, fake, pool.getSettings().isExploratory());
|
RequestTunnelJob req = new RequestTunnelJob(ctx, cfg, onCreated, onFailed, cfg.getLength()-1, zeroHop, pool.getSettings().isExploratory());
|
||||||
if (fake) // lets get it done inline, as we /need/ it asap
|
if (zeroHop || (cfg.getLength() <= 1) ) // lets get it done inline, as we /need/ it asap
|
||||||
req.runJob();
|
req.runJob();
|
||||||
else
|
else
|
||||||
ctx.jobQueue().addJob(req);
|
ctx.jobQueue().addJob(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PooledTunnelCreatorConfig configTunnel(RouterContext ctx, TunnelPool pool, boolean fake) {
|
private PooledTunnelCreatorConfig configTunnel(RouterContext ctx, TunnelPool pool, boolean zeroHop) {
|
||||||
Log log = ctx.logManager().getLog(TunnelBuilder.class);
|
Log log = ctx.logManager().getLog(TunnelBuilder.class);
|
||||||
TunnelPoolSettings settings = pool.getSettings();
|
TunnelPoolSettings settings = pool.getSettings();
|
||||||
long expiration = ctx.clock().now() + settings.getDuration();
|
long expiration = ctx.clock().now() + settings.getDuration();
|
||||||
List peers = null;
|
List peers = null;
|
||||||
|
|
||||||
long failures = countFailures(ctx);
|
if (zeroHop) {
|
||||||
boolean failing = (failures > 5) && (pool.getSettings().getAllowZeroHop());
|
|
||||||
boolean failsafe = false;
|
|
||||||
if (failing && (ctx.random().nextInt(100) < failures) )
|
|
||||||
failsafe = true;
|
|
||||||
if (fake || failsafe) {
|
|
||||||
peers = new ArrayList(1);
|
peers = new ArrayList(1);
|
||||||
peers.add(ctx.routerHash());
|
peers.add(ctx.routerHash());
|
||||||
if ( (failsafe) && (log.shouldLog(Log.WARN)) )
|
if (log.shouldLog(Log.WARN))
|
||||||
log.warn("Building failsafe tunnel for " + pool);
|
log.warn("Building failsafe tunnel for " + pool);
|
||||||
} else {
|
} else {
|
||||||
peers = pool.getSelector().selectPeers(ctx, settings);
|
peers = pool.getSelector().selectPeers(ctx, settings);
|
||||||
@@ -80,10 +72,10 @@ public class TunnelBuilder {
|
|||||||
// the pool is refusing 0 hop tunnels
|
// the pool is refusing 0 hop tunnels
|
||||||
if (peers == null) {
|
if (peers == null) {
|
||||||
if (log.shouldLog(Log.ERROR))
|
if (log.shouldLog(Log.ERROR))
|
||||||
log.error("No peers to put in the new tunnel! selectPeers returned null! boo, hiss! fake=" + fake);
|
log.error("No peers to put in the new tunnel! selectPeers returned null! boo, hiss! fake=" + zeroHop);
|
||||||
} else {
|
} else {
|
||||||
if (log.shouldLog(Log.ERROR))
|
if (log.shouldLog(Log.ERROR))
|
||||||
log.error("No peers to put in the new tunnel! selectPeers returned an empty list?! fake=" + fake);
|
log.error("No peers to put in the new tunnel! selectPeers returned an empty list?! fake=" + zeroHop);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -108,36 +100,20 @@ public class TunnelBuilder {
|
|||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long countFailures(RouterContext ctx) {
|
|
||||||
RateStat rs = ctx.statManager().getRate("tunnel.testFailedTime");
|
|
||||||
if (rs == null)
|
|
||||||
return 0;
|
|
||||||
Rate r = rs.getRate(10*60*1000);
|
|
||||||
if (r == null)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return r.getCurrentEventCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the building fails, try, try again.
|
* If the building fails, try, try again.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private class RetryJob extends JobImpl {
|
private class RetryJob extends JobImpl {
|
||||||
private TunnelPool _pool;
|
private TunnelPool _pool;
|
||||||
private Object _buildToken;
|
public RetryJob(RouterContext ctx, TunnelPool pool) {
|
||||||
public RetryJob(RouterContext ctx, TunnelPool pool, Object buildToken) {
|
|
||||||
super(ctx);
|
super(ctx);
|
||||||
_pool = pool;
|
_pool = pool;
|
||||||
_buildToken = buildToken;
|
|
||||||
}
|
}
|
||||||
public String getName() { return "tunnel create failed"; }
|
public String getName() { return "Tunnel create failed"; }
|
||||||
public void runJob() {
|
public void runJob() {
|
||||||
// yikes, nothing left, lets get some backup (if we're allowed)
|
// yikes, nothing left, lets get some backup (if we're allowed)
|
||||||
if ( (_pool.selectTunnel() == null) && (_pool.getSettings().getAllowZeroHop()) )
|
_pool.refreshBuilders();
|
||||||
_pool.buildFake();
|
|
||||||
|
|
||||||
buildTunnel(getContext(), _pool, _buildToken);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,14 +30,6 @@ public class TunnelPool {
|
|||||||
private boolean _alive;
|
private boolean _alive;
|
||||||
private long _lifetimeProcessed;
|
private long _lifetimeProcessed;
|
||||||
|
|
||||||
/**
|
|
||||||
* list of pool tokens (Object) passed around during building/rebuilding/etc.
|
|
||||||
* if/when the token is removed from this list, that sequence of building/rebuilding/etc
|
|
||||||
* should cease (though others may continue).
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private List _tokens;
|
|
||||||
|
|
||||||
public TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel, TunnelBuilder builder) {
|
public TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel, TunnelBuilder builder) {
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
_log = ctx.logManager().getLog(TunnelPool.class);
|
_log = ctx.logManager().getLog(TunnelPool.class);
|
||||||
@@ -46,7 +38,6 @@ public class TunnelPool {
|
|||||||
_tunnels = new ArrayList(settings.getLength() + settings.getBackupQuantity());
|
_tunnels = new ArrayList(settings.getLength() + settings.getBackupQuantity());
|
||||||
_peerSelector = sel;
|
_peerSelector = sel;
|
||||||
_builder = builder;
|
_builder = builder;
|
||||||
_tokens = new ArrayList(settings.getBackupQuantity() + settings.getQuantity());
|
|
||||||
_alive = false;
|
_alive = false;
|
||||||
_lifetimeProcessed = 0;
|
_lifetimeProcessed = 0;
|
||||||
refreshSettings();
|
refreshSettings();
|
||||||
@@ -70,102 +61,39 @@ public class TunnelPool {
|
|||||||
}
|
}
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
_alive = false;
|
_alive = false;
|
||||||
synchronized (_tokens) { _tokens.clear(); }
|
}
|
||||||
|
|
||||||
|
private int countUsableTunnels() {
|
||||||
|
int valid = 0;
|
||||||
|
synchronized (_tunnels) {
|
||||||
|
for (int i = 0; i < _tunnels.size(); i++) {
|
||||||
|
TunnelInfo info = (TunnelInfo)_tunnels.get(i);
|
||||||
|
if (info.getExpiration() > _context.clock().now() + 3*_settings.getRebuildPeriod())
|
||||||
|
valid++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int refreshBuilders() {
|
/**
|
||||||
|
* Fire up as many buildTunnel tasks as necessary, returning how many
|
||||||
|
* were added
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int refreshBuilders() {
|
||||||
|
if (!_alive) return 0;
|
||||||
// only start up new build tasks if we need more of 'em
|
// only start up new build tasks if we need more of 'em
|
||||||
int target = _settings.getQuantity() + _settings.getBackupQuantity();
|
int target = _settings.getQuantity() + _settings.getBackupQuantity();
|
||||||
int oldTokenCount = 0;
|
int usableTunnels = countUsableTunnels();
|
||||||
List newTokens = null;
|
|
||||||
synchronized (_tokens) {
|
|
||||||
oldTokenCount = _tokens.size();
|
|
||||||
while (_tokens.size() > target)
|
|
||||||
_tokens.remove(0);
|
|
||||||
if (_tokens.size() < target) {
|
|
||||||
int wanted = target - _tokens.size();
|
|
||||||
newTokens = new ArrayList(wanted);
|
|
||||||
for (int i = 0; i < wanted; i++) {
|
|
||||||
Object token = new Object();
|
|
||||||
newTokens.add(token);
|
|
||||||
_tokens.add(token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newTokens != null) {
|
if ( (target > usableTunnels) && (_log.shouldLog(Log.INFO)) )
|
||||||
if (_log.shouldLog(Log.INFO))
|
_log.info(toString() + ": refreshing builders, previously had " + usableTunnels
|
||||||
_log.info(toString() + ": refreshing builders, previously had " + oldTokenCount
|
|
||||||
+ ", want a total of " + target + ", creating "
|
+ ", want a total of " + target + ", creating "
|
||||||
+ newTokens.size() + " new ones.");
|
+ (target-usableTunnels) + " new ones.");
|
||||||
for (int i = 0; i < newTokens.size(); i++) {
|
for (int i = usableTunnels; i < target; i++)
|
||||||
Object token = newTokens.get(i);
|
_builder.buildTunnel(_context, this);
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
|
||||||
_log.debug(toString() + ": Building a tunnel with the token " + token);
|
|
||||||
_builder.buildTunnel(_context, this, token);
|
|
||||||
}
|
|
||||||
return newTokens.size();
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** do we still need this sequence of build/rebuild/etc to continue? */
|
|
||||||
public boolean keepBuilding(Object token) {
|
|
||||||
boolean connected = true;
|
|
||||||
boolean rv = false;
|
|
||||||
int remaining = 0;
|
|
||||||
int wanted = _settings.getQuantity() + _settings.getBackupQuantity();
|
|
||||||
if ( (_settings.getDestination() != null) && (!_context.clientManager().isLocal(_settings.getDestination())) )
|
|
||||||
connected = false;
|
|
||||||
synchronized (_tokens) {
|
|
||||||
if (!connected) {
|
|
||||||
// client disconnected, so stop rebuilding this series
|
|
||||||
_tokens.remove(token);
|
|
||||||
rv = false;
|
|
||||||
} else {
|
|
||||||
rv = _tokens.contains(token);
|
|
||||||
}
|
|
||||||
remaining = _tokens.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remaining <= 0) {
|
return (target > usableTunnels ? target-usableTunnels : 0);
|
||||||
_manager.removeTunnels(_settings.getDestination());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rv) {
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
|
||||||
_log.info(toString() + ": keepBuilding does NOT want building to continue (want "
|
|
||||||
+ wanted + ", have " + remaining);
|
|
||||||
} else {
|
|
||||||
boolean needed = true;
|
|
||||||
int valid = 0;
|
|
||||||
synchronized (_tunnels) {
|
|
||||||
if (_tunnels.size() > wanted) {
|
|
||||||
for (int i = 0; i < _tunnels.size(); i++) {
|
|
||||||
TunnelInfo info = (TunnelInfo)_tunnels.get(i);
|
|
||||||
if (info.getExpiration() > _context.clock().now() + 3*_settings.getRebuildPeriod()) {
|
|
||||||
valid++;
|
|
||||||
if (valid >= wanted*2)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (valid >= wanted*2)
|
|
||||||
needed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!needed) {
|
|
||||||
if (_log.shouldLog(Log.WARN))
|
|
||||||
_log.warn(toString() + ": keepBuilding wants building to continue, but not "
|
|
||||||
+ " with the current object... # tunnels = " + valid + ", wanted = " + wanted);
|
|
||||||
synchronized (_tokens) {
|
|
||||||
_tokens.remove(token);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void refreshSettings() {
|
void refreshSettings() {
|
||||||
@@ -210,7 +138,7 @@ public class TunnelPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_alive && _settings.getAllowZeroHop())
|
if (_alive && _settings.getAllowZeroHop())
|
||||||
buildFake();
|
buildFallback();
|
||||||
if (allowRecurseOnFail)
|
if (allowRecurseOnFail)
|
||||||
return selectTunnel(false);
|
return selectTunnel(false);
|
||||||
else
|
else
|
||||||
@@ -244,6 +172,8 @@ public class TunnelPool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getTunnelCount() { synchronized (_tunnels) { return _tunnels.size(); } }
|
||||||
|
|
||||||
public TunnelBuilder getBuilder() { return _builder; }
|
public TunnelBuilder getBuilder() { return _builder; }
|
||||||
public TunnelPoolSettings getSettings() { return _settings; }
|
public TunnelPoolSettings getSettings() { return _settings; }
|
||||||
public void setSettings(TunnelPoolSettings settings) {
|
public void setSettings(TunnelPoolSettings settings) {
|
||||||
@@ -274,6 +204,8 @@ public class TunnelPool {
|
|||||||
|
|
||||||
if (ls != null)
|
if (ls != null)
|
||||||
_context.clientManager().requestLeaseSet(_settings.getDestination(), ls);
|
_context.clientManager().requestLeaseSet(_settings.getDestination(), ls);
|
||||||
|
|
||||||
|
refreshBuilders();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTunnel(TunnelInfo info) {
|
public void removeTunnel(TunnelInfo info) {
|
||||||
@@ -298,9 +230,17 @@ public class TunnelPool {
|
|||||||
_log.warn(toString() + ": unable to build a new leaseSet on removal (" + remaining
|
_log.warn(toString() + ": unable to build a new leaseSet on removal (" + remaining
|
||||||
+ " remaining), request a new tunnel");
|
+ " remaining), request a new tunnel");
|
||||||
if (_settings.getAllowZeroHop())
|
if (_settings.getAllowZeroHop())
|
||||||
buildFake();
|
buildFallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean connected = true;
|
||||||
|
if ( (_settings.getDestination() != null) && (!_context.clientManager().isLocal(_settings.getDestination())) )
|
||||||
|
connected = false;
|
||||||
|
if ( (getTunnelCount() <= 0) && (!connected) ) {
|
||||||
|
_manager.removeTunnels(_settings.getDestination());
|
||||||
|
return;
|
||||||
|
}
|
||||||
refreshBuilders();
|
refreshBuilders();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +266,7 @@ public class TunnelPool {
|
|||||||
_log.warn(toString() + ": unable to build a new leaseSet on failure (" + remaining
|
_log.warn(toString() + ": unable to build a new leaseSet on failure (" + remaining
|
||||||
+ " remaining), request a new tunnel");
|
+ " remaining), request a new tunnel");
|
||||||
if (remaining < _settings.getBackupQuantity() + _settings.getQuantity())
|
if (remaining < _settings.getBackupQuantity() + _settings.getQuantity())
|
||||||
buildFake(false);
|
buildFallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
refreshBuilders();
|
refreshBuilders();
|
||||||
@@ -350,43 +290,23 @@ public class TunnelPool {
|
|||||||
+ " remaining), request a new tunnel");
|
+ " remaining), request a new tunnel");
|
||||||
if ( (remaining < _settings.getBackupQuantity() + _settings.getQuantity())
|
if ( (remaining < _settings.getBackupQuantity() + _settings.getQuantity())
|
||||||
&& (_settings.getAllowZeroHop()) )
|
&& (_settings.getAllowZeroHop()) )
|
||||||
buildFake();
|
buildFallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildFake() { buildFake(true); }
|
void buildFallback() {
|
||||||
void buildFake(boolean zeroHop) {
|
|
||||||
int quantity = _settings.getBackupQuantity() + _settings.getQuantity();
|
int quantity = _settings.getBackupQuantity() + _settings.getQuantity();
|
||||||
boolean needed = true;
|
int usable = countUsableTunnels();
|
||||||
synchronized (_tunnels) {
|
if (usable >= quantity) return;
|
||||||
if (_tunnels.size() > quantity) {
|
|
||||||
int valid = 0;
|
|
||||||
for (int i = 0; i < _tunnels.size(); i++) {
|
|
||||||
TunnelInfo info = (TunnelInfo)_tunnels.get(i);
|
|
||||||
if (info.getExpiration() > _context.clock().now() + 3*_settings.getRebuildPeriod()) {
|
|
||||||
valid++;
|
|
||||||
if (valid >= quantity)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (valid >= quantity)
|
|
||||||
needed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!needed) return;
|
|
||||||
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info(toString() + ": building a fake tunnel (allow zeroHop? " + zeroHop + ")");
|
_log.info(toString() + ": building a fallback tunnel (usable: " + usable + " needed: " + quantity + ")");
|
||||||
Object tempToken = new Object();
|
if ( (usable == 0) && (_settings.getAllowZeroHop()) )
|
||||||
synchronized (_tokens) {
|
_builder.buildTunnel(_context, this, true);
|
||||||
_tokens.add(tempToken);
|
else
|
||||||
}
|
_builder.buildTunnel(_context, this);
|
||||||
_builder.buildTunnel(_context, this, zeroHop, tempToken);
|
refreshBuilders();
|
||||||
synchronized (_tokens) {
|
|
||||||
_tokens.remove(tempToken);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,12 +26,14 @@ import net.i2p.router.TunnelInfo;
|
|||||||
import net.i2p.router.TunnelManagerFacade;
|
import net.i2p.router.TunnelManagerFacade;
|
||||||
import net.i2p.router.TunnelPoolSettings;
|
import net.i2p.router.TunnelPoolSettings;
|
||||||
import net.i2p.router.tunnel.HopConfig;
|
import net.i2p.router.tunnel.HopConfig;
|
||||||
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TunnelPoolManager implements TunnelManagerFacade {
|
public class TunnelPoolManager implements TunnelManagerFacade {
|
||||||
private RouterContext _context;
|
private RouterContext _context;
|
||||||
|
private Log _log;
|
||||||
/** Hash (destination) to TunnelPool */
|
/** Hash (destination) to TunnelPool */
|
||||||
private Map _clientInboundPools;
|
private Map _clientInboundPools;
|
||||||
/** Hash (destination) to TunnelPool */
|
/** Hash (destination) to TunnelPool */
|
||||||
@@ -41,6 +43,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
|
|
||||||
public TunnelPoolManager(RouterContext ctx) {
|
public TunnelPoolManager(RouterContext ctx) {
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
|
_log = ctx.logManager().getLog(TunnelPoolManager.class);
|
||||||
|
|
||||||
HandlerJobBuilder builder = new HandleTunnelCreateMessageJob.Builder(ctx);
|
HandlerJobBuilder builder = new HandleTunnelCreateMessageJob.Builder(ctx);
|
||||||
ctx.inNetMessagePool().registerHandlerJobBuilder(TunnelCreateMessage.MESSAGE_TYPE, builder);
|
ctx.inNetMessagePool().registerHandlerJobBuilder(TunnelCreateMessage.MESSAGE_TYPE, builder);
|
||||||
@@ -63,7 +66,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
public TunnelInfo selectInboundTunnel() {
|
public TunnelInfo selectInboundTunnel() {
|
||||||
TunnelInfo info = _inboundExploratory.selectTunnel();
|
TunnelInfo info = _inboundExploratory.selectTunnel();
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
_inboundExploratory.buildFake();
|
_inboundExploratory.buildFallback();
|
||||||
// still can be null, but probably not
|
// still can be null, but probably not
|
||||||
info = _inboundExploratory.selectTunnel();
|
info = _inboundExploratory.selectTunnel();
|
||||||
}
|
}
|
||||||
@@ -80,6 +83,9 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
if (pool != null) {
|
if (pool != null) {
|
||||||
return pool.selectTunnel();
|
return pool.selectTunnel();
|
||||||
}
|
}
|
||||||
|
if (_log.shouldLog(Log.CRIT))
|
||||||
|
_log.log(Log.CRIT, "wtf, want the inbound tunnel for " + destination.calculateHash().toBase64() +
|
||||||
|
" but there isn't a pool?");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +93,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
public TunnelInfo selectOutboundTunnel() {
|
public TunnelInfo selectOutboundTunnel() {
|
||||||
TunnelInfo info = _outboundExploratory.selectTunnel();
|
TunnelInfo info = _outboundExploratory.selectTunnel();
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
_outboundExploratory.buildFake();
|
_outboundExploratory.buildFallback();
|
||||||
// still can be null, but probably not
|
// still can be null, but probably not
|
||||||
info = _outboundExploratory.selectTunnel();
|
info = _outboundExploratory.selectTunnel();
|
||||||
}
|
}
|
||||||
@@ -224,6 +230,10 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
|
|
||||||
public void removeTunnels(Hash destination) {
|
public void removeTunnels(Hash destination) {
|
||||||
if (destination == null) return;
|
if (destination == null) return;
|
||||||
|
if (_context.clientManager().isLocal(destination)) {
|
||||||
|
if (_log.shouldLog(Log.CRIT))
|
||||||
|
_log.log(Log.CRIT, "wtf, why are you removing the pool for " + destination.toBase64(), new Exception("i did it"));
|
||||||
|
}
|
||||||
TunnelPool inbound = null;
|
TunnelPool inbound = null;
|
||||||
TunnelPool outbound = null;
|
TunnelPool outbound = null;
|
||||||
synchronized (_clientInboundPools) {
|
synchronized (_clientInboundPools) {
|
||||||
@@ -268,7 +278,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
}
|
}
|
||||||
public String getName() { return "Bootstrap tunnel pool"; }
|
public String getName() { return "Bootstrap tunnel pool"; }
|
||||||
public void runJob() {
|
public void runJob() {
|
||||||
_pool.buildFake(false);
|
_pool.buildFallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user