Router: Add startup/shutdown state machine

Tunnels: Cleanup, catch more cases of zero-hop configuration
ClientAppConfig: Start i2ptunnel sooner
  Since BuildRequestor won't use a zero-hop exploratory as a paired tunnel
  for client builds, it's now safe to start client tunnels
  before the expl. tunnels are ready. This will save up to 90 seconds.
This commit is contained in:
zzz
2015-01-07 17:54:21 +00:00
parent b3238079c3
commit 37f34d83f8
12 changed files with 291 additions and 64 deletions

View File

@ -1,3 +1,8 @@
2015-01-07 zzz
* ClientAppConfig: Start i2ptunnel sooner
* Router: Add startup/shutdown state machine
* Tunnels: Cleanup, catch more cases of zero-hop configuration
2015-01-05 zzz
* Blocklist:
- Rewrite to read and merge multiple files

View File

@ -39,6 +39,7 @@ clientApp.1.startOnLoad=false
clientApp.2.main=net.i2p.i2ptunnel.TunnelControllerGroup
clientApp.2.name=Application tunnels
clientApp.2.args=i2ptunnel.config
clientApp.2.delay=35
clientApp.2.startOnLoad=true
# run our own eepsite with a seperate jetty instance

View File

@ -78,16 +78,15 @@ public class Router implements RouterClock.ClockShiftListener {
private boolean _higherVersionSeen;
//private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
private boolean _killVMOnEnd;
private volatile boolean _isAlive;
private int _gracefulExitCode;
private I2PThread.OOMEventListener _oomListener;
private ShutdownHook _shutdownHook;
/** non-cancellable shutdown has begun */
private volatile boolean _shutdownInProgress;
private I2PThread _gracefulShutdownDetector;
private RouterWatchdog _watchdog;
private Thread _watchdogThread;
private final EventLog _eventLog;
private final Object _stateLock = new Object();
private State _state = State.UNINITIALIZED;
public final static String PROP_CONFIG_FILE = "router.configLocation";
@ -105,7 +104,8 @@ public class Router implements RouterClock.ClockShiftListener {
/** this does not put an 'H' in your routerInfo **/
public final static String PROP_HIDDEN_HIDDEN = "router.isHidden";
public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys";
public final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress";
/** deprecated, use gracefulShutdownInProgress() */
private final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress";
private static final String PROP_IB_RANDOM_KEY = TunnelPoolSettings.PREFIX_INBOUND_EXPLORATORY + TunnelPoolSettings.PROP_RANDOM_KEY;
private static final String PROP_OB_RANDOM_KEY = TunnelPoolSettings.PREFIX_OUTBOUND_EXPLORATORY + TunnelPoolSettings.PROP_RANDOM_KEY;
public final static String DNS_CACHE_TIME = "" + (5*60);
@ -287,6 +287,7 @@ public class Router implements RouterClock.ClockShiftListener {
_config.put("router.previousVersion", RouterVersion.VERSION);
saveConfig();
}
changeState(State.INITIALIZED);
// ********* Start no threads before here ********* //
}
@ -459,11 +460,16 @@ public class Router implements RouterClock.ClockShiftListener {
* Standard standalone installation uses main() instead, which
* checks for updates and then calls this.
*
* This may take quite a while, especially if NTP fails.
*
* @since public as of 0.9 for Android and other embedded uses
*/
public synchronized void runRouter() {
if (_isAlive)
throw new IllegalStateException();
synchronized(_stateLock) {
if (_state != State.INITIALIZED)
throw new IllegalStateException();
changeState(State.STARTING_1);
}
String last = _config.get("router.previousFullVersion");
if (last != null) {
_eventLog.addEvent(EventLog.UPDATED, "from " + last + " to " + RouterVersion.FULL_VERSION);
@ -471,7 +477,7 @@ public class Router implements RouterClock.ClockShiftListener {
}
_eventLog.addEvent(EventLog.STARTED, RouterVersion.FULL_VERSION);
startupStuff();
_isAlive = true;
changeState(State.STARTING_2);
_started = _context.clock().now();
try {
Runtime.getRuntime().addShutdownHook(_shutdownHook);
@ -518,6 +524,7 @@ public class Router implements RouterClock.ClockShiftListener {
if (_log.shouldLog(Log.INFO))
_log.info("Waited " + waited + "ms to initialize");
changeState(State.STARTING_3);
_context.jobQueue().addJob(new StartupJob(_context));
}
@ -573,9 +580,141 @@ public class Router implements RouterClock.ClockShiftListener {
}
return props;
}
////////// begin state management
public boolean isAlive() { return _isAlive; }
/**
* Startup / shutdown states
*
* @since 0.9.18
*/
private enum State {
UNINITIALIZED,
/** constructor complete */
INITIALIZED,
/** runRouter() called */
STARTING_1,
/** startupStuff() complete, most of the time here is NTP */
STARTING_2,
/** NTP done, Job queue started, StartupJob queued, runRouter() returned */
STARTING_3,
/** RIs loaded. From STARTING_3 */
NETDB_READY,
/** Non-zero-hop expl. tunnels built. From STARTING_3 */
EXPL_TUNNELS_READY,
/** from NETDB_READY or EXPL_TUNNELS_READY */
RUNNING,
/**
* A "soft" restart, primarily of the comm system, after
* a port change or large step-change in system time.
* Does not stop the whole JVM, so it is safe even in the absence
* of the wrapper.
* This is not a graceful restart - all peer connections are dropped immediately.
*/
RESTARTING,
/** cancellable shutdown has begun */
GRACEFUL_SHUTDOWN,
/** In shutdown(). Non-cancellable shutdown has begun */
FINAL_SHUTDOWN_1,
/** In shutdown2(). Killing everything */
FINAL_SHUTDOWN_2,
/** In finalShutdown(). Final cleanup */
FINAL_SHUTDOWN_3,
/** all done */
STOPPED
}
/**
* @since 0.9.18
*/
private void changeState(State state) {
State oldState;
synchronized(_stateLock) {
oldState = _state;
_state = state;
}
if (_log != null && state != State.STOPPED && _log.shouldLog(Log.WARN))
_log.warn("Router state change from " + oldState + " to " + state /* , new Exception() */ );
}
/**
* True during the initial start, but false during a soft restart.
*/
public boolean isAlive() {
synchronized(_stateLock) {
return _state == State.RUNNING ||
_state == State.GRACEFUL_SHUTDOWN ||
_state == State.STARTING_1 ||
_state == State.STARTING_2 ||
_state == State.STARTING_3 ||
_state == State.NETDB_READY ||
_state == State.EXPL_TUNNELS_READY;
}
}
/**
* Only for Restarter, after soft restart is complete
* @since 0.8.12
*/
public void setIsAlive() {
changeState(State.RUNNING);
}
/**
* Only for NetDB, after RIs are loaded
* @since 0.9.18
*/
public void setNetDbReady() {
synchronized(_stateLock) {
if (_state == State.STARTING_3)
changeState(State.NETDB_READY);
else if (_state == State.EXPL_TUNNELS_READY)
changeState(State.RUNNING);
}
}
/**
* Only for Tunnel Building, after we have non-zero-hop expl. tunnels
* @since 0.9.18
*/
public void setExplTunnelsReady() {
synchronized(_stateLock) {
if (_state == State.STARTING_3)
changeState(State.EXPL_TUNNELS_READY);
else if (_state == State.NETDB_READY)
changeState(State.RUNNING);
}
}
/**
* Is a graceful shutdown in progress? This may be cancelled.
* Note that this also returns true if an uncancellable final shutdown is in progress.
*/
public boolean gracefulShutdownInProgress() {
synchronized(_stateLock) {
return _state == State.GRACEFUL_SHUTDOWN ||
_state == State.FINAL_SHUTDOWN_1 ||
_state == State.FINAL_SHUTDOWN_2 ||
_state == State.FINAL_SHUTDOWN_3 ||
_state == State.STOPPED;
}
}
/**
* Is a final shutdown in progress? This may not be cancelled.
* @since 0.8.12
*/
public boolean isFinalShutdownInProgress() {
synchronized(_stateLock) {
return _state == State.FINAL_SHUTDOWN_1 ||
_state == State.FINAL_SHUTDOWN_2 ||
_state == State.FINAL_SHUTDOWN_3 ||
_state == State.STOPPED;
}
}
////////// end state management
/**
* Rebuild and republish our routerInfo since something significant
* has changed.
@ -801,9 +940,14 @@ public class Router implements RouterClock.ClockShiftListener {
* Shutdown with no chance of cancellation
*/
public synchronized void shutdown(int exitCode) {
if (_shutdownInProgress)
return;
_shutdownInProgress = true;
synchronized(_stateLock) {
if (_state == State.FINAL_SHUTDOWN_1 ||
_state == State.FINAL_SHUTDOWN_2 ||
_state == State.FINAL_SHUTDOWN_3 ||
_state == State.STOPPED)
return;
changeState(State.FINAL_SHUTDOWN_1);
}
_context.throttle().setShutdownStatus();
if (_shutdownHook != null) {
try {
@ -819,10 +963,10 @@ public class Router implements RouterClock.ClockShiftListener {
* NOT to be called by others, use shutdown().
*/
public synchronized void shutdown2(int exitCode) {
changeState(State.FINAL_SHUTDOWN_2);
// help us shut down esp. after OOM
int priority = (exitCode == EXIT_OOM) ? Thread.MAX_PRIORITY - 1 : Thread.NORM_PRIORITY + 2;
Thread.currentThread().setPriority(priority);
_shutdownInProgress = true;
_log.log(Log.CRIT, "Starting final shutdown(" + exitCode + ')');
// So we can get all the way to the end
// No, you can't do Thread.currentThread.setDaemon(false)
@ -832,7 +976,6 @@ public class Router implements RouterClock.ClockShiftListener {
} catch (Throwable t) {}
}
((RouterClock) _context.clock()).removeShiftListener(this);
_isAlive = false;
_context.random().saveSeed();
I2PThread.removeOOMEventListener(_oomListener);
// Run the shutdown hooks first in case they want to send some goodbye messages
@ -916,6 +1059,7 @@ public class Router implements RouterClock.ClockShiftListener {
* Cancel the JVM runtime hook before calling this.
*/
private synchronized void finalShutdown(int exitCode) {
changeState(State.FINAL_SHUTDOWN_3);
clearCaches();
_log.log(Log.CRIT, "Shutdown(" + exitCode + ") complete" /* , new Exception("Shutdown") */ );
try { _context.logManager().shutdown(); } catch (Throwable t) { }
@ -948,6 +1092,7 @@ public class Router implements RouterClock.ClockShiftListener {
} else if (SystemVersion.isAndroid()) {
Runtime.getRuntime().gc();
}
changeState(State.STOPPED);
}
/**
@ -962,13 +1107,21 @@ public class Router implements RouterClock.ClockShiftListener {
public void shutdownGracefully() {
shutdownGracefully(EXIT_GRACEFUL);
}
/**
* Call this with EXIT_HARD or EXIT_HARD_RESTART for a non-blocking,
* hard, non-graceful shutdown with a brief delay to allow a UI response
*
* Returns silently if a final shutdown is already in progress.
*/
public void shutdownGracefully(int exitCode) {
synchronized(_stateLock) {
if (isFinalShutdownInProgress())
return; // too late
changeState(State.GRACEFUL_SHUTDOWN);
}
_gracefulExitCode = exitCode;
_config.put(PROP_SHUTDOWN_IN_PROGRESS, "true");
//_config.put(PROP_SHUTDOWN_IN_PROGRESS, "true");
_context.throttle().setShutdownStatus();
synchronized (_gracefulShutdownDetector) {
_gracefulShutdownDetector.notifyAll();
@ -978,10 +1131,16 @@ public class Router implements RouterClock.ClockShiftListener {
/**
* Cancel any prior request to shut the router down gracefully.
*
* Returns silently if a final shutdown is already in progress.
*/
public void cancelGracefulShutdown() {
synchronized(_stateLock) {
if (isFinalShutdownInProgress())
return; // too late
changeState(State.RUNNING);
}
_gracefulExitCode = -1;
_config.remove(PROP_SHUTDOWN_IN_PROGRESS);
//_config.remove(PROP_SHUTDOWN_IN_PROGRESS);
_context.throttle().cancelShutdownStatus();
synchronized (_gracefulShutdownDetector) {
_gracefulShutdownDetector.notifyAll();
@ -993,21 +1152,6 @@ public class Router implements RouterClock.ClockShiftListener {
*/
public int scheduledGracefulExitCode() { return _gracefulExitCode; }
/**
* Is a graceful shutdown in progress? This may be cancelled.
*/
public boolean gracefulShutdownInProgress() {
return (null != _config.get(PROP_SHUTDOWN_IN_PROGRESS));
}
/**
* Is a final shutdown in progress? This may not be cancelled.
* @since 0.8.12
*/
public boolean isFinalShutdownInProgress() {
return _shutdownInProgress;
}
/** How long until the graceful shutdown will kill us? */
public long getShutdownTimeRemaining() {
if (_gracefulExitCode <= 0) return -1; // maybe Long.MAX_VALUE would be better?
@ -1094,8 +1238,10 @@ public class Router implements RouterClock.ClockShiftListener {
* @since 0.8.8
*/
public void clockShift(long delta) {
if (gracefulShutdownInProgress() || !_isAlive)
return;
synchronized(_stateLock) {
if (gracefulShutdownInProgress() || !isAlive())
return;
}
if (delta > -60*1000 && delta < 60*1000)
return;
_eventLog.addEvent(EventLog.CLOCK_SHIFT, Long.toString(delta));
@ -1121,24 +1267,18 @@ public class Router implements RouterClock.ClockShiftListener {
* Poll isAlive() if you need to know when the restart is complete.
*/
public synchronized void restart() {
if (gracefulShutdownInProgress() || !_isAlive)
return;
synchronized(_stateLock) {
if (gracefulShutdownInProgress() || !isAlive())
return;
changeState(State.RESTARTING);
}
((RouterClock) _context.clock()).removeShiftListener(this);
_isAlive = false;
_started = _context.clock().now();
Thread t = new Thread(new Restarter(_context), "Router Restart");
t.setPriority(Thread.NORM_PRIORITY + 1);
t.start();
}
/**
* Only for Restarter
* @since 0.8.12
*/
public void setIsAlive() {
_isAlive = true;
}
/**
* Usage: Router [rebuild]
* No other options allowed, for now

View File

@ -107,7 +107,7 @@ class RouterThrottleImpl implements RouterThrottle {
* @return 0 for accept or nonzero reject code
*/
public int acceptTunnelRequest() {
if (_context.getProperty(Router.PROP_SHUTDOWN_IN_PROGRESS) != null) {
if (_context.router().gracefulShutdownInProgress()) {
if (_log.shouldLog(Log.WARN))
_log.warn("Refusing tunnel request since we are shutting down ASAP");
setShutdownStatus();

View File

@ -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 = 6;
public final static long BUILD = 7;
/** for example "-test" */
public final static String EXTRA = "";

View File

@ -66,7 +66,7 @@ class FloodfillMonitorJob extends JobImpl {
private boolean shouldBeFloodfill() {
// Only if not shutting down...
if (getContext().getProperty(Router.PROP_SHUTDOWN_IN_PROGRESS) != null)
if (getContext().router().gracefulShutdownInProgress())
return false;
// Hidden trumps netDb.floodfillParticipant=true

View File

@ -429,14 +429,21 @@ class PersistentDataStore extends TransientDataStore {
}
if (!_initialized) {
if (_facade.reseedChecker().checkReseed(routerCount))
if (_facade.reseedChecker().checkReseed(routerCount)) {
_lastReseed = _context.clock().now();
// checkReseed will call wakeup() when done and we will run again
} else {
_context.router().setNetDbReady();
}
_initialized = true;
} else if (_lastReseed < _context.clock().now() - MIN_RESEED_INTERVAL) {
int count = Math.min(routerCount, size());
if (count < MIN_ROUTERS) {
if (_facade.reseedChecker().checkReseed(count))
_lastReseed = _context.clock().now();
// checkReseed will call wakeup() when done and we will run again
} else {
_context.router().setNetDbReady();
}
}
}

View File

@ -65,7 +65,9 @@ import net.i2p.util.SecureFileOutputStream;
*/
public class ClientAppConfig {
/** wait 2 minutes before starting up client apps */
private final static long STARTUP_DELAY = 2*60*1000;
private final static long DEFAULT_STARTUP_DELAY = 2*60*1000;
/** speed up i2ptunnel without rewriting clients.config */
private final static long I2PTUNNEL_STARTUP_DELAY = 35*1000;
private static final String PROP_CLIENT_CONFIG_FILENAME = "router.clientConfigFile";
private static final String DEFAULT_CLIENT_CONFIG_FILENAME = "clients.config";
@ -183,7 +185,10 @@ public class ClientAppConfig {
if (onBoot != null)
onStartup = "true".equals(onBoot) || "yes".equals(onBoot);
long delay = (onStartup ? 0 : STARTUP_DELAY);
// speed up the start of i2ptunnel for everybody without rewriting clients.config
long delay = onStartup ? 0 :
(className.equals("net.i2p.i2ptunnel.TunnelControllerGroup") ?
I2PTUNNEL_STARTUP_DELAY : DEFAULT_STARTUP_DELAY);
if (delayStr != null && !onStartup)
try { delay = 1000*Integer.parseInt(delayStr); } catch (NumberFormatException nfe) {}

View File

@ -62,6 +62,10 @@ class BuildHandler implements Runnable {
private final BuildReplyHandler _buildReplyHandler;
private final AtomicInteger _currentLookups = new AtomicInteger();
private volatile boolean _isRunning;
private final Object _startupLock = new Object();
private ExplState _explState = ExplState.NONE;
private enum ExplState { NONE, IB, OB, BOTH }
/** TODO these may be too high, review and adjust */
private static final int MIN_QUEUE = 18;
@ -152,6 +156,30 @@ class BuildHandler implements Runnable {
ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildMessage.MESSAGE_TYPE, tbmhjb);
ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb);
}
/**
* Call the same time you start the threads
*
* @since 0.9.18
*/
void init() {
// fixup startup state if 0-hop exploratory is allowed in either direction
int ibl = _manager.getInboundSettings().getLength();
int ibv = _manager.getInboundSettings().getLengthVariance();
int obl = _manager.getOutboundSettings().getLength();
int obv = _manager.getOutboundSettings().getLengthVariance();
boolean ibz = ibl <= 0 || ibl + ibv <= 0;
boolean obz = obl <= 0 || obl + obv <= 0;
if (ibz && obz) {
_explState = ExplState.BOTH;
_context.router().setExplTunnelsReady();
} else if (ibz) {
_explState = ExplState.IB;
} else if (obz) {
_explState = ExplState.OB;
}
}
/**
* @since 0.9
@ -337,6 +365,38 @@ class BuildHandler implements Runnable {
// call buildComplete() after addTunnel() so we don't try another build.
_exec.buildComplete(cfg, cfg.getTunnelPool());
_exec.buildSuccessful(cfg);
if (cfg.getTunnelPool().getSettings().isExploratory()) {
// Notify router that exploratory tunnels are ready
boolean isIn = cfg.isInbound();
synchronized(_startupLock) {
switch (_explState) {
case NONE:
if (isIn)
_explState = ExplState.IB;
else
_explState = ExplState.OB;
break;
case IB:
if (!isIn) {
_explState = ExplState.BOTH;
_context.router().setExplTunnelsReady();
}
break;
case OB:
if (isIn) {
_explState = ExplState.BOTH;
_context.router().setExplTunnelsReady();
}
break;
case BOTH:
break;
}
}
}
ExpireJob expireJob = new ExpireJob(_context, cfg, cfg.getTunnelPool());
cfg.setExpireJob(expireJob);

View File

@ -138,6 +138,7 @@ abstract class BuildRequestor {
pairedTunnel = mgr.selectOutboundTunnel();
if (pairedTunnel != null &&
pairedTunnel.getLength() <= 1 &&
mgr.getOutboundSettings().getLength() > 0 &&
mgr.getOutboundSettings().getLength() + mgr.getOutboundSettings().getLengthVariance() > 0) {
// don't build using a zero-hop expl.,
// as it is both very bad for anonomyity,
@ -150,6 +151,7 @@ abstract class BuildRequestor {
pairedTunnel = mgr.selectInboundTunnel();
if (pairedTunnel != null &&
pairedTunnel.getLength() <= 1 &&
mgr.getInboundSettings().getLength() > 0 &&
mgr.getInboundSettings().getLength() + mgr.getInboundSettings().getLengthVariance() > 0) {
// ditto
pairedTunnel = null;

View File

@ -89,7 +89,7 @@ public class TunnelPool {
_lastRateUpdate = _started;
_lastLifetimeProcessed = 0;
_manager.getExecutor().repoll();
if (_settings.isInbound() && (_settings.getDestination() != null) ) {
if (_settings.isInbound() && !_settings.isExploratory()) {
// we just reconnected and didn't require any new tunnel builders.
// however, we /do/ want a leaseSet, so build one
LeaseSet ls = null;
@ -117,10 +117,8 @@ public class TunnelPool {
}
}
TunnelPoolManager getManager() { return _manager; }
void refreshSettings() {
if (_settings.getDestination() != null) {
if (!_settings.isExploratory()) {
return; // don't override client specified settings
} else {
if (_settings.isExploratory()) {
@ -160,7 +158,8 @@ public class TunnelPool {
TunnelInfo selectTunnel() { return selectTunnel(true); }
private TunnelInfo selectTunnel(boolean allowRecurseOnFail) {
boolean avoidZeroHop = ((getSettings().getLength() + getSettings().getLengthVariance()) > 0);
boolean avoidZeroHop = getSettings().getLength() > 0 &&
getSettings().getLength() + getSettings().getLengthVariance() > 0;
long period = curPeriod();
synchronized (_tunnels) {
@ -247,7 +246,8 @@ public class TunnelPool {
* @since 0.8.10
*/
TunnelInfo selectTunnel(Hash closestTo) {
boolean avoidZeroHop = ((getSettings().getLength() + getSettings().getLengthVariance()) > 0);
boolean avoidZeroHop = getSettings().getLength() > 0 &&
getSettings().getLength() + getSettings().getLengthVariance() > 0;
TunnelInfo rv = null;
synchronized (_tunnels) {
if (!_tunnels.isEmpty()) {
@ -419,8 +419,7 @@ public class TunnelPool {
public boolean isAlive() {
return _alive &&
(_settings.isExploratory() ||
(_settings.getDestination() != null &&
_context.clientManager().isLocal(_settings.getDestination())));
_context.clientManager().isLocal(_settings.getDestination()));
}
/** duplicate of getTunnelCount(), let's pick one */
@ -439,7 +438,7 @@ public class TunnelPool {
LeaseSet ls = null;
synchronized (_tunnels) {
_tunnels.add(info);
if (_settings.isInbound() && (_settings.getDestination() != null) )
if (_settings.isInbound() && !_settings.isExploratory())
ls = locked_buildNewLeaseSet();
}
@ -459,7 +458,7 @@ public class TunnelPool {
boolean removed = _tunnels.remove(info);
if (!removed)
return;
if (_settings.isInbound() && (_settings.getDestination() != null) )
if (_settings.isInbound() && !_settings.isExploratory())
ls = locked_buildNewLeaseSet();
remaining = _tunnels.size();
if (_lastSelected == info) {
@ -478,7 +477,7 @@ public class TunnelPool {
for (int i = 0; i < info.getLength(); i++)
_context.profileManager().tunnelLifetimePushed(info.getPeer(i), lifetime, lifetimeConfirmed);
if (_alive && _settings.isInbound() && (_settings.getDestination() != null) ) {
if (_alive && _settings.isInbound() && !_settings.isExploratory()) {
if (ls != null) {
_context.clientManager().requestLeaseSet(_settings.getDestination(), ls);
} else {
@ -528,7 +527,7 @@ public class TunnelPool {
boolean removed = _tunnels.remove(cfg);
if (!removed)
return;
if (_settings.isInbound() && (_settings.getDestination() != null) )
if (_settings.isInbound() && !_settings.isExploratory())
ls = locked_buildNewLeaseSet();
if (_lastSelected == cfg) {
_lastSelected = null;
@ -541,7 +540,7 @@ public class TunnelPool {
_lifetimeProcessed += cfg.getProcessedMessagesCount();
updateRate();
if (_settings.isInbound() && (_settings.getDestination() != null) ) {
if (_settings.isInbound() && !_settings.isExploratory()) {
if (ls != null) {
_context.clientManager().requestLeaseSet(_settings.getDestination(), ls);
}
@ -590,7 +589,7 @@ public class TunnelPool {
/** noop for outbound and exploratory */
void refreshLeaseSet() {
if (_settings.isInbound() && (_settings.getDestination() != null) ) {
if (_settings.isInbound() && !_settings.isExploratory()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug(toString() + ": refreshing leaseSet on tunnel expiration (but prior to grace timeout)");
LeaseSet ls = null;
@ -618,7 +617,7 @@ public class TunnelPool {
if (_settings.getAllowZeroHop()) {
if ( (_settings.getLength() + _settings.getLengthVariance() > 0) &&
(_settings.getDestination() != null) &&
(!_settings.isExploratory()) &&
(_context.profileOrganizer().countActivePeers() > 0) ) {
// if it is a client tunnel pool and our variance doesn't allow 0 hop, prefer failure to
// 0 hop operation (unless our router is offline)

View File

@ -344,9 +344,16 @@ public class TunnelPoolManager implements TunnelManagerFacade {
return pool.listTunnels().contains(tunnel);
}
/** exploratory */
public TunnelPoolSettings getInboundSettings() { return _inboundExploratory.getSettings(); }
/** exploratory */
public TunnelPoolSettings getOutboundSettings() { return _outboundExploratory.getSettings(); }
/** exploratory */
public void setInboundSettings(TunnelPoolSettings settings) { _inboundExploratory.setSettings(settings); }
/** exploratory */
public void setOutboundSettings(TunnelPoolSettings settings) { _outboundExploratory.setSettings(settings); }
public TunnelPoolSettings getInboundSettings(Hash client) {
@ -497,6 +504,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
if (!_executor.isRunning()) {
I2PThread t = new I2PThread(_executor, "BuildExecutor", true);
t.start();
_handler.init();
for (int i = 1; i <= _numHandlerThreads; i++) {
I2PThread hThread = new I2PThread(_handler, "BuildHandler " + i + '/' + _numHandlerThreads, true);
hThread.start();