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