forked from I2P_Developers/i2p.i2p
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:
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 = "";
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
Reference in New Issue
Block a user