I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 46fe4298 authored by str4d's avatar str4d
Browse files

States for TunnelController (#815)

parent 9790d3ba
No related branches found
No related tags found
No related merge requests found
......@@ -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,19 +828,26 @@ 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;
}
return true;
}
private synchronized void changeState(TunnelState state) {
_state = state;
}
/**
* A text description of the tunnel.
......@@ -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;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment