forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p' (head 04337e47a38298a4035f48b830f6a2532767bd50)
to branch 'i2p.i2p.zzz.test2' (head 052c3194bd75846075a6b64a1f96cdca6eae33b4)
This commit is contained in:
@ -70,7 +70,6 @@ public class ConsoleUpdateManager implements UpdateManager {
|
|||||||
/** downloaded AND installed */
|
/** downloaded AND installed */
|
||||||
private final Map<UpdateItem, Version> _installed;
|
private final Map<UpdateItem, Version> _installed;
|
||||||
private static final DecimalFormat _pct = new DecimalFormat("0.0%");
|
private static final DecimalFormat _pct = new DecimalFormat("0.0%");
|
||||||
private static final VersionComparator _versionComparator = new VersionComparator();
|
|
||||||
|
|
||||||
private volatile String _status;
|
private volatile String _status;
|
||||||
|
|
||||||
@ -1289,7 +1288,7 @@ public class ConsoleUpdateManager implements UpdateManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(Version r) {
|
public int compareTo(Version r) {
|
||||||
return _versionComparator.compare(version, r.version);
|
return VersionComparator.comp(version, r.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -252,7 +252,7 @@ class PluginUpdateRunner extends UpdateRunner {
|
|||||||
|
|
||||||
String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version");
|
String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version");
|
||||||
if (minVersion != null &&
|
if (minVersion != null &&
|
||||||
(new VersionComparator()).compare(CoreVersion.VERSION, minVersion) < 0) {
|
VersionComparator.comp(CoreVersion.VERSION, minVersion) < 0) {
|
||||||
to.delete();
|
to.delete();
|
||||||
statusDone("<b>" + _("This plugin requires I2P version {0} or higher", minVersion) + "</b>");
|
statusDone("<b>" + _("This plugin requires I2P version {0} or higher", minVersion) + "</b>");
|
||||||
return;
|
return;
|
||||||
@ -260,7 +260,7 @@ class PluginUpdateRunner extends UpdateRunner {
|
|||||||
|
|
||||||
minVersion = ConfigClientsHelper.stripHTML(props, "min-java-version");
|
minVersion = ConfigClientsHelper.stripHTML(props, "min-java-version");
|
||||||
if (minVersion != null &&
|
if (minVersion != null &&
|
||||||
(new VersionComparator()).compare(System.getProperty("java.version"), minVersion) < 0) {
|
VersionComparator.comp(System.getProperty("java.version"), minVersion) < 0) {
|
||||||
to.delete();
|
to.delete();
|
||||||
statusDone("<b>" + _("This plugin requires Java version {0} or higher", minVersion) + "</b>");
|
statusDone("<b>" + _("This plugin requires Java version {0} or higher", minVersion) + "</b>");
|
||||||
return;
|
return;
|
||||||
@ -295,21 +295,21 @@ class PluginUpdateRunner extends UpdateRunner {
|
|||||||
}
|
}
|
||||||
String oldVersion = oldProps.getProperty("version");
|
String oldVersion = oldProps.getProperty("version");
|
||||||
if (oldVersion == null ||
|
if (oldVersion == null ||
|
||||||
(new VersionComparator()).compare(oldVersion, version) >= 0) {
|
VersionComparator.comp(oldVersion, version) >= 0) {
|
||||||
to.delete();
|
to.delete();
|
||||||
statusDone("<b>" + _("Downloaded plugin version {0} is not newer than installed plugin", version) + "</b>");
|
statusDone("<b>" + _("Downloaded plugin version {0} is not newer than installed plugin", version) + "</b>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
minVersion = ConfigClientsHelper.stripHTML(props, "min-installed-version");
|
minVersion = ConfigClientsHelper.stripHTML(props, "min-installed-version");
|
||||||
if (minVersion != null &&
|
if (minVersion != null &&
|
||||||
(new VersionComparator()).compare(minVersion, oldVersion) > 0) {
|
VersionComparator.comp(minVersion, oldVersion) > 0) {
|
||||||
to.delete();
|
to.delete();
|
||||||
statusDone("<b>" + _("Plugin update requires installed plugin version {0} or higher", minVersion) + "</b>");
|
statusDone("<b>" + _("Plugin update requires installed plugin version {0} or higher", minVersion) + "</b>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String maxVersion = ConfigClientsHelper.stripHTML(props, "max-installed-version");
|
String maxVersion = ConfigClientsHelper.stripHTML(props, "max-installed-version");
|
||||||
if (maxVersion != null &&
|
if (maxVersion != null &&
|
||||||
(new VersionComparator()).compare(maxVersion, oldVersion) < 0) {
|
VersionComparator.comp(maxVersion, oldVersion) < 0) {
|
||||||
to.delete();
|
to.delete();
|
||||||
statusDone("<b>" + _("Plugin update requires installed plugin version {0} or lower", maxVersion) + "</b>");
|
statusDone("<b>" + _("Plugin update requires installed plugin version {0} or lower", maxVersion) + "</b>");
|
||||||
return;
|
return;
|
||||||
@ -317,14 +317,14 @@ class PluginUpdateRunner extends UpdateRunner {
|
|||||||
oldVersion = LogsHelper.jettyVersion();
|
oldVersion = LogsHelper.jettyVersion();
|
||||||
minVersion = ConfigClientsHelper.stripHTML(props, "min-jetty-version");
|
minVersion = ConfigClientsHelper.stripHTML(props, "min-jetty-version");
|
||||||
if (minVersion != null &&
|
if (minVersion != null &&
|
||||||
(new VersionComparator()).compare(minVersion, oldVersion) > 0) {
|
VersionComparator.comp(minVersion, oldVersion) > 0) {
|
||||||
to.delete();
|
to.delete();
|
||||||
statusDone("<b>" + _("Plugin requires Jetty version {0} or higher", minVersion) + "</b>");
|
statusDone("<b>" + _("Plugin requires Jetty version {0} or higher", minVersion) + "</b>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
|
maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
|
||||||
if (maxVersion != null &&
|
if (maxVersion != null &&
|
||||||
(new VersionComparator()).compare(maxVersion, oldVersion) < 0) {
|
VersionComparator.comp(maxVersion, oldVersion) < 0) {
|
||||||
to.delete();
|
to.delete();
|
||||||
statusDone("<b>" + _("Plugin requires Jetty version {0} or lower", maxVersion) + "</b>");
|
statusDone("<b>" + _("Plugin requires Jetty version {0} or lower", maxVersion) + "</b>");
|
||||||
return;
|
return;
|
||||||
|
@ -184,7 +184,7 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
|
|||||||
if (_isPartial) {
|
if (_isPartial) {
|
||||||
// Compare version with what we have now
|
// Compare version with what we have now
|
||||||
String newVersion = TrustedUpdate.getVersionString(new ByteArrayInputStream(_baos.toByteArray()));
|
String newVersion = TrustedUpdate.getVersionString(new ByteArrayInputStream(_baos.toByteArray()));
|
||||||
boolean newer = (new VersionComparator()).compare(newVersion, RouterVersion.VERSION) > 0;
|
boolean newer = VersionComparator.comp(newVersion, RouterVersion.VERSION) > 0;
|
||||||
if (newer) {
|
if (newer) {
|
||||||
_newVersion = newVersion;
|
_newVersion = newVersion;
|
||||||
} else {
|
} else {
|
||||||
|
@ -144,7 +144,7 @@ public class ConfigServiceHandler extends FormHandler {
|
|||||||
if (ctx.hasWrapper() && _wrapperListener == null &&
|
if (ctx.hasWrapper() && _wrapperListener == null &&
|
||||||
!SystemVersion.isWindows()) {
|
!SystemVersion.isWindows()) {
|
||||||
String wv = System.getProperty("wrapper.version");
|
String wv = System.getProperty("wrapper.version");
|
||||||
if (wv != null && (new VersionComparator()).compare(wv, LISTENER_AVAILABLE) >= 0) {
|
if (wv != null && VersionComparator.comp(wv, LISTENER_AVAILABLE) >= 0) {
|
||||||
try {
|
try {
|
||||||
_wrapperListener = new WrapperListener(ctx);
|
_wrapperListener = new WrapperListener(ctx);
|
||||||
} catch (Throwable t) {}
|
} catch (Throwable t) {}
|
||||||
|
@ -48,7 +48,7 @@ public class LogsHelper extends HelperBase {
|
|||||||
File f = null;
|
File f = null;
|
||||||
if (ctx.hasWrapper()) {
|
if (ctx.hasWrapper()) {
|
||||||
String wv = System.getProperty("wrapper.version");
|
String wv = System.getProperty("wrapper.version");
|
||||||
if (wv != null && (new VersionComparator()).compare(wv, LOCATION_AVAILABLE) >= 0) {
|
if (wv != null && VersionComparator.comp(wv, LOCATION_AVAILABLE) >= 0) {
|
||||||
try {
|
try {
|
||||||
f = WrapperManager.getWrapperLogFile();
|
f = WrapperManager.getWrapperLogFile();
|
||||||
} catch (Throwable t) {}
|
} catch (Throwable t) {}
|
||||||
|
@ -73,7 +73,7 @@ public class PluginStarter implements Runnable {
|
|||||||
!NewsHelper.isUpdateInProgress()) {
|
!NewsHelper.isUpdateInProgress()) {
|
||||||
String prev = _context.getProperty("router.previousVersion");
|
String prev = _context.getProperty("router.previousVersion");
|
||||||
if (prev != null &&
|
if (prev != null &&
|
||||||
(new VersionComparator()).compare(RouterVersion.VERSION, prev) > 0) {
|
VersionComparator.comp(RouterVersion.VERSION, prev) > 0) {
|
||||||
updateAll(_context, true);
|
updateAll(_context, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ public class PluginStarter implements Runnable {
|
|||||||
|
|
||||||
String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version");
|
String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version");
|
||||||
if (minVersion != null &&
|
if (minVersion != null &&
|
||||||
(new VersionComparator()).compare(CoreVersion.VERSION, minVersion) < 0) {
|
VersionComparator.comp(CoreVersion.VERSION, minVersion) < 0) {
|
||||||
String foo = "Plugin " + appName + " requires I2P version " + minVersion + " or higher";
|
String foo = "Plugin " + appName + " requires I2P version " + minVersion + " or higher";
|
||||||
log.error(foo);
|
log.error(foo);
|
||||||
disablePlugin(appName);
|
disablePlugin(appName);
|
||||||
@ -245,7 +245,7 @@ public class PluginStarter implements Runnable {
|
|||||||
|
|
||||||
minVersion = ConfigClientsHelper.stripHTML(props, "min-java-version");
|
minVersion = ConfigClientsHelper.stripHTML(props, "min-java-version");
|
||||||
if (minVersion != null &&
|
if (minVersion != null &&
|
||||||
(new VersionComparator()).compare(System.getProperty("java.version"), minVersion) < 0) {
|
VersionComparator.comp(System.getProperty("java.version"), minVersion) < 0) {
|
||||||
String foo = "Plugin " + appName + " requires Java version " + minVersion + " or higher";
|
String foo = "Plugin " + appName + " requires Java version " + minVersion + " or higher";
|
||||||
log.error(foo);
|
log.error(foo);
|
||||||
disablePlugin(appName);
|
disablePlugin(appName);
|
||||||
@ -255,7 +255,7 @@ public class PluginStarter implements Runnable {
|
|||||||
String jVersion = LogsHelper.jettyVersion();
|
String jVersion = LogsHelper.jettyVersion();
|
||||||
minVersion = ConfigClientsHelper.stripHTML(props, "min-jetty-version");
|
minVersion = ConfigClientsHelper.stripHTML(props, "min-jetty-version");
|
||||||
if (minVersion != null &&
|
if (minVersion != null &&
|
||||||
(new VersionComparator()).compare(minVersion, jVersion) > 0) {
|
VersionComparator.comp(minVersion, jVersion) > 0) {
|
||||||
String foo = "Plugin " + appName + " requires Jetty version " + minVersion + " or higher";
|
String foo = "Plugin " + appName + " requires Jetty version " + minVersion + " or higher";
|
||||||
log.error(foo);
|
log.error(foo);
|
||||||
disablePlugin(appName);
|
disablePlugin(appName);
|
||||||
@ -264,7 +264,7 @@ public class PluginStarter implements Runnable {
|
|||||||
|
|
||||||
String maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
|
String maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
|
||||||
if (maxVersion != null &&
|
if (maxVersion != null &&
|
||||||
(new VersionComparator()).compare(maxVersion, jVersion) < 0) {
|
VersionComparator.comp(maxVersion, jVersion) < 0) {
|
||||||
String foo = "Plugin " + appName + " requires Jetty version " + maxVersion + " or lower";
|
String foo = "Plugin " + appName + " requires Jetty version " + maxVersion + " or lower";
|
||||||
log.error(foo);
|
log.error(foo);
|
||||||
disablePlugin(appName);
|
disablePlugin(appName);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package gnu.crypto.prng;
|
package gnu.crypto.prng;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
@ -77,8 +77,7 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
|
|||||||
/** the seed is only propogated once the prng is started with startup() */
|
/** the seed is only propogated once the prng is started with startup() */
|
||||||
@Override
|
@Override
|
||||||
public void seed(byte val[]) {
|
public void seed(byte val[]) {
|
||||||
Map props = new HashMap(1);
|
Map props = Collections.singletonMap(SEED, val);
|
||||||
props.put(SEED, val);
|
|
||||||
init(props);
|
init(props);
|
||||||
//fillBlock();
|
//fillBlock();
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ import java.io.Serializable;
|
|||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import net.i2p.crypto.CryptixAESKeyCache;
|
import net.i2p.crypto.CryptixAESKeyCache;
|
||||||
@ -131,8 +131,7 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void seed(byte val[]) {
|
public void seed(byte val[]) {
|
||||||
Map props = new HashMap(1);
|
Map props = Collections.singletonMap(SEED, val);
|
||||||
props.put(SEED, val);
|
|
||||||
init(props);
|
init(props);
|
||||||
fillBlock();
|
fillBlock();
|
||||||
}
|
}
|
||||||
|
@ -150,11 +150,19 @@ public class SessionKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accept the given tags and associate them with the given key for decryption
|
* Accept the given tags and associate them with the given key for decryption,
|
||||||
*
|
* with the default expiration.
|
||||||
*/
|
*/
|
||||||
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags) { // nop
|
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags) {}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Accept the given tags and associate them with the given key for decryption,
|
||||||
|
* with specified expiration.
|
||||||
|
*
|
||||||
|
* @param expire time from now
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags, long expire) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if we have received a session key associated with the given session tag,
|
* Determine if we have received a session key associated with the given session tag,
|
||||||
|
@ -89,9 +89,8 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
private final int _lowThreshold;
|
private final int _lowThreshold;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let session tags sit around for this long before expiring them. We can now have such a large
|
* Let outbound session tags sit around for this long before expiring them.
|
||||||
* value since there is the persistent session key manager. This value is for outbound tags -
|
* Inbound tag expiration is set by SESSION_LIFETIME_MAX_MS
|
||||||
* inbound tags are managed by SESSION_LIFETIME_MAX_MS
|
|
||||||
*/
|
*/
|
||||||
private final static long SESSION_TAG_DURATION_MS = 12 * 60 * 1000;
|
private final static long SESSION_TAG_DURATION_MS = 12 * 60 * 1000;
|
||||||
|
|
||||||
@ -99,6 +98,8 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
* Keep unused inbound session tags around for this long (a few minutes longer than
|
* Keep unused inbound session tags around for this long (a few minutes longer than
|
||||||
* session tags are used on the outbound side so that no reasonable network lag
|
* session tags are used on the outbound side so that no reasonable network lag
|
||||||
* can cause failed decrypts)
|
* can cause failed decrypts)
|
||||||
|
*
|
||||||
|
* This is also the max idle time for an outbound session.
|
||||||
*/
|
*/
|
||||||
private final static long SESSION_LIFETIME_MAX_MS = SESSION_TAG_DURATION_MS + 3 * 60 * 1000;
|
private final static long SESSION_LIFETIME_MAX_MS = SESSION_TAG_DURATION_MS + 3 * 60 * 1000;
|
||||||
|
|
||||||
@ -499,11 +500,22 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
/**
|
/**
|
||||||
* Accept the given tags and associate them with the given key for decryption
|
* Accept the given tags and associate them with the given key for decryption
|
||||||
*
|
*
|
||||||
|
* @param sessionTags modifiable; NOT copied
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags) {
|
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags) {
|
||||||
int overage = 0;
|
tagsReceived(key, sessionTags, SESSION_LIFETIME_MAX_MS);
|
||||||
TagSet tagSet = new TagSet(sessionTags, key, _context.clock().now(), _rcvTagSetID.incrementAndGet());
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept the given tags and associate them with the given key for decryption
|
||||||
|
*
|
||||||
|
* @param sessionTags modifiable; NOT copied
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags, long expire) {
|
||||||
|
TagSet tagSet = new TagSet(sessionTags, key, _context.clock().now() + expire,
|
||||||
|
_rcvTagSetID.incrementAndGet());
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Received " + tagSet);
|
_log.info("Received " + tagSet);
|
||||||
TagSet old = null;
|
TagSet old = null;
|
||||||
@ -513,7 +525,6 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
//if (_log.shouldLog(Log.DEBUG))
|
//if (_log.shouldLog(Log.DEBUG))
|
||||||
// _log.debug("Receiving tag " + tag + " in tagSet: " + tagSet);
|
// _log.debug("Receiving tag " + tag + " in tagSet: " + tagSet);
|
||||||
old = _inboundTagSets.put(tag, tagSet);
|
old = _inboundTagSets.put(tag, tagSet);
|
||||||
overage = _inboundTagSets.size() - MAX_INBOUND_SESSION_TAGS;
|
|
||||||
if (old != null) {
|
if (old != null) {
|
||||||
if (!old.getAssociatedKey().equals(tagSet.getAssociatedKey())) {
|
if (!old.getAssociatedKey().equals(tagSet.getAssociatedKey())) {
|
||||||
_inboundTagSets.remove(tag);
|
_inboundTagSets.remove(tag);
|
||||||
@ -546,6 +557,7 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int overage = _inboundTagSets.size() - MAX_INBOUND_SESSION_TAGS;
|
||||||
if (overage > 0)
|
if (overage > 0)
|
||||||
clearExcess(overage);
|
clearExcess(overage);
|
||||||
|
|
||||||
@ -573,25 +585,23 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
_log.log(Log.CRIT, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
|
_log.log(Log.CRIT, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
|
||||||
List<TagSet> removed = new ArrayList(toRemove);
|
List<TagSet> removed = new ArrayList(toRemove);
|
||||||
synchronized (_inboundTagSets) {
|
synchronized (_inboundTagSets) {
|
||||||
for (Iterator<TagSet> iter = _inboundTagSets.values().iterator(); iter.hasNext(); ) {
|
for (TagSet set : _inboundTagSets.values()) {
|
||||||
TagSet set = iter.next();
|
|
||||||
int size = set.getTags().size();
|
int size = set.getTags().size();
|
||||||
if (size > 1000)
|
if (size > 1000)
|
||||||
absurd++;
|
absurd++;
|
||||||
if (size > 100)
|
if (size > 100)
|
||||||
large++;
|
large++;
|
||||||
if (now - set.getDate() > SESSION_LIFETIME_MAX_MS)
|
if (now >= set.getDate())
|
||||||
old++;
|
old++;
|
||||||
else if (now - set.getDate() < 1*60*1000)
|
else if (set.getDate() - now > 10*60*1000)
|
||||||
recent++;
|
recent++;
|
||||||
|
|
||||||
if ((removed.size() < (toRemove)) || (now - set.getDate() > SESSION_LIFETIME_MAX_MS))
|
if ((removed.size() < (toRemove)) || (now >= set.getDate()))
|
||||||
removed.add(set);
|
removed.add(set);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < removed.size(); i++) {
|
for (int i = 0; i < removed.size(); i++) {
|
||||||
TagSet cur = removed.get(i);
|
TagSet cur = removed.get(i);
|
||||||
for (Iterator<SessionTag> iter = cur.getTags().iterator(); iter.hasNext(); ) {
|
for (SessionTag tag : cur.getTags()) {
|
||||||
SessionTag tag = iter.next();
|
|
||||||
_inboundTagSets.remove(tag);
|
_inboundTagSets.remove(tag);
|
||||||
tags++;
|
tags++;
|
||||||
}
|
}
|
||||||
@ -616,21 +626,21 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SessionKey consumeTag(SessionTag tag) {
|
public SessionKey consumeTag(SessionTag tag) {
|
||||||
//if (false) aggressiveExpire();
|
TagSet tagSet;
|
||||||
synchronized (_inboundTagSets) {
|
synchronized (_inboundTagSets) {
|
||||||
TagSet tagSet = _inboundTagSets.remove(tag);
|
tagSet = _inboundTagSets.remove(tag);
|
||||||
if (tagSet == null) {
|
if (tagSet == null) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Cannot consume IB " + tag + " as it is not known");
|
_log.debug("Cannot consume IB " + tag + " as it is not known");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
tagSet.consume(tag);
|
tagSet.consume(tag);
|
||||||
|
|
||||||
SessionKey key = tagSet.getAssociatedKey();
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
|
||||||
_log.debug("IB Tag consumed: " + tag + " from: " + tagSet);
|
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SessionKey key = tagSet.getAssociatedKey();
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("IB Tag consumed: " + tag + " from: " + tagSet);
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OutboundSession getSession(PublicKey target) {
|
private OutboundSession getSession(PublicKey target) {
|
||||||
@ -660,44 +670,28 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
/**
|
/**
|
||||||
* Aggressively expire inbound tag sets and outbound sessions
|
* Aggressively expire inbound tag sets and outbound sessions
|
||||||
*
|
*
|
||||||
* @return number of tag sets expired
|
* @return number of tag sets expired (bogus as it overcounts inbound)
|
||||||
*/
|
*/
|
||||||
private int aggressiveExpire() {
|
private int aggressiveExpire() {
|
||||||
int removed = 0;
|
int removed = 0;
|
||||||
int remaining = 0;
|
int remaining = 0;
|
||||||
long now = _context.clock().now();
|
long now = _context.clock().now();
|
||||||
StringBuilder buf = null;
|
|
||||||
//StringBuilder bufSummary = null;
|
|
||||||
if (_log.shouldLog(Log.DEBUG)) {
|
|
||||||
buf = new StringBuilder(128);
|
|
||||||
buf.append("Expiring inbound: ");
|
|
||||||
//bufSummary = new StringBuilder(1024);
|
|
||||||
}
|
|
||||||
synchronized (_inboundTagSets) {
|
synchronized (_inboundTagSets) {
|
||||||
for (Iterator<SessionTag> iter = _inboundTagSets.keySet().iterator(); iter.hasNext();) {
|
for (Iterator<TagSet> iter = _inboundTagSets.values().iterator(); iter.hasNext();) {
|
||||||
SessionTag tag = iter.next();
|
TagSet ts = iter.next();
|
||||||
TagSet ts = _inboundTagSets.get(tag);
|
// for inbound tagsets, getDate() is the expire time
|
||||||
long age = now - ts.getDate();
|
if (ts.getDate() <= now) {
|
||||||
if (age > SESSION_LIFETIME_MAX_MS) {
|
|
||||||
//if (ts.getDate() < now - SESSION_LIFETIME_MAX_MS) {
|
|
||||||
iter.remove();
|
iter.remove();
|
||||||
|
// bug, this counts inbound tags, not tag sets
|
||||||
removed++;
|
removed++;
|
||||||
if (buf != null)
|
|
||||||
buf.append(tag).append(" @ age ").append(DataHelper.formatDuration(age));
|
|
||||||
//} else if (false && (bufSummary != null) ) {
|
|
||||||
// bufSummary.append("\nTagSet: " + ts + ", key: " + ts.getAssociatedKey()
|
|
||||||
// + ": tag: " + tag);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
remaining = _inboundTagSets.size();
|
remaining = _inboundTagSets.size();
|
||||||
}
|
}
|
||||||
_context.statManager().addRateData("crypto.sessionTagsRemaining", remaining, 0);
|
_context.statManager().addRateData("crypto.sessionTagsRemaining", remaining, 0);
|
||||||
if ( (buf != null) && (removed > 0) )
|
if (removed > 0 && _log.shouldLog(Log.DEBUG))
|
||||||
_log.debug(buf.toString());
|
_log.debug("Expired inbound: " + removed);
|
||||||
//if (bufSummary != null)
|
|
||||||
// _log.debug("Cleaning up with remaining: " + bufSummary.toString());
|
|
||||||
|
|
||||||
//_log.warn("Expiring tags: [" + tagsToDrop + "]");
|
|
||||||
|
|
||||||
synchronized (_outboundSessions) {
|
synchronized (_outboundSessions) {
|
||||||
for (Iterator<OutboundSession> iter = _outboundSessions.values().iterator(); iter.hasNext();) {
|
for (Iterator<OutboundSession> iter = _outboundSessions.values().iterator(); iter.hasNext();) {
|
||||||
@ -722,10 +716,12 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
Set<TagSet> inbound = getInboundTagSets();
|
Set<TagSet> inbound = getInboundTagSets();
|
||||||
Map<SessionKey, Set<TagSet>> inboundSets = new HashMap(inbound.size());
|
Map<SessionKey, Set<TagSet>> inboundSets = new HashMap(inbound.size());
|
||||||
// Build a map of the inbound tag sets, grouped by SessionKey
|
// Build a map of the inbound tag sets, grouped by SessionKey
|
||||||
for (Iterator<TagSet> iter = inbound.iterator(); iter.hasNext();) {
|
for (TagSet ts : inbound) {
|
||||||
TagSet ts = iter.next();
|
|
||||||
if (!inboundSets.containsKey(ts.getAssociatedKey())) inboundSets.put(ts.getAssociatedKey(), new HashSet());
|
|
||||||
Set<TagSet> sets = inboundSets.get(ts.getAssociatedKey());
|
Set<TagSet> sets = inboundSets.get(ts.getAssociatedKey());
|
||||||
|
if (sets == null) {
|
||||||
|
sets = new HashSet();
|
||||||
|
inboundSets.put(ts.getAssociatedKey(), sets);
|
||||||
|
}
|
||||||
sets.add(ts);
|
sets.add(ts);
|
||||||
}
|
}
|
||||||
int total = 0;
|
int total = 0;
|
||||||
@ -741,8 +737,12 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
TagSet ts = siter.next();
|
TagSet ts = siter.next();
|
||||||
int size = ts.getTags().size();
|
int size = ts.getTags().size();
|
||||||
total += size;
|
total += size;
|
||||||
buf.append("<li><b>ID: ").append(ts.getID())
|
buf.append("<li><b>ID: ").append(ts.getID());
|
||||||
.append(" Received:</b> ").append(DataHelper.formatDuration2(now - ts.getDate())).append(" ago with ");
|
long expires = ts.getDate() - now;
|
||||||
|
if (expires > 0)
|
||||||
|
buf.append(" Expires in:</b> ").append(DataHelper.formatDuration2(expires)).append(" with ");
|
||||||
|
else
|
||||||
|
buf.append(" Expired:</b> ").append(DataHelper.formatDuration2(0 - expires)).append(" ago with ");
|
||||||
buf.append(size).append('/').append(ts.getOriginalSize()).append(" tags remaining</li>");
|
buf.append(size).append('/').append(ts.getOriginalSize()).append(" tags remaining</li>");
|
||||||
}
|
}
|
||||||
buf.append("</ul></td></tr>\n");
|
buf.append("</ul></td></tr>\n");
|
||||||
@ -802,7 +802,10 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
*/
|
*/
|
||||||
private static class TagSetComparator implements Comparator<TagSet> {
|
private static class TagSetComparator implements Comparator<TagSet> {
|
||||||
public int compare(TagSet l, TagSet r) {
|
public int compare(TagSet l, TagSet r) {
|
||||||
return (int) (l.getDate() - r.getDate());
|
int rv = (int) (l.getDate() - r.getDate());
|
||||||
|
if (rv != 0)
|
||||||
|
return rv;
|
||||||
|
return l.hashCode() - r.hashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1088,6 +1091,9 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
/** did we get an ack for this tagset? Only for outbound tagsets */
|
/** did we get an ack for this tagset? Only for outbound tagsets */
|
||||||
private boolean _acked;
|
private boolean _acked;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param date For inbound: when the TagSet will expire; for outbound: creation time
|
||||||
|
*/
|
||||||
public TagSet(Set<SessionTag> tags, SessionKey key, long date, int id) {
|
public TagSet(Set<SessionTag> tags, SessionKey key, long date, int id) {
|
||||||
if (key == null) throw new IllegalArgumentException("Missing key");
|
if (key == null) throw new IllegalArgumentException("Missing key");
|
||||||
if (tags == null) throw new IllegalArgumentException("Missing tags");
|
if (tags == null) throw new IllegalArgumentException("Missing tags");
|
||||||
@ -1104,7 +1110,9 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** when the tag set was created */
|
/**
|
||||||
|
* For inbound: when the TagSet will expire; for outbound: creation time
|
||||||
|
*/
|
||||||
public long getDate() {
|
public long getDate() {
|
||||||
return _date;
|
return _date;
|
||||||
}
|
}
|
||||||
@ -1135,23 +1143,29 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let's do this without counting the elements first.
|
* For outbound only.
|
||||||
* Caller must synch.
|
* Caller must synch.
|
||||||
|
* @return a tag or null
|
||||||
*/
|
*/
|
||||||
public SessionTag consumeNext() {
|
public SessionTag consumeNext() {
|
||||||
SessionTag first;
|
Iterator<SessionTag> iter = _sessionTags.iterator();
|
||||||
try {
|
if (!iter.hasNext())
|
||||||
first = _sessionTags.iterator().next();
|
|
||||||
} catch (NoSuchElementException nsee) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
SessionTag first = iter.next();
|
||||||
_sessionTags.remove(first);
|
iter.remove();
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
//public Exception getCreatedBy() { return _createdBy; }
|
//public Exception getCreatedBy() { return _createdBy; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For outbound only.
|
||||||
|
*/
|
||||||
public void setAcked() { _acked = true; }
|
public void setAcked() { _acked = true; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For outbound only.
|
||||||
|
*/
|
||||||
public boolean getAcked() { return _acked; }
|
public boolean getAcked() { return _acked; }
|
||||||
|
|
||||||
/****** this will return a dup if two in the same ms, so just use java
|
/****** this will return a dup if two in the same ms, so just use java
|
||||||
|
@ -302,7 +302,7 @@ riCe6OlAEiNpcc6mMyIYYWFICbrDFTrDR3wXqwc/Jkcx6L5VVWoagpSzbo3yGhc=
|
|||||||
* version, otherwise <code>false</code>.
|
* version, otherwise <code>false</code>.
|
||||||
*/
|
*/
|
||||||
public static final boolean needsUpdate(String currentVersion, String newVersion) {
|
public static final boolean needsUpdate(String currentVersion, String newVersion) {
|
||||||
return (new VersionComparator()).compare(currentVersion, newVersion) < 0;
|
return VersionComparator.comp(currentVersion, newVersion) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return success */
|
/** @return success */
|
||||||
|
@ -56,7 +56,7 @@ public abstract class SystemVersion {
|
|||||||
if (_isAndroid) {
|
if (_isAndroid) {
|
||||||
_oneDotSix = _androidSDK >= 9;
|
_oneDotSix = _androidSDK >= 9;
|
||||||
} else {
|
} else {
|
||||||
_oneDotSix = (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0;
|
_oneDotSix = VersionComparator.comp(System.getProperty("java.version"), "1.6") >= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,9 +11,15 @@ import java.util.Comparator;
|
|||||||
*/
|
*/
|
||||||
public class VersionComparator implements Comparator<String> {
|
public class VersionComparator implements Comparator<String> {
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(String l, String r) {
|
public int compare(String l, String r) {
|
||||||
|
return comp(l, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To avoid churning comparators
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public static int comp(String l, String r) {
|
||||||
if (l.equals(r))
|
if (l.equals(r))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -17,8 +17,12 @@ import java.util.Set;
|
|||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
|
import net.i2p.data.RouterInfo;
|
||||||
|
import net.i2p.data.SessionKey;
|
||||||
|
import net.i2p.data.SessionTag;
|
||||||
import net.i2p.data.TunnelId;
|
import net.i2p.data.TunnelId;
|
||||||
//import net.i2p.util.Log;
|
//import net.i2p.util.Log;
|
||||||
|
import net.i2p.util.VersionComparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the message a router sends to another router to search for a
|
* Defines the message a router sends to another router to search for a
|
||||||
@ -34,6 +38,8 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
|
|||||||
private TunnelId _replyTunnel;
|
private TunnelId _replyTunnel;
|
||||||
/** this must be kept as a list to preserve the order and not break the checksum */
|
/** this must be kept as a list to preserve the order and not break the checksum */
|
||||||
private List<Hash> _dontIncludePeers;
|
private List<Hash> _dontIncludePeers;
|
||||||
|
private SessionKey _replyKey;
|
||||||
|
private SessionTag _replyTag;
|
||||||
|
|
||||||
//private static volatile long _currentLookupPeriod = 0;
|
//private static volatile long _currentLookupPeriod = 0;
|
||||||
//private static volatile int _currentLookupCount = 0;
|
//private static volatile int _currentLookupCount = 0;
|
||||||
@ -45,6 +51,11 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
|
|||||||
Have to prevent a huge alloc on rcv of a malicious msg though */
|
Have to prevent a huge alloc on rcv of a malicious msg though */
|
||||||
private static final int MAX_NUM_PEERS = 512;
|
private static final int MAX_NUM_PEERS = 512;
|
||||||
|
|
||||||
|
private static final byte FLAG_TUNNEL = 0x01;
|
||||||
|
private static final byte FLAG_ENCRYPT = 0x02;
|
||||||
|
|
||||||
|
private static final String MIN_ENCRYPTION_VERSION = "0.9.8";
|
||||||
|
|
||||||
public DatabaseLookupMessage(I2PAppContext context) {
|
public DatabaseLookupMessage(I2PAppContext context) {
|
||||||
this(context, false);
|
this(context, false);
|
||||||
}
|
}
|
||||||
@ -144,6 +155,49 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
|
|||||||
_replyTunnel = replyTunnel;
|
_replyTunnel = replyTunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this router support encrypted replies?
|
||||||
|
*
|
||||||
|
* @param to null OK
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public static boolean supportsEncryptedReplies(RouterInfo to) {
|
||||||
|
if (to == null)
|
||||||
|
return false;
|
||||||
|
String v = to.getOption("router.version");
|
||||||
|
return v != null &&
|
||||||
|
VersionComparator.comp(v, MIN_ENCRYPTION_VERSION) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The included session key or null if unset
|
||||||
|
*
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public SessionKey getReplyKey() { return _replyKey; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The included session tag or null if unset
|
||||||
|
*
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public SessionTag getReplyTag() { return _replyTag; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only worthwhile if sending reply via tunnel
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException if key or tag previously set, to protect saved checksum
|
||||||
|
* @param encryptKey non-null
|
||||||
|
* @param encryptTag non-null
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public void setReplySession(SessionKey encryptKey, SessionTag encryptTag) {
|
||||||
|
if (_replyKey != null || _replyTag != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
_replyKey = encryptKey;
|
||||||
|
_replyTag = encryptTag;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of peers that a lookup reply should NOT include.
|
* Set of peers that a lookup reply should NOT include.
|
||||||
* WARNING - returns a copy.
|
* WARNING - returns a copy.
|
||||||
@ -224,7 +278,8 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
|
|||||||
|
|
||||||
// as of 0.9.6, ignore other 7 bits of the flag byte
|
// as of 0.9.6, ignore other 7 bits of the flag byte
|
||||||
// TODO store the whole flag byte
|
// TODO store the whole flag byte
|
||||||
boolean tunnelSpecified = (data[curIndex] & 0x01) != 0;
|
boolean tunnelSpecified = (data[curIndex] & FLAG_TUNNEL) != 0;
|
||||||
|
boolean replyKeySpecified = (data[curIndex] & FLAG_ENCRYPT) != 0;
|
||||||
curIndex++;
|
curIndex++;
|
||||||
|
|
||||||
if (tunnelSpecified) {
|
if (tunnelSpecified) {
|
||||||
@ -246,6 +301,15 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
|
|||||||
peers.add(p);
|
peers.add(p);
|
||||||
}
|
}
|
||||||
_dontIncludePeers = peers;
|
_dontIncludePeers = peers;
|
||||||
|
if (replyKeySpecified) {
|
||||||
|
byte[] rk = new byte[SessionKey.KEYSIZE_BYTES];
|
||||||
|
System.arraycopy(data, curIndex, rk, 0, SessionKey.KEYSIZE_BYTES);
|
||||||
|
_replyKey = new SessionKey(rk);
|
||||||
|
curIndex += SessionKey.KEYSIZE_BYTES;
|
||||||
|
byte[] rt = new byte[SessionTag.BYTE_LENGTH];
|
||||||
|
System.arraycopy(data, curIndex, rt, 0, SessionTag.BYTE_LENGTH);
|
||||||
|
_replyTag = new SessionTag(rt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -258,6 +322,8 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
|
|||||||
totalLength += 2; // numPeers
|
totalLength += 2; // numPeers
|
||||||
if (_dontIncludePeers != null)
|
if (_dontIncludePeers != null)
|
||||||
totalLength += Hash.HASH_LENGTH * _dontIncludePeers.size();
|
totalLength += Hash.HASH_LENGTH * _dontIncludePeers.size();
|
||||||
|
if (_replyKey != null)
|
||||||
|
totalLength += SessionKey.KEYSIZE_BYTES + SessionTag.BYTE_LENGTH;
|
||||||
return totalLength;
|
return totalLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,12 +335,17 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
|
|||||||
curIndex += Hash.HASH_LENGTH;
|
curIndex += Hash.HASH_LENGTH;
|
||||||
System.arraycopy(_fromHash.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
System.arraycopy(_fromHash.getData(), 0, out, curIndex, Hash.HASH_LENGTH);
|
||||||
curIndex += Hash.HASH_LENGTH;
|
curIndex += Hash.HASH_LENGTH;
|
||||||
// TODO allow specification of the other 7 bits of the flag byte
|
// Generate the flag byte
|
||||||
if (_replyTunnel != null) {
|
if (_replyTunnel != null) {
|
||||||
out[curIndex++] = 0x01;
|
byte flag = FLAG_TUNNEL;
|
||||||
|
if (_replyKey != null)
|
||||||
|
flag |= FLAG_ENCRYPT;
|
||||||
|
out[curIndex++] = flag;
|
||||||
byte id[] = DataHelper.toLong(4, _replyTunnel.getTunnelId());
|
byte id[] = DataHelper.toLong(4, _replyTunnel.getTunnelId());
|
||||||
System.arraycopy(id, 0, out, curIndex, 4);
|
System.arraycopy(id, 0, out, curIndex, 4);
|
||||||
curIndex += 4;
|
curIndex += 4;
|
||||||
|
} else if (_replyKey != null) {
|
||||||
|
out[curIndex++] = FLAG_ENCRYPT;
|
||||||
} else {
|
} else {
|
||||||
out[curIndex++] = 0x00;
|
out[curIndex++] = 0x00;
|
||||||
}
|
}
|
||||||
@ -293,6 +364,12 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
|
|||||||
curIndex += Hash.HASH_LENGTH;
|
curIndex += Hash.HASH_LENGTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_replyKey != null) {
|
||||||
|
System.arraycopy(_replyKey.getData(), 0, out, curIndex, SessionKey.KEYSIZE_BYTES);
|
||||||
|
curIndex += SessionKey.KEYSIZE_BYTES;
|
||||||
|
System.arraycopy(_replyTag.getData(), 0, out, curIndex, SessionTag.BYTE_LENGTH);
|
||||||
|
curIndex += SessionTag.BYTE_LENGTH;
|
||||||
|
}
|
||||||
return curIndex;
|
return curIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,6 +403,10 @@ public class DatabaseLookupMessage extends FastI2NPMessageImpl {
|
|||||||
buf.append("\n\tSearch Key: ").append(_key);
|
buf.append("\n\tSearch Key: ").append(_key);
|
||||||
buf.append("\n\tFrom: ").append(_fromHash);
|
buf.append("\n\tFrom: ").append(_fromHash);
|
||||||
buf.append("\n\tReply Tunnel: ").append(_replyTunnel);
|
buf.append("\n\tReply Tunnel: ").append(_replyTunnel);
|
||||||
|
if (_replyKey != null)
|
||||||
|
buf.append("\n\tReply Key: ").append(_replyKey);
|
||||||
|
if (_replyTag != null)
|
||||||
|
buf.append("\n\tReply Tag: ").append(_replyTag);
|
||||||
buf.append("\n\tDont Include Peers: ");
|
buf.append("\n\tDont Include Peers: ");
|
||||||
if (_dontIncludePeers != null)
|
if (_dontIncludePeers != null)
|
||||||
buf.append(_dontIncludePeers.size());
|
buf.append(_dontIncludePeers.size());
|
||||||
|
@ -8,6 +8,7 @@ package net.i2p.router.networkdb;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ import net.i2p.data.Hash;
|
|||||||
import net.i2p.data.LeaseSet;
|
import net.i2p.data.LeaseSet;
|
||||||
import net.i2p.data.RouterIdentity;
|
import net.i2p.data.RouterIdentity;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.RouterInfo;
|
||||||
|
import net.i2p.data.SessionKey;
|
||||||
import net.i2p.data.TunnelId;
|
import net.i2p.data.TunnelId;
|
||||||
import net.i2p.data.i2np.DatabaseLookupMessage;
|
import net.i2p.data.i2np.DatabaseLookupMessage;
|
||||||
import net.i2p.data.i2np.DatabaseSearchReplyMessage;
|
import net.i2p.data.i2np.DatabaseSearchReplyMessage;
|
||||||
@ -27,6 +29,7 @@ import net.i2p.router.JobImpl;
|
|||||||
import net.i2p.router.OutNetMessage;
|
import net.i2p.router.OutNetMessage;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
import net.i2p.router.networkdb.kademlia.MessageWrapper;
|
||||||
import net.i2p.router.message.SendMessageDirectJob;
|
import net.i2p.router.message.SendMessageDirectJob;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
@ -36,8 +39,9 @@ import net.i2p.util.Log;
|
|||||||
* Unused directly - see kademlia/ for extension
|
* Unused directly - see kademlia/ for extension
|
||||||
*/
|
*/
|
||||||
public class HandleDatabaseLookupMessageJob extends JobImpl {
|
public class HandleDatabaseLookupMessageJob extends JobImpl {
|
||||||
private Log _log;
|
private final Log _log;
|
||||||
private DatabaseLookupMessage _message;
|
private final DatabaseLookupMessage _message;
|
||||||
|
|
||||||
private final static int MAX_ROUTERS_RETURNED = 3;
|
private final static int MAX_ROUTERS_RETURNED = 3;
|
||||||
private final static int CLOSENESS_THRESHOLD = 8; // FNDF.MAX_TO_FLOOD + 1
|
private final static int CLOSENESS_THRESHOLD = 8; // FNDF.MAX_TO_FLOOD + 1
|
||||||
private final static int REPLY_TIMEOUT = 60*1000;
|
private final static int REPLY_TIMEOUT = 60*1000;
|
||||||
@ -149,8 +153,7 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
|
|||||||
if ( (info.getIdentity().isHidden()) || (isUnreachable(info) && !publishUnreachable()) ) {
|
if ( (info.getIdentity().isHidden()) || (isUnreachable(info) && !publishUnreachable()) ) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Not answering a query for a netDb peer who isn't reachable");
|
_log.debug("Not answering a query for a netDb peer who isn't reachable");
|
||||||
Set<Hash> us = new HashSet<Hash>(1);
|
Set<Hash> us = Collections.singleton(getContext().routerHash());
|
||||||
us.add(getContext().routerHash());
|
|
||||||
sendClosest(_message.getSearchKey(), us, fromKey, _message.getReplyTunnel());
|
sendClosest(_message.getSearchKey(), us, fromKey, _message.getReplyTunnel());
|
||||||
//} else if (info.isHidden()) {
|
//} else if (info.isHidden()) {
|
||||||
// // Don't return hidden nodes
|
// // Don't return hidden nodes
|
||||||
@ -203,9 +206,11 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
|
|||||||
*/
|
*/
|
||||||
private Set<Hash> getNearestRouters() {
|
private Set<Hash> getNearestRouters() {
|
||||||
Set<Hash> dontInclude = _message.getDontIncludePeers();
|
Set<Hash> dontInclude = _message.getDontIncludePeers();
|
||||||
|
Hash us = getContext().routerHash();
|
||||||
if (dontInclude == null)
|
if (dontInclude == null)
|
||||||
dontInclude = new HashSet(1);
|
dontInclude = Collections.singleton(us);
|
||||||
dontInclude.add(getContext().routerHash());
|
else
|
||||||
|
dontInclude.add(us);
|
||||||
// Honor flag to exclude all floodfills
|
// Honor flag to exclude all floodfills
|
||||||
//if (dontInclude.contains(Hash.FAKE_HASH)) {
|
//if (dontInclude.contains(Hash.FAKE_HASH)) {
|
||||||
// This is handled in FloodfillPeerSelector
|
// This is handled in FloodfillPeerSelector
|
||||||
@ -289,6 +294,15 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
|
|||||||
getContext().tunnelDispatcher().dispatch(m);
|
getContext().tunnelDispatcher().dispatch(m);
|
||||||
} else {
|
} else {
|
||||||
// if we aren't the gateway, forward it on
|
// if we aren't the gateway, forward it on
|
||||||
|
SessionKey replyKey = _message.getReplyKey();
|
||||||
|
if (replyKey != null) {
|
||||||
|
// encrypt the reply
|
||||||
|
message = MessageWrapper.wrap(getContext(), message, replyKey, _message.getReplyTag());
|
||||||
|
if (message == null) {
|
||||||
|
_log.error("Encryption error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
TunnelGatewayMessage m = new TunnelGatewayMessage(getContext());
|
TunnelGatewayMessage m = new TunnelGatewayMessage(getContext());
|
||||||
m.setMessage(message);
|
m.setMessage(message);
|
||||||
m.setMessageExpiration(message.getMessageExpiration());
|
m.setMessageExpiration(message.getMessageExpiration());
|
||||||
|
@ -111,6 +111,10 @@ class FloodfillVerifyStoreJob extends JobImpl {
|
|||||||
_facade.verifyFinished(_key);
|
_facade.verifyFinished(_key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (DatabaseLookupMessage.supportsEncryptedReplies(peer)) {
|
||||||
|
MessageWrapper.OneTimeSession sess = MessageWrapper.generateSession(getContext());
|
||||||
|
lookup.setReplySession(sess.key, sess.tag);
|
||||||
|
}
|
||||||
Hash fromKey;
|
Hash fromKey;
|
||||||
if (_isRouterInfo)
|
if (_isRouterInfo)
|
||||||
fromKey = null;
|
fromKey = null;
|
||||||
|
@ -24,6 +24,7 @@ import net.i2p.router.RouterContext;
|
|||||||
import net.i2p.router.TunnelInfo;
|
import net.i2p.router.TunnelInfo;
|
||||||
import net.i2p.router.util.RandomIterator;
|
import net.i2p.router.util.RandomIterator;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
import net.i2p.util.VersionComparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A traditional Kademlia search that continues to search
|
* A traditional Kademlia search that continues to search
|
||||||
@ -233,6 +234,11 @@ class IterativeSearchJob extends FloodSearchJob {
|
|||||||
// if we have the ff RI, garlic encrypt it
|
// if we have the ff RI, garlic encrypt it
|
||||||
RouterInfo ri = getContext().netDb().lookupRouterInfoLocally(peer);
|
RouterInfo ri = getContext().netDb().lookupRouterInfoLocally(peer);
|
||||||
if (ri != null) {
|
if (ri != null) {
|
||||||
|
// request encrypted reply
|
||||||
|
if (DatabaseLookupMessage.supportsEncryptedReplies(ri)) {
|
||||||
|
MessageWrapper.OneTimeSession sess = MessageWrapper.generateSession(getContext());
|
||||||
|
dlm.setReplySession(sess.key, sess.tag);
|
||||||
|
}
|
||||||
outMsg = MessageWrapper.wrap(getContext(), dlm, ri);
|
outMsg = MessageWrapper.wrap(getContext(), dlm, ri);
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug(getJobId() + ": Encrypted DLM for " + _key + " to " + peer);
|
_log.debug(getJobId() + ": Encrypted DLM for " + _key + " to " + peer);
|
||||||
|
@ -17,14 +17,16 @@ import net.i2p.data.i2np.I2NPMessage;
|
|||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.message.GarlicMessageBuilder;
|
import net.i2p.router.message.GarlicMessageBuilder;
|
||||||
import net.i2p.router.message.PayloadGarlicConfig;
|
import net.i2p.router.message.PayloadGarlicConfig;
|
||||||
|
import net.i2p.router.util.RemovableSingletonSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method and class for garlic encrypting outbound netdb traffic,
|
* Method and class for garlic encrypting outbound netdb traffic,
|
||||||
* including management of the ElGamal/AES tags
|
* and sending keys and tags for others to encrypt inbound netdb traffic,
|
||||||
|
* including management of the ElGamal/AES tags.
|
||||||
*
|
*
|
||||||
* @since 0.7.10
|
* @since 0.7.10
|
||||||
*/
|
*/
|
||||||
class MessageWrapper {
|
public class MessageWrapper {
|
||||||
|
|
||||||
//private static final Log _log = RouterContext.getGlobalContext().logManager().getLog(MessageWrapper.class);
|
//private static final Log _log = RouterContext.getGlobalContext().logManager().getLog(MessageWrapper.class);
|
||||||
|
|
||||||
@ -142,4 +144,61 @@ class MessageWrapper {
|
|||||||
key, sentKey, null);
|
key, sentKey, null);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single key and tag, for receiving a single message.
|
||||||
|
*
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public static class OneTimeSession {
|
||||||
|
public final SessionKey key;
|
||||||
|
public final SessionTag tag;
|
||||||
|
|
||||||
|
public OneTimeSession(SessionKey key, SessionTag tag) {
|
||||||
|
this.key = key; this.tag = tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a single key and tag, for receiving a single encrypted message,
|
||||||
|
* and register it with the router's session key manager, to expire in two minutes.
|
||||||
|
* The recipient can then send us an AES-encrypted message,
|
||||||
|
* avoiding ElGamal.
|
||||||
|
*
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public static OneTimeSession generateSession(RouterContext ctx) {
|
||||||
|
SessionKey key = ctx.keyGenerator().generateSessionKey();
|
||||||
|
SessionTag tag = new SessionTag(true);
|
||||||
|
Set<SessionTag> tags = new RemovableSingletonSet(tag);
|
||||||
|
ctx.sessionKeyManager().tagsReceived(key, tags, 2*60*1000);
|
||||||
|
return new OneTimeSession(key, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Garlic wrap a message from nobody, destined for an unknown router,
|
||||||
|
* to hide the contents from the IBGW.
|
||||||
|
* Uses a supplied session key and session tag for AES encryption,
|
||||||
|
* avoiding ElGamal.
|
||||||
|
*
|
||||||
|
* @param encryptKey non-null
|
||||||
|
* @param encryptTag non-null
|
||||||
|
* @return null on encrypt failure
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public static GarlicMessage wrap(RouterContext ctx, I2NPMessage m, SessionKey encryptKey, SessionTag encryptTag) {
|
||||||
|
DeliveryInstructions instructions = new DeliveryInstructions();
|
||||||
|
instructions.setDeliveryMode(DeliveryInstructions.DELIVERY_MODE_LOCAL);
|
||||||
|
|
||||||
|
PayloadGarlicConfig payload = new PayloadGarlicConfig();
|
||||||
|
payload.setCertificate(Certificate.NULL_CERT);
|
||||||
|
payload.setId(ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE));
|
||||||
|
payload.setPayload(m);
|
||||||
|
payload.setDeliveryInstructions(instructions);
|
||||||
|
payload.setExpiration(m.getMessageExpiration());
|
||||||
|
|
||||||
|
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, null,
|
||||||
|
null, encryptKey, encryptTag);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ class StoreJob extends JobImpl {
|
|||||||
String v = ri.getOption("router.version");
|
String v = ri.getOption("router.version");
|
||||||
if (v == null)
|
if (v == null)
|
||||||
return false;
|
return false;
|
||||||
return (new VersionComparator()).compare(v, MIN_ENCRYPTION_VERSION) >= 0;
|
return VersionComparator.comp(v, MIN_ENCRYPTION_VERSION) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,7 +202,6 @@ abstract class BuildRequestor {
|
|||||||
private static final boolean SEND_VARIABLE = true;
|
private static final boolean SEND_VARIABLE = true;
|
||||||
/** 5 (~2600 bytes) fits nicely in 3 tunnel messages */
|
/** 5 (~2600 bytes) fits nicely in 3 tunnel messages */
|
||||||
private static final int SHORT_RECORDS = 5;
|
private static final int SHORT_RECORDS = 5;
|
||||||
private static final VersionComparator _versionComparator = new VersionComparator();
|
|
||||||
private static final List<Integer> SHORT_ORDER = new ArrayList(SHORT_RECORDS);
|
private static final List<Integer> SHORT_ORDER = new ArrayList(SHORT_RECORDS);
|
||||||
static {
|
static {
|
||||||
for (int i = 0; i < SHORT_RECORDS; i++)
|
for (int i = 0; i < SHORT_RECORDS; i++)
|
||||||
@ -217,7 +216,7 @@ abstract class BuildRequestor {
|
|||||||
String v = ri.getOption("router.version");
|
String v = ri.getOption("router.version");
|
||||||
if (v == null)
|
if (v == null)
|
||||||
return false;
|
return false;
|
||||||
return _versionComparator.compare(v, MIN_VARIABLE_VERSION) >= 0;
|
return VersionComparator.comp(v, MIN_VARIABLE_VERSION) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.i2p.router.tunnel.pool;
|
package net.i2p.router.tunnel.pool;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.i2p.crypto.SessionKeyManager;
|
import net.i2p.crypto.SessionKeyManager;
|
||||||
@ -19,6 +18,7 @@ import net.i2p.router.RouterContext;
|
|||||||
import net.i2p.router.TunnelInfo;
|
import net.i2p.router.TunnelInfo;
|
||||||
import net.i2p.router.message.GarlicMessageBuilder;
|
import net.i2p.router.message.GarlicMessageBuilder;
|
||||||
import net.i2p.router.message.PayloadGarlicConfig;
|
import net.i2p.router.message.PayloadGarlicConfig;
|
||||||
|
import net.i2p.router.util.RemovableSingletonSet;
|
||||||
import net.i2p.stat.Rate;
|
import net.i2p.stat.Rate;
|
||||||
import net.i2p.stat.RateStat;
|
import net.i2p.stat.RateStat;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
@ -140,9 +140,7 @@ class TestJob extends JobImpl {
|
|||||||
scheduleRetest();
|
scheduleRetest();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// can't be a singleton, the SKM modifies it
|
Set<SessionTag> encryptTags = new RemovableSingletonSet(encryptTag);
|
||||||
Set encryptTags = new HashSet(1);
|
|
||||||
encryptTags.add(encryptTag);
|
|
||||||
// Register the single tag with the appropriate SKM
|
// Register the single tag with the appropriate SKM
|
||||||
if (_cfg.isInbound() && !_pool.getSettings().isExploratory()) {
|
if (_cfg.isInbound() && !_pool.getSettings().isExploratory()) {
|
||||||
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_pool.getSettings().getDestination());
|
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_pool.getSettings().getDestination());
|
||||||
|
@ -212,7 +212,7 @@ public abstract class TunnelPeerSelector {
|
|||||||
if (caps != null)
|
if (caps != null)
|
||||||
peers.addAll(caps);
|
peers.addAll(caps);
|
||||||
}
|
}
|
||||||
if (filterSlow(ctx, isInbound, isExploratory)) {
|
if (filterSlow(isInbound, isExploratory)) {
|
||||||
// NOTE: filterSlow always returns true
|
// NOTE: filterSlow always returns true
|
||||||
Log log = ctx.logManager().getLog(TunnelPeerSelector.class);
|
Log log = ctx.logManager().getLog(TunnelPeerSelector.class);
|
||||||
char excl[] = getExcludeCaps(ctx);
|
char excl[] = getExcludeCaps(ctx);
|
||||||
@ -345,7 +345,6 @@ public abstract class TunnelPeerSelector {
|
|||||||
|
|
||||||
/** 0.7.8 and earlier had major message corruption bugs */
|
/** 0.7.8 and earlier had major message corruption bugs */
|
||||||
private static final String MIN_VERSION = "0.7.9";
|
private static final String MIN_VERSION = "0.7.9";
|
||||||
private static final VersionComparator _versionComparator = new VersionComparator();
|
|
||||||
|
|
||||||
private static boolean shouldExclude(RouterContext ctx, Log log, RouterInfo peer, char excl[]) {
|
private static boolean shouldExclude(RouterContext ctx, Log log, RouterInfo peer, char excl[]) {
|
||||||
String cap = peer.getCapabilities();
|
String cap = peer.getCapabilities();
|
||||||
@ -371,7 +370,7 @@ public abstract class TunnelPeerSelector {
|
|||||||
|
|
||||||
// minimum version check
|
// minimum version check
|
||||||
String v = peer.getOption("router.version");
|
String v = peer.getOption("router.version");
|
||||||
if (v == null || _versionComparator.compare(v, MIN_VERSION) < 0)
|
if (v == null || VersionComparator.comp(v, MIN_VERSION) < 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// uptime is always spoofed to 90m, so just remove all this
|
// uptime is always spoofed to 90m, so just remove all this
|
||||||
@ -435,34 +434,28 @@ public abstract class TunnelPeerSelector {
|
|||||||
private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.inboundExploratoryExcludeUnreachable";
|
private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.inboundExploratoryExcludeUnreachable";
|
||||||
private static final String PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.inboundClientExcludeUnreachable";
|
private static final String PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.inboundClientExcludeUnreachable";
|
||||||
|
|
||||||
private static final String DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "false";
|
private static final boolean DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false;
|
||||||
private static final String DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = "false";
|
private static final boolean DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = false;
|
||||||
// see comments at getExclude() above
|
// see comments at getExclude() above
|
||||||
private static final String DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "true";
|
private static final boolean DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = true;
|
||||||
private static final String DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "true";
|
private static final boolean DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* do we want to skip peers who haven't been up for long?
|
* do we want to skip peers who haven't been up for long?
|
||||||
* @return true for inbound, false for outbound, unless configured otherwise
|
* @return true for inbound, false for outbound, unless configured otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean filterUnreachable(boolean isInbound, boolean isExploratory) {
|
protected boolean filterUnreachable(boolean isInbound, boolean isExploratory) {
|
||||||
boolean def = false;
|
if (isExploratory) {
|
||||||
String val = null;
|
|
||||||
|
|
||||||
if (isExploratory)
|
|
||||||
if (isInbound)
|
if (isInbound)
|
||||||
val = ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE, DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE);
|
return ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE, DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE);
|
||||||
else
|
else
|
||||||
val = ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE, DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE);
|
return ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE, DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE);
|
||||||
else
|
} else {
|
||||||
if (isInbound)
|
if (isInbound)
|
||||||
val = ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE, DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE);
|
return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE, DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE);
|
||||||
else
|
else
|
||||||
val = ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE, DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE);
|
return ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE, DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE);
|
||||||
|
}
|
||||||
boolean rv = (val != null ? Boolean.parseBoolean(val) : def);
|
|
||||||
//System.err.println("Filter unreachable? " + rv + " (inbound? " + isInbound + ", exploratory? " + isExploratory);
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -475,56 +468,50 @@ public abstract class TunnelPeerSelector {
|
|||||||
* do we want to skip peers that are slow?
|
* do we want to skip peers that are slow?
|
||||||
* @return true unless configured otherwise
|
* @return true unless configured otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean filterSlow(RouterContext ctx, boolean isInbound, boolean isExploratory) {
|
protected boolean filterSlow(boolean isInbound, boolean isExploratory) {
|
||||||
boolean def = true;
|
if (isExploratory) {
|
||||||
String val = null;
|
|
||||||
|
|
||||||
if (isExploratory)
|
|
||||||
if (isInbound)
|
if (isInbound)
|
||||||
val = ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_SLOW);
|
return ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_SLOW, true);
|
||||||
else
|
else
|
||||||
val = ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_SLOW);
|
return ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_SLOW, true);
|
||||||
else
|
} else {
|
||||||
if (isInbound)
|
if (isInbound)
|
||||||
val = ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_SLOW);
|
return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_SLOW, true);
|
||||||
else
|
else
|
||||||
val = ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_SLOW);
|
return ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_SLOW, true);
|
||||||
|
}
|
||||||
boolean rv = (val != null ? Boolean.parseBoolean(val) : def);
|
|
||||||
//System.err.println("Filter unreachable? " + rv + " (inbound? " + isInbound + ", exploratory? " + isExploratory);
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****
|
||||||
private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UPTIME = "router.outboundExploratoryExcludeUptime";
|
private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UPTIME = "router.outboundExploratoryExcludeUptime";
|
||||||
private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME = "router.outboundClientExcludeUptime";
|
private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME = "router.outboundClientExcludeUptime";
|
||||||
private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UPTIME = "router.inboundExploratoryExcludeUptime";
|
private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UPTIME = "router.inboundExploratoryExcludeUptime";
|
||||||
private static final String PROP_INBOUND_CLIENT_EXCLUDE_UPTIME = "router.inboundClientExcludeUptime";
|
private static final String PROP_INBOUND_CLIENT_EXCLUDE_UPTIME = "router.inboundClientExcludeUptime";
|
||||||
|
****/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* do we want to skip peers who haven't been up for long?
|
* do we want to skip peers who haven't been up for long?
|
||||||
* @return true unless configured otherwise
|
* @return true unless configured otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean filterUptime(RouterContext ctx, boolean isInbound, boolean isExploratory) {
|
/****
|
||||||
boolean def = true;
|
protected boolean filterUptime(boolean isInbound, boolean isExploratory) {
|
||||||
String val = null;
|
if (isExploratory) {
|
||||||
|
|
||||||
if (isExploratory)
|
|
||||||
if (isInbound)
|
if (isInbound)
|
||||||
val = ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_UPTIME);
|
return ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_UPTIME, true);
|
||||||
else
|
else
|
||||||
val = ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UPTIME);
|
return ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UPTIME, true);
|
||||||
else
|
} else {
|
||||||
if (isInbound)
|
if (isInbound)
|
||||||
val = ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UPTIME);
|
return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UPTIME, true);
|
||||||
else
|
else
|
||||||
val = ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME);
|
return ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME, true);
|
||||||
|
}
|
||||||
boolean rv = (val != null ? Boolean.parseBoolean(val) : def);
|
|
||||||
//System.err.println("Filter unreachable? " + rv + " (inbound? " + isInbound + ", exploratory? " + isExploratory);
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
****/
|
||||||
|
|
||||||
|
/** see HashComparator */
|
||||||
protected void orderPeers(List rv, Hash hash) {
|
protected void orderPeers(List rv, Hash hash) {
|
||||||
|
if (rv.size() > 1)
|
||||||
Collections.sort(rv, new HashComparator(hash));
|
Collections.sort(rv, new HashComparator(hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,8 +1114,7 @@ public class TunnelPool {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
peers = new ArrayList(1);
|
peers = Collections.singletonList(_context.routerHash());
|
||||||
peers.add(_context.routerHash());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PooledTunnelCreatorConfig cfg = new PooledTunnelCreatorConfig(_context, peers.size(), settings.isInbound(), settings.getDestination());
|
PooledTunnelCreatorConfig cfg = new PooledTunnelCreatorConfig(_context, peers.size(), settings.isInbound(), settings.getDestination());
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
package net.i2p.router.util;
|
||||||
|
|
||||||
|
import java.util.AbstractSet;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like Collections.singleton() but item is removable,
|
||||||
|
* clear() is supported, and the iterator supports remove().
|
||||||
|
* Item may not be null. add() and addAll() unsupported.
|
||||||
|
* Unsynchronized.
|
||||||
|
*
|
||||||
|
* @since 0.9.7
|
||||||
|
*/
|
||||||
|
public class RemovableSingletonSet<E> extends AbstractSet<E> {
|
||||||
|
private E _elem;
|
||||||
|
|
||||||
|
public RemovableSingletonSet(E element) {
|
||||||
|
if (element == null)
|
||||||
|
throw new NullPointerException();
|
||||||
|
_elem = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
_elem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object o) {
|
||||||
|
return o != null && o.equals(_elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return _elem == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object o) {
|
||||||
|
boolean rv = o.equals(_elem);
|
||||||
|
if (rv)
|
||||||
|
_elem = null;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return _elem != null ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<E> iterator() {
|
||||||
|
return new RSSIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RSSIterator implements Iterator<E> {
|
||||||
|
boolean done;
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return _elem != null && !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
public E next() {
|
||||||
|
if (!hasNext())
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
done = true;
|
||||||
|
return _elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
if (_elem == null || !done)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
_elem = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user