forked from I2P_Developers/i2p.i2p
Compare commits
6 Commits
i2p.i2p.2.
...
rekeyOnIdl
Author | SHA1 | Date | |
---|---|---|---|
c19c7a5cee | |||
8729eab0a6 | |||
3356f75cea | |||
bb5dd0def9 | |||
1d44f604f8 | |||
84987486f1 |
@ -222,8 +222,8 @@ public class GeneralHelper {
|
||||
*/
|
||||
private static final String[] SHARED_OPTIONS = {
|
||||
// I2CP
|
||||
"i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.newDestOnResume",
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
|
||||
"i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.rekeyOnIdle", "i2cp.newDestOnResume",
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.rekeyIdleTime", "i2cp.closeIdleTime",
|
||||
// dest / LS
|
||||
I2PClient.PROP_SIGTYPE, "i2cp.leaseSetEncType", "i2cp.leaseSetType",
|
||||
"persistentClientKey",
|
||||
@ -885,9 +885,19 @@ public class GeneralHelper {
|
||||
return getProperty(tunnel, "i2cp.closeIdleTime", def*60*1000) / (60*1000);
|
||||
}
|
||||
|
||||
/** @since 0.9.47 */
|
||||
public boolean getRekeyOnIdle(int tunnel, boolean def) {
|
||||
return getBooleanProperty(tunnel, "i2cp.rekeyOnIdle", def);
|
||||
}
|
||||
|
||||
/** @since 0.9.47 */
|
||||
public int getRekeyTime(int tunnel, int def) {
|
||||
return getProperty(tunnel, "i2cp.rekeyIdleTime", def*60*1000) / (60*1000);
|
||||
}
|
||||
|
||||
public boolean getNewDest(int tunnel) {
|
||||
return getBooleanProperty(tunnel, "i2cp.newDestOnResume") &&
|
||||
getBooleanProperty(tunnel, "i2cp.closeOnIdle") &&
|
||||
(getBooleanProperty(tunnel, "i2cp.closeOnIdle") || getBooleanProperty(tunnel, "i2cp.restartOnIdle")) &&
|
||||
!getBooleanProperty(tunnel, "persistentClientKey");
|
||||
}
|
||||
|
||||
|
@ -264,6 +264,16 @@ public class TunnelConfig {
|
||||
else
|
||||
_booleanOptions.remove("i2cp.closeOnIdle");
|
||||
}
|
||||
/** @since 0.9.47 */
|
||||
public void setRekey(boolean val) {
|
||||
if (val){
|
||||
_booleanOptions.add("i2cp.rekeyOnIdle");
|
||||
setNewDest(1);
|
||||
setShared(false);
|
||||
}else{
|
||||
_booleanOptions.remove("i2cp.rekeyOnIdle");
|
||||
}
|
||||
}
|
||||
public void setEncrypt(boolean val) {
|
||||
if (val)
|
||||
_booleanOptions.add("i2cp.encryptLeaseSet");
|
||||
@ -478,6 +488,10 @@ public class TunnelConfig {
|
||||
public void setCloseTime(int val) {
|
||||
_otherOptions.put("i2cp.closeIdleTime", Integer.toString(val * 60*1000));
|
||||
}
|
||||
/** @since 0.9.47 */
|
||||
public void setRekeyTime(int val) {
|
||||
_otherOptions.put("i2cp.rekeyIdleTime", Integer.toString(val * 60*1000));
|
||||
}
|
||||
|
||||
public void setAllowUserAgent(boolean val) {
|
||||
if (val)
|
||||
@ -1091,7 +1105,7 @@ public class TunnelConfig {
|
||||
I2PTunnelIRCClient.PROP_DCC
|
||||
};
|
||||
private static final String _booleanClientOpts[] = {
|
||||
"i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.newDestOnResume", "persistentClientKey", "i2cp.delayOpen",
|
||||
"i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.rekeyOnIdle", "i2cp.newDestOnResume", "persistentClientKey", "i2cp.delayOpen",
|
||||
I2PTunnelClientBase.PROP_USE_SSL,
|
||||
};
|
||||
private static final String _booleanProxyOpts[] = {
|
||||
@ -1114,7 +1128,7 @@ public class TunnelConfig {
|
||||
TunnelController.PROP_LIMITS_SET
|
||||
};
|
||||
private static final String _otherClientOpts[] = {
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime", "i2cp.rekeyIdleTime",
|
||||
"outproxyUsername", "outproxyPassword",
|
||||
I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
|
||||
I2PTunnelHTTPClientBase.PROP_AUTH,
|
||||
|
@ -340,11 +340,21 @@ public class EditBean extends IndexBean {
|
||||
public boolean getClose(int tunnel) {
|
||||
return _helper.getCloseOnIdle(tunnel, false);
|
||||
}
|
||||
|
||||
|
||||
public int getCloseTime(int tunnel) {
|
||||
return _helper.getCloseTime(tunnel, 30);
|
||||
}
|
||||
|
||||
|
||||
/** @since 0.9.47 */
|
||||
public boolean getRekey(int tunnel) {
|
||||
return _helper.getRekeyOnIdle(tunnel, false);
|
||||
}
|
||||
|
||||
/** @since 0.9.47 */
|
||||
public int getRekeyTime(int tunnel) {
|
||||
return _helper.getRekeyTime(tunnel, 10);
|
||||
}
|
||||
|
||||
public boolean getNewDest(int tunnel) {
|
||||
return _helper.getNewDest(tunnel);
|
||||
}
|
||||
|
@ -485,11 +485,11 @@ public class IndexBean {
|
||||
}
|
||||
|
||||
public String getSharedClient(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getSharedClient();
|
||||
else
|
||||
return "";
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getSharedClient();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getClientDestination(int tunnel) {
|
||||
@ -847,10 +847,10 @@ public class IndexBean {
|
||||
_config.setStartOnLoad(true);
|
||||
}
|
||||
public void setShared(String moo) {
|
||||
_config.setShared(true);
|
||||
_config.setShared(true);
|
||||
}
|
||||
public void setShared(boolean val) {
|
||||
_config.setShared(val);
|
||||
_config.setShared(val);
|
||||
}
|
||||
public void setConnectDelay(String moo) {
|
||||
_config.setConnectDelay(true);
|
||||
@ -865,6 +865,10 @@ public class IndexBean {
|
||||
public void setClose(String moo) {
|
||||
_config.setClose(true);
|
||||
}
|
||||
/** @since 0.9.47 */
|
||||
public void setRekey(String moo) {
|
||||
_config.setRekey(true);
|
||||
}
|
||||
public void setEncrypt(String moo) {
|
||||
_config.setEncrypt(true);
|
||||
}
|
||||
@ -1056,6 +1060,15 @@ public class IndexBean {
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 0.9.47 */
|
||||
public void setRekeyTime(String val) {
|
||||
if (val != null) {
|
||||
try {
|
||||
_config.setRekeyTime(Integer.parseInt(val.trim()));
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 0.9.14 */
|
||||
public void setAllowUserAgent(String moo) {
|
||||
_config.setAllowUserAgent(true);
|
||||
|
@ -409,6 +409,21 @@
|
||||
<%
|
||||
} // !streamrclient
|
||||
%>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
<%=intl._t("Rekey tunnel to change destination when idle")%>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label title="<%=intl._t("To force rotation of tunnel identity, re-key tunnels after an idle period")%>"><input value="1" type="checkbox" name="rekey"<%=(editBean.getRekey(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
<%=intl._t("Change keys of client tunnels after specified idle period(incompatible with \"Shared Tunnels\")")%></label>
|
||||
</td><td>
|
||||
<b><%=intl._t("Idle period")%>:</b>
|
||||
<input type="text" name="rekeyTime" size="4" maxlength="4" title="<%=intl._t("Rekey Tunnel Idle Time")%>" value="<%=editBean.getRekeyTime(curTunnel)%>" class="freetext period" />
|
||||
minutes
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
<%=intl._t("Reduce tunnel quantity when idle")%>
|
||||
|
@ -10,6 +10,8 @@ package net.i2p.client.impl;
|
||||
*/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -34,7 +36,9 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PSessionListener;
|
||||
@ -90,7 +94,7 @@ import net.i2p.util.VersionComparator;
|
||||
public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessageEventListener {
|
||||
protected final Log _log;
|
||||
/** who we are */
|
||||
private final Destination _myDestination;
|
||||
private Destination _myDestination;
|
||||
/** private key for decryption */
|
||||
private PrivateKey _privateKey;
|
||||
/** private key for signing */
|
||||
@ -584,11 +588,11 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
// we don't support EncTypes in Destinations,
|
||||
// but i2pd does, and also, this code is used from PrivateKeyFile to
|
||||
// read in router.keys.dat files and we will support EncTypes for RouterIdentities
|
||||
EncType etype = _myDestination.getPublicKey().getType();
|
||||
EncType etype = getMyDestination().getPublicKey().getType();
|
||||
if (etype != EncType.ELGAMAL_2048)
|
||||
_privateKey = new PrivateKey(etype);
|
||||
_privateKey.readBytes(destKeyStream);
|
||||
SigType dtype = _myDestination.getSigningPublicKey().getType();
|
||||
SigType dtype = getMyDestination().getSigningPublicKey().getType();
|
||||
_signingPrivateKey = new SigningPrivateKey(dtype);
|
||||
_signingPrivateKey.readBytes(destKeyStream);
|
||||
if (_signingPrivateKey.isOffline()) {
|
||||
@ -607,6 +611,43 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the keys used for the current session in order to force a change of destination.
|
||||
* It is incompatible with persistent client keys, and will cause persistent client keys to
|
||||
* change if used with them.
|
||||
*
|
||||
* It will re-use the settings it finds from the previous session. Before using it, close the
|
||||
* tunnel(usually with destroySession) and re-connect it afterward.
|
||||
*
|
||||
* @since 0.9.47
|
||||
*/
|
||||
public void rekeySession() throws I2PException, DataFormatException, IOException {
|
||||
verifyClosed();
|
||||
|
||||
ByteArrayOutputStream destOutputStream = new ByteArrayOutputStream();
|
||||
Properties props = getOptions();
|
||||
SigType sigType = getMyDestination().getSigType();
|
||||
try {
|
||||
I2PClientFactory.createClient().createDestination(destOutputStream, sigType);
|
||||
ByteArrayInputStream destKeyStream = new ByteArrayInputStream(destOutputStream.toByteArray());
|
||||
_myDestination = new Destination();
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Starting a re-key");
|
||||
_myDestination.readBytes(destKeyStream);
|
||||
|
||||
EncType etype = getMyDestination().getPublicKey().getType();
|
||||
_privateKey = new PrivateKey(etype);
|
||||
_privateKey.readBytes(destKeyStream);
|
||||
|
||||
SigType dtype = getMyDestination().getSigningPublicKey().getType();
|
||||
_signingPrivateKey = new SigningPrivateKey(dtype);
|
||||
_signingPrivateKey.readBytes(destKeyStream);
|
||||
|
||||
}catch(I2PException e){
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this session have offline and transient keys?
|
||||
* @since 0.9.38
|
||||
@ -763,7 +804,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Before getDate");
|
||||
Properties auth = null;
|
||||
if ((!_context.isRouterContext()) && _options.containsKey(I2PClient.PROP_USER) && _options.containsKey(I2PClient.PROP_PW)) {
|
||||
// Only supported by routers 0.9.11 or higher, but we don't know the version yet.
|
||||
// Only supported by routers 0.9.11 or higher, but we don't know the version yet.
|
||||
// Auth will also be sent in the SessionConfig.
|
||||
auth = new OrderedProperties();
|
||||
auth.setProperty(I2PClient.PROP_USER, _options.getProperty(I2PClient.PROP_USER));
|
||||
@ -1127,8 +1168,33 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
|
||||
/**
|
||||
* Retrieve the destination of the session
|
||||
*
|
||||
* @since 0.9.47(8?) _myDestination is no longer final, but must
|
||||
* be re-instantiated in order to change it's value, or it will
|
||||
* throw an IllegalStateException
|
||||
*/
|
||||
public Destination getMyDestination() { return _myDestination; }
|
||||
public Destination getMyDestination() {
|
||||
try {
|
||||
return getMyDestination(false);
|
||||
}catch(I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("I2PSessionException retrieving I2P destination");
|
||||
}
|
||||
return _myDestination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the destination of the session
|
||||
*/
|
||||
public Destination getMyDestination(boolean change) throws I2PSessionException {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "getting tunnel destination with change: " + change);
|
||||
while (change) {
|
||||
verifyClosed();
|
||||
change = false;
|
||||
break;
|
||||
}
|
||||
return _myDestination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the decryption PrivateKey
|
||||
@ -1217,6 +1283,53 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void verifyClosed() throws I2PSessionException {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "Verifying tunnel state is closed, current state is:" + _state);
|
||||
synchronized(_stateLock) {
|
||||
boolean loop = true;
|
||||
boolean wasOpening = false;
|
||||
while (loop) {
|
||||
if (_myDestination.equals(new Destination())){
|
||||
loop = false;
|
||||
break;
|
||||
}
|
||||
switch (_state) {
|
||||
case INIT:
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "Tunnel is initializing, safe to rekey" + _state);
|
||||
loop = false;
|
||||
break;
|
||||
case CLOSED:
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "Tunnel is closed, safe to rekey" + _state);
|
||||
loop = false;
|
||||
break;
|
||||
case OPENING:
|
||||
if (_log.shouldLog(Log.WARN)) _log.warn(getPrefix() + "Tunnel is in an opening state, unsafe to rekey" + _state);
|
||||
wasOpening = true;
|
||||
try {
|
||||
_stateLock.wait(10*1000);
|
||||
} catch (InterruptedException ie) {
|
||||
throw new I2PSessionException("Interrupted", ie);
|
||||
}
|
||||
break;
|
||||
case GOTDATE:
|
||||
if (_log.shouldLog(Log.WARN)) _log.warn(getPrefix() + "Tunnel is getting date, unsafe to rekey" + _state);
|
||||
wasOpening = true;
|
||||
try {
|
||||
_stateLock.wait(10*1000);
|
||||
} catch (InterruptedException ie) {
|
||||
throw new I2PSessionException("Interrupted", ie);
|
||||
}
|
||||
break;
|
||||
case CLOSING: // fall through and loop over again
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "Tunnel is closing, loop over" + _state);
|
||||
case OPEN:
|
||||
if (_log.shouldLog(Log.WARN)) _log.warn(getPrefix() + "Tunnel is open and unavailable for rekey" + _state);
|
||||
throw new I2PSessionException("Tunnel is open and unavailable for rekey");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deliver an I2CP message to the router
|
||||
@ -1330,7 +1443,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getPrefix() + "Closing the socket", new Exception("closeSocket"));
|
||||
// maybe not the right place for this, but let's be sure
|
||||
Destination d = _myDestination;
|
||||
Destination d = getMyDestination();
|
||||
if (d != null)
|
||||
_context.keyRing().remove(d.calculateHash());
|
||||
synchronized(_stateLock) {
|
||||
@ -1902,6 +2015,14 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
return _lastActivity;
|
||||
}
|
||||
|
||||
private long updateLastActivity() {
|
||||
if (_lastActivity == 0)
|
||||
updateActivity();
|
||||
long la = _lastActivity;
|
||||
updateActivity();
|
||||
return la;
|
||||
}
|
||||
|
||||
public void setReduced() {
|
||||
_isReduced = true;
|
||||
}
|
||||
@ -1910,9 +2031,10 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
_isReduced = false;
|
||||
boolean reduce = Boolean.parseBoolean(_options.getProperty("i2cp.reduceOnIdle"));
|
||||
boolean close = Boolean.parseBoolean(_options.getProperty("i2cp.closeOnIdle"));
|
||||
if (reduce || close) {
|
||||
updateActivity();
|
||||
_context.simpleTimer2().addEvent(new SessionIdleTimer(_context, this, reduce, close), SessionIdleTimer.MINIMUM_TIME);
|
||||
boolean restart = Boolean.parseBoolean(_options.getProperty("i2cp.rekeyOnIdle"));
|
||||
if (reduce || close || restart ) {
|
||||
// updateActivity();
|
||||
_context.simpleTimer2().addEvent(new SessionIdleTimer(_context, this, reduce, close, restart, updateLastActivity()), SessionIdleTimer.MINIMUM_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1920,8 +2042,8 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(32);
|
||||
buf.append("Session: ");
|
||||
if (_myDestination != null)
|
||||
buf.append(_myDestination.calculateHash().toBase64().substring(0, 4));
|
||||
if (getMyDestination() != null)
|
||||
buf.append(getMyDestination().calculateHash().toBase64().substring(0, 4));
|
||||
else
|
||||
buf.append("[null dest]");
|
||||
buf.append(getPrefix());
|
||||
|
@ -6,8 +6,10 @@ package net.i2p.client.impl;
|
||||
*/
|
||||
|
||||
import java.util.Properties;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
@ -20,6 +22,7 @@ import net.i2p.util.SimpleTimer;
|
||||
*/
|
||||
class SessionIdleTimer implements SimpleTimer.TimedEvent {
|
||||
public static final long MINIMUM_TIME = 5*60*1000;
|
||||
private static final long DEFAULT_CYCLE_TIME = 180*60*1000;
|
||||
private static final long DEFAULT_REDUCE_TIME = 20*60*1000;
|
||||
private static final long DEFAULT_CLOSE_TIME = 30*60*1000;
|
||||
private final Log _log;
|
||||
@ -30,14 +33,16 @@ class SessionIdleTimer implements SimpleTimer.TimedEvent {
|
||||
private final long _reduceTime;
|
||||
private final boolean _shutdownEnabled;
|
||||
private final long _shutdownTime;
|
||||
private final boolean _restartEnabled;
|
||||
private final long _restartTime;
|
||||
private final long _minimumTime;
|
||||
private long _lastActive;
|
||||
|
||||
/**
|
||||
* reduce, shutdown, or both must be true
|
||||
* reduce, shutdown, restart or some combination must be true
|
||||
*/
|
||||
public SessionIdleTimer(I2PAppContext context, I2PSessionImpl session, boolean reduce, boolean shutdown) {
|
||||
if (! (reduce || shutdown))
|
||||
public SessionIdleTimer(I2PAppContext context, I2PSessionImpl session, boolean reduce, boolean shutdown, boolean restart, long starttime) {
|
||||
if (! (reduce || shutdown || restart))
|
||||
throw new IllegalArgumentException("At least one must be enabled");
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(SessionIdleTimer.class);
|
||||
@ -46,6 +51,7 @@ class SessionIdleTimer implements SimpleTimer.TimedEvent {
|
||||
long minimumTime = Long.MAX_VALUE;
|
||||
long reduceTime = 0;
|
||||
long shutdownTime = 0;
|
||||
long restartTime = 0;
|
||||
int reduceQuantity = 0;
|
||||
if (reduce) {
|
||||
reduceQuantity = 1;
|
||||
@ -77,41 +83,104 @@ class SessionIdleTimer implements SimpleTimer.TimedEvent {
|
||||
if (reduce && shutdownTime <= reduceTime)
|
||||
reduce = false;
|
||||
}
|
||||
if (restart) {
|
||||
restartTime = DEFAULT_CYCLE_TIME;
|
||||
String p = props.getProperty("i2cp.rekeyIdleTime");
|
||||
if (p != null) {
|
||||
try {
|
||||
restartTime = Math.max(Long.parseLong(p), MINIMUM_TIME);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
if (shutdown && restartTime <= shutdownTime)
|
||||
shutdown = false;
|
||||
minimumTime = Math.min(minimumTime, restartTime);
|
||||
if (reduce && restartTime <= reduceTime)
|
||||
reduce = false;
|
||||
}
|
||||
_reduceEnabled = reduce;
|
||||
_reduceQuantity = reduceQuantity;
|
||||
_reduceTime = reduceTime;
|
||||
_shutdownEnabled = shutdown;
|
||||
_shutdownTime = shutdownTime;
|
||||
_restartEnabled = restart;
|
||||
_restartTime = restartTime;
|
||||
_minimumTime = minimumTime;
|
||||
_lastActive = starttime;
|
||||
}
|
||||
|
||||
public void timeReached() {
|
||||
if (_session.isClosed())
|
||||
return;
|
||||
long nextDelay = 0;
|
||||
long now = _context.clock().now();
|
||||
long lastActivity = _session.lastActivity();
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Fire idle timer, last activity: " + DataHelper.formatDuration(now - lastActivity) + " ago ");
|
||||
long nextDelay = 0;
|
||||
if (_shutdownEnabled && now - lastActivity >= _shutdownTime) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Closing on idle " + _session);
|
||||
_session.destroySession();
|
||||
if (_session.isClosed() && !_restartEnabled)
|
||||
return;
|
||||
} else if (lastActivity <= _lastActive && !_shutdownEnabled) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Fire idle timer, last activity: " + DataHelper.formatDuration(now - lastActivity) + " ago " + _session);
|
||||
|
||||
// Since re-keys happen all-at-once, it should be safe to do them before we do the
|
||||
// tunnel count/close adjustments. Also, since there's no good reason to re-key an inactive tunnel
|
||||
// only do it once per extended period of idle time.
|
||||
if (_restartEnabled && now - lastActivity >= _restartTime && now - _lastActive < (2*_restartTime)) {
|
||||
try {
|
||||
// don't do a rekey if the tunnel was closed to begin with
|
||||
if (!_session.isClosed()) {
|
||||
_session.destroySession();
|
||||
_session.rekeySession();
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Closing on idle for quick rekey" + _session);
|
||||
}
|
||||
} catch (I2PException ie) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Failed recreating the session" + _session, ie);
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Failed recreating the session" + _session, ioe);
|
||||
} finally {
|
||||
nextDelay = _restartTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Top priority is close-on-idle to conserve resources. If the close-on-idle event has occurred or the time
|
||||
// since the last activity has been greater than the minimum shutown time, then destroySession if it's not
|
||||
// already closed.
|
||||
if (_shutdownEnabled && now - lastActivity >= _shutdownTime) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Closing on idle " + _session);
|
||||
if (!_session.isClosed())
|
||||
_session.destroySession();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've made it here, then close-on-idle isn't in effect so it's OK to reconnect the tunnel with the new
|
||||
// destination keys. This preserves the functionality of close-on-idle in the presence of the rekeying function.
|
||||
if (_restartEnabled) {
|
||||
if (_session.isClosed()){
|
||||
_session.reconnect();
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Key cycle complete, next re-key in " + _restartTime + " ms, session" + _session);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the next delay for sleeping tunnels
|
||||
if (lastActivity <= _lastActive && !_shutdownEnabled) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Still idle, sleeping again " + _session);
|
||||
nextDelay = _reduceTime;
|
||||
} else if (_reduceEnabled && now - lastActivity >= _reduceTime) {
|
||||
|
||||
// Make sure that the tunnel count is correct for the idle duration, adjust down if we've passed the
|
||||
// reduce-idle-time threshold.
|
||||
} //else
|
||||
if (_reduceEnabled && now - lastActivity >= _reduceTime) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Reducing quantity on idle " + _session);
|
||||
try {
|
||||
_session.getProducer().updateTunnels(_session, _reduceQuantity);
|
||||
} catch (I2PSessionException ise) {
|
||||
_log.error("bork idle reduction " + ise);
|
||||
_log.error("bork idle reduction ", ise);
|
||||
}
|
||||
_session.setReduced();
|
||||
_lastActive = lastActivity;
|
||||
if (!_restartEnabled)
|
||||
_lastActive = lastActivity;
|
||||
if (_shutdownEnabled)
|
||||
nextDelay = _shutdownTime - (now - lastActivity);
|
||||
else
|
||||
@ -119,6 +188,7 @@ class SessionIdleTimer implements SimpleTimer.TimedEvent {
|
||||
} else {
|
||||
nextDelay = _minimumTime - (now - lastActivity);
|
||||
}
|
||||
|
||||
_context.simpleTimer2().addEvent(this, nextDelay);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user