forked from I2P_Developers/i2p.i2p
States for TunnelController (#815)
This commit is contained in:
@@ -42,8 +42,17 @@ public class TunnelController implements Logging {
|
||||
private final I2PTunnel _tunnel;
|
||||
private final List<String> _messages;
|
||||
private List<I2PSession> _sessions;
|
||||
private boolean _running;
|
||||
private boolean _starting;
|
||||
private volatile TunnelState _state;
|
||||
|
||||
private enum TunnelState {
|
||||
START_ON_LOAD,
|
||||
STARTING,
|
||||
RUNNING,
|
||||
STOPPING,
|
||||
STOPPED,
|
||||
DESTROYING,
|
||||
DESTROYED,
|
||||
}
|
||||
|
||||
public static final String KEY_BACKUP_DIR = "i2ptunnel-keyBackup";
|
||||
|
||||
@@ -124,11 +133,10 @@ public class TunnelController implements Logging {
|
||||
_log = I2PAppContext.getGlobalContext().logManager().getLog(TunnelController.class);
|
||||
setConfig(config, prefix);
|
||||
_messages = new ArrayList<String>(4);
|
||||
_running = false;
|
||||
boolean keyOK = true;
|
||||
if (createKey && (getType().endsWith("server") || getPersistentClientKey()))
|
||||
keyOK = createPrivateKey();
|
||||
_starting = keyOK && getStartOnLoad();
|
||||
_state = keyOK && getStartOnLoad() ? TunnelState.START_ON_LOAD : TunnelState.STOPPED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,8 +201,10 @@ public class TunnelController implements Logging {
|
||||
}
|
||||
|
||||
public void startTunnelBackground() {
|
||||
if (_running) return;
|
||||
_starting = true;
|
||||
synchronized (this) {
|
||||
if (_state != TunnelState.STOPPED && _state != TunnelState.START_ON_LOAD)
|
||||
return;
|
||||
}
|
||||
new I2PAppThread(new Runnable() { public void run() { startTunnel(); } }).start();
|
||||
}
|
||||
|
||||
@@ -203,7 +213,17 @@ public class TunnelController implements Logging {
|
||||
*
|
||||
*/
|
||||
public void startTunnel() {
|
||||
_starting = true;
|
||||
synchronized (this) {
|
||||
if (_state != TunnelState.STOPPED && _state != TunnelState.START_ON_LOAD) {
|
||||
if (_state == TunnelState.RUNNING) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Already running");
|
||||
log("Tunnel " + getName() + " is already running");
|
||||
}
|
||||
return;
|
||||
}
|
||||
changeState(TunnelState.STARTING);
|
||||
}
|
||||
try {
|
||||
doStartTunnel();
|
||||
} catch (Exception e) {
|
||||
@@ -213,21 +233,20 @@ public class TunnelController implements Logging {
|
||||
acquire();
|
||||
stopTunnel();
|
||||
}
|
||||
_starting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException via methods in I2PTunnel
|
||||
*/
|
||||
private void doStartTunnel() {
|
||||
if (_running) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Already running");
|
||||
log("Tunnel " + getName() + " is already running");
|
||||
return;
|
||||
synchronized (this) {
|
||||
if (_state != TunnelState.STARTING)
|
||||
return;
|
||||
}
|
||||
|
||||
String type = getType();
|
||||
if ( (type == null) || (type.length() <= 0) ) {
|
||||
changeState(TunnelState.STOPPED);
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Cannot start the tunnel - no type specified");
|
||||
return;
|
||||
@@ -237,6 +256,7 @@ public class TunnelController implements Logging {
|
||||
if (type.endsWith("server") || getPersistentClientKey()) {
|
||||
boolean ok = createPrivateKey();
|
||||
if (!ok) {
|
||||
changeState(TunnelState.STOPPED);
|
||||
log("Failed to start tunnel " + getName() + " as the private key file could not be created");
|
||||
return;
|
||||
}
|
||||
@@ -268,12 +288,13 @@ public class TunnelController implements Logging {
|
||||
} else if (TYPE_STREAMR_SERVER.equals(type)) {
|
||||
startStreamrServer();
|
||||
} else {
|
||||
changeState(TunnelState.STOPPED);
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Cannot start tunnel - unknown type [" + type + "]");
|
||||
return;
|
||||
}
|
||||
acquire();
|
||||
_running = true;
|
||||
changeState(TunnelState.RUNNING);
|
||||
}
|
||||
|
||||
private void startHttpClient() {
|
||||
@@ -554,12 +575,17 @@ public class TunnelController implements Logging {
|
||||
* and it may have timer threads that continue running.
|
||||
*/
|
||||
public void stopTunnel() {
|
||||
synchronized (this) {
|
||||
if (_state != TunnelState.RUNNING)
|
||||
return;
|
||||
changeState(TunnelState.STOPPING);
|
||||
}
|
||||
// I2PTunnel removes the session in close(),
|
||||
// so save the sessions to pass to release() and TCG
|
||||
Collection<I2PSession> sessions = getAllSessions();
|
||||
_tunnel.runClose(new String[] { "forced", "all" }, this);
|
||||
release(sessions);
|
||||
_running = false;
|
||||
changeState(TunnelState.STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -569,12 +595,17 @@ public class TunnelController implements Logging {
|
||||
* @since 0.9.17
|
||||
*/
|
||||
public void destroyTunnel() {
|
||||
synchronized (this) {
|
||||
if (_state != TunnelState.RUNNING)
|
||||
return;
|
||||
changeState(TunnelState.DESTROYING);
|
||||
}
|
||||
// I2PTunnel removes the session in close(),
|
||||
// so save the sessions to pass to release() and TCG
|
||||
Collection<I2PSession> sessions = getAllSessions();
|
||||
_tunnel.runClose(new String[] { "destroy", "all" }, this);
|
||||
release(sessions);
|
||||
_running = false;
|
||||
changeState(TunnelState.DESTROYED);
|
||||
}
|
||||
|
||||
public void restartTunnel() {
|
||||
@@ -626,26 +657,29 @@ public class TunnelController implements Logging {
|
||||
// tell i2ptunnel, who will tell the TunnelTask, who will tell the SocketManager
|
||||
setSessionOptions();
|
||||
|
||||
if (_running) {
|
||||
Collection<I2PSession> sessions = getAllSessions();
|
||||
if (sessions.isEmpty()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Running but no sessions to update");
|
||||
}
|
||||
for (I2PSession s : sessions) {
|
||||
// tell the router via the session
|
||||
if (!s.isClosed()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Session is open, updating: " + s);
|
||||
s.updateOptions(_tunnel.getClientOptions());
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Session is closed, not updating: " + s);
|
||||
synchronized (this) {
|
||||
if (_state != TunnelState.RUNNING) {
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Not running, not updating sessions");
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Not running, not updating sessions");
|
||||
}
|
||||
// Running, so check sessions
|
||||
Collection<I2PSession> sessions = getAllSessions();
|
||||
if (sessions.isEmpty()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Running but no sessions to update");
|
||||
}
|
||||
for (I2PSession s : sessions) {
|
||||
// tell the router via the session
|
||||
if (!s.isClosed()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Session is open, updating: " + s);
|
||||
s.updateOptions(_tunnel.getClientOptions());
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Session is closed, not updating: " + s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -794,13 +828,16 @@ public class TunnelController implements Logging {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean getIsRunning() { return _running; }
|
||||
public boolean getIsStarting() { return _starting; }
|
||||
public boolean getIsRunning() { return _state == TunnelState.RUNNING; }
|
||||
public boolean getIsStarting() { return _state == TunnelState.START_ON_LOAD || _state == TunnelState.STARTING; }
|
||||
|
||||
/** if running but no open sessions, we are in standby */
|
||||
public boolean getIsStandby() {
|
||||
if (!_running)
|
||||
return false;
|
||||
synchronized (this) {
|
||||
if (_state != TunnelState.RUNNING)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (I2PSession sess : _tunnel.getSessions()) {
|
||||
if (!sess.isClosed())
|
||||
return false;
|
||||
@@ -808,6 +845,10 @@ public class TunnelController implements Logging {
|
||||
return true;
|
||||
}
|
||||
|
||||
private synchronized void changeState(TunnelState state) {
|
||||
_state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* A text description of the tunnel.
|
||||
* @deprecated unused
|
||||
@@ -927,7 +968,7 @@ public class TunnelController implements Logging {
|
||||
*
|
||||
*/
|
||||
public void log(String s) {
|
||||
synchronized (this) {
|
||||
synchronized (_messages) {
|
||||
_messages.add(s);
|
||||
while (_messages.size() > 10)
|
||||
_messages.remove(0);
|
||||
@@ -943,7 +984,7 @@ public class TunnelController implements Logging {
|
||||
*/
|
||||
public List<String> clearMessages() {
|
||||
List<String> rv = null;
|
||||
synchronized (this) {
|
||||
synchronized (_messages) {
|
||||
rv = new ArrayList<String>(_messages);
|
||||
_messages.clear();
|
||||
}
|
||||
@@ -955,6 +996,6 @@ public class TunnelController implements Logging {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TC " + getType() + ' ' + getName() + " for " + _tunnel;
|
||||
return "TC " + getType() + ' ' + getName() + " for " + _tunnel + ' ' + _state;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user