forked from I2P_Developers/i2p.i2p
* DHSessionKeyBuilder:
- Move from core to router/transport - Make non-static, instantiate in TransportManager - Generate keypair in constructor and make final to move more processing to the precalc thread and eliminate races - Synchronize getSessionKey() to eliminate races - Comment out unused methods * UDPTransport: - Make key builder final in InboundEstablishState to eliminate rare NPE (ticket #406) - Remove unused static instance
This commit is contained in:
21
history.txt
21
history.txt
@@ -1,3 +1,22 @@
|
||||
2012-03-14 zzz
|
||||
* Blockfile, i2psnark: Remove static logs
|
||||
* DHSessionKeyBuilder:
|
||||
- Move from core to router/transport
|
||||
- Make non-static, instantiate in TransportManager
|
||||
- Generate keypair in constructor and make final
|
||||
to move more processing to the precalc thread
|
||||
and eliminate races
|
||||
- Synchronize getSessionKey() to eliminate races
|
||||
- Comment out unused methods
|
||||
* Jetty:
|
||||
- Set default cache-control for webapps and eepsite
|
||||
- Disable dir listing for console webapps
|
||||
* UDPTransport:
|
||||
- Make key builder final in InboundEstablishState to
|
||||
eliminate rare NPE (ticket #406)
|
||||
- Remove unused static instance
|
||||
* YKGenerator: Make non-static, instantiate in ElGamalEngine
|
||||
|
||||
2012-03-13 sponge
|
||||
* Add sponge.i2p :-D bump version.
|
||||
|
||||
@@ -9,7 +28,7 @@
|
||||
|
||||
2012-03-13 sponge
|
||||
* Plugins:
|
||||
- Handle 'file://' URLs for installation and updates.
|
||||
- Handle 'file://' URLs for installation and updates (ticket #429).
|
||||
You must specify the entire path, e.g.
|
||||
file:///home/someone/magicplugin.xpi2p
|
||||
- This works for updates too!
|
||||
|
@@ -30,7 +30,6 @@ import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
import net.i2p.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.data.Certificate;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
@@ -711,10 +710,8 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
|
||||
private void warmupCrypto() {
|
||||
_context.random().nextBoolean();
|
||||
// Use restart() to refire the static refiller threads, in case
|
||||
// we are restarting the router in the same JVM (Android)
|
||||
DHSessionKeyBuilder.restart();
|
||||
_context.elGamalEngine().restart();
|
||||
// Instantiate to fire up the YK refiller thread
|
||||
_context.elGamalEngine();
|
||||
}
|
||||
|
||||
private void startupQueue() {
|
||||
@@ -1091,15 +1088,12 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
|
||||
// shut down I2PAppContext tasks here
|
||||
|
||||
// If there are multiple routers in the JVM, we don't want to do this
|
||||
// to the DH or YK tasks, as they are singletons.
|
||||
if (contexts.isEmpty()) {
|
||||
try {
|
||||
DHSessionKeyBuilder.shutdown();
|
||||
} catch (Throwable t) { _log.log(Log.CRIT, "Error shutting DH", t); }
|
||||
try {
|
||||
_context.elGamalEngine().shutdown();
|
||||
} catch (Throwable t) { _log.log(Log.CRIT, "Error shutting elGamal", t); }
|
||||
|
||||
if (contexts.isEmpty()) {
|
||||
// any thing else to shut down?
|
||||
} else {
|
||||
_log.logAlways(Log.WARN, "Warning - " + contexts.size() + " routers remaining in this JVM, not releasing all resources");
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 13;
|
||||
public final static long BUILD = 14;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
@@ -56,9 +56,12 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
||||
startTimestamper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cannot be restarted.
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (_manager != null)
|
||||
_manager.stopListening();
|
||||
_manager.shutdown();
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
|
@@ -30,6 +30,7 @@ import net.i2p.data.i2np.I2NPMessage;
|
||||
import net.i2p.router.CommSystemFacade;
|
||||
import net.i2p.router.OutNetMessage;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.router.transport.ntcp.NTCPTransport;
|
||||
import net.i2p.router.transport.udp.UDPTransport;
|
||||
import net.i2p.util.Addresses;
|
||||
@@ -45,6 +46,7 @@ public class TransportManager implements TransportEventListener {
|
||||
private final Map<String, Transport> _transports;
|
||||
private final RouterContext _context;
|
||||
private final UPnPManager _upnpManager;
|
||||
private final DHSessionKeyBuilder.PrecalcRunner _dhThread;
|
||||
|
||||
/** default true */
|
||||
public final static String PROP_ENABLE_UDP = "i2np.udp.enable";
|
||||
@@ -67,6 +69,7 @@ public class TransportManager implements TransportEventListener {
|
||||
_upnpManager = new UPnPManager(context, this);
|
||||
else
|
||||
_upnpManager = null;
|
||||
_dhThread = new DHSessionKeyBuilder.PrecalcRunner(context);
|
||||
}
|
||||
|
||||
public void addTransport(Transport transport) {
|
||||
@@ -84,12 +87,12 @@ public class TransportManager implements TransportEventListener {
|
||||
private void configTransports() {
|
||||
boolean enableUDP = _context.getBooleanPropertyDefaultTrue(PROP_ENABLE_UDP);
|
||||
if (enableUDP) {
|
||||
UDPTransport udp = new UDPTransport(_context);
|
||||
UDPTransport udp = new UDPTransport(_context, _dhThread);
|
||||
addTransport(udp);
|
||||
initializeAddress(udp);
|
||||
}
|
||||
if (isNTCPEnabled(_context))
|
||||
addTransport(new NTCPTransport(_context));
|
||||
addTransport(new NTCPTransport(_context, _dhThread));
|
||||
if (_transports.isEmpty())
|
||||
_log.log(Log.CRIT, "No transports are enabled");
|
||||
}
|
||||
@@ -135,6 +138,7 @@ public class TransportManager implements TransportEventListener {
|
||||
}
|
||||
|
||||
public void startListening() {
|
||||
_dhThread.start();
|
||||
// For now, only start UPnP if we have no publicly-routable addresses
|
||||
// so we don't open the listener ports to the world.
|
||||
// Maybe we need a config option to force on? Probably not.
|
||||
@@ -161,6 +165,9 @@ public class TransportManager implements TransportEventListener {
|
||||
startListening();
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be restarted.
|
||||
*/
|
||||
public void stopListening() {
|
||||
if (_upnpManager != null)
|
||||
_upnpManager.stop();
|
||||
@@ -170,6 +177,16 @@ public class TransportManager implements TransportEventListener {
|
||||
_transports.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cannot be restarted.
|
||||
* @since 0.9
|
||||
*/
|
||||
public void shutdown() {
|
||||
stopListening();
|
||||
_dhThread.shutdown();
|
||||
}
|
||||
|
||||
public Transport getTransport(String style) {
|
||||
return _transports.get(style);
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package net.i2p.crypto;
|
||||
package net.i2p.router.transport.crypto;
|
||||
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
@@ -10,17 +10,19 @@ package net.i2p.crypto;
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
//import java.io.InputStream;
|
||||
//import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.crypto.CryptoConstants;
|
||||
import net.i2p.crypto.KeyGenerator;
|
||||
import net.i2p.crypto.SHA256Generator;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataHelper;
|
||||
//import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.NativeBigInteger;
|
||||
@@ -31,11 +33,10 @@ import net.i2p.util.RandomSource;
|
||||
* constants defined in CryptoConstants, which causes the exchange to create a
|
||||
* 256 bit session key.
|
||||
*
|
||||
* This class precalcs a set of values on its own thread, using those transparently
|
||||
* when a new instance is created. By default, the minimum threshold for creating
|
||||
* new values for the pool is 5, and the max pool size is 10. Whenever the pool has
|
||||
* This class precalcs a set of values on its own thread.
|
||||
* Whenever the pool has
|
||||
* less than the minimum, it fills it up again to the max. There is a delay after
|
||||
* each precalculation so that the CPU isn't hosed during startup (defaulting to 1 second).
|
||||
* each precalculation so that the CPU isn't hosed during startup.
|
||||
* These three parameters are controlled by java environmental variables and
|
||||
* can be adjusted via:
|
||||
* -Dcrypto.dh.precalc.min=40 -Dcrypto.dh.precalc.max=100 -Dcrypto.dh.precalc.delay=60000
|
||||
@@ -44,135 +45,54 @@ import net.i2p.util.RandomSource;
|
||||
*
|
||||
* To disable precalculation, set min to 0
|
||||
*
|
||||
* @since 0.9 moved from net.i2p.crypto
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
public class DHSessionKeyBuilder {
|
||||
private static I2PAppContext _context = I2PAppContext.getGlobalContext();
|
||||
private static Log _log;
|
||||
private static final int MIN_NUM_BUILDERS;
|
||||
private static final int MAX_NUM_BUILDERS;
|
||||
private static final int CALC_DELAY;
|
||||
private static final LinkedBlockingQueue<DHSessionKeyBuilder> _builders;
|
||||
private static Thread _precalcThread;
|
||||
private static volatile boolean _isRunning;
|
||||
|
||||
// the data of importance
|
||||
private BigInteger _myPrivateValue;
|
||||
private BigInteger _myPublicValue;
|
||||
private final BigInteger _myPrivateValue;
|
||||
private final BigInteger _myPublicValue;
|
||||
private BigInteger _peerValue;
|
||||
private SessionKey _sessionKey;
|
||||
private ByteArray _extraExchangedBytes; // bytes after the session key from the DH exchange
|
||||
private final ByteArray _extraExchangedBytes; // bytes after the session key from the DH exchange
|
||||
|
||||
public final static String PROP_DH_PRECALC_MIN = "crypto.dh.precalc.min";
|
||||
public final static String PROP_DH_PRECALC_MAX = "crypto.dh.precalc.max";
|
||||
public final static String PROP_DH_PRECALC_DELAY = "crypto.dh.precalc.delay";
|
||||
public final static int DEFAULT_DH_PRECALC_MIN = 15;
|
||||
public final static int DEFAULT_DH_PRECALC_MAX = 40;
|
||||
public final static int DEFAULT_DH_PRECALC_DELAY = 200;
|
||||
private final static String PROP_DH_PRECALC_MIN = "crypto.dh.precalc.min";
|
||||
private final static String PROP_DH_PRECALC_MAX = "crypto.dh.precalc.max";
|
||||
private final static String PROP_DH_PRECALC_DELAY = "crypto.dh.precalc.delay";
|
||||
private final static int DEFAULT_DH_PRECALC_MIN = 15;
|
||||
private final static int DEFAULT_DH_PRECALC_MAX = 40;
|
||||
private final static int DEFAULT_DH_PRECALC_DELAY = 200;
|
||||
|
||||
static {
|
||||
I2PAppContext ctx = _context;
|
||||
_log = ctx.logManager().getLog(DHSessionKeyBuilder.class);
|
||||
ctx.statManager().createRateStat("crypto.dhGeneratePublicTime", "How long it takes to create x and X", "Encryption", new long[] { 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.dhCalculateSessionTime", "How long it takes to create the session key", "Encryption", new long[] { 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.DHUsed", "Need a DH from the queue", "Encryption", new long[] { 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.DHEmpty", "DH queue empty", "Encryption", new long[] { 60*60*1000 });
|
||||
|
||||
// add to the defaults for every 128MB of RAM, up to 512MB
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
if (maxMemory == Long.MAX_VALUE)
|
||||
maxMemory = 127*1024*1024l;
|
||||
int factor = (int) Math.max(1l, Math.min(4l, 1 + (maxMemory / (128*1024*1024l))));
|
||||
int defaultMin = DEFAULT_DH_PRECALC_MIN * factor;
|
||||
int defaultMax = DEFAULT_DH_PRECALC_MAX * factor;
|
||||
MIN_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MIN, defaultMin);
|
||||
MAX_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MAX, defaultMax);
|
||||
|
||||
CALC_DELAY = ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY);
|
||||
_builders = new LinkedBlockingQueue(MAX_NUM_BUILDERS);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("DH Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
|
||||
+ CALC_DELAY + ")");
|
||||
startPrecalc();
|
||||
/**
|
||||
* Create a new public/private value pair for the DH exchange.
|
||||
* Only for internal use and unit tests.
|
||||
* Others should get instances from PrecalcRunner.getBuilder()
|
||||
*/
|
||||
DHSessionKeyBuilder() {
|
||||
this(RandomSource.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Caller must synch on class
|
||||
* @since 0.8.8
|
||||
* Create a new public/private value pair for the DH exchange.
|
||||
* Only for internal use and unit tests.
|
||||
* Others should get instances from PrecalcRunner.getBuilder()
|
||||
*/
|
||||
private static void startPrecalc() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(DHSessionKeyBuilder.class);
|
||||
_precalcThread = new I2PThread(new DHSessionKeyBuilderPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS),
|
||||
"DH Precalc", true);
|
||||
_precalcThread.setPriority(Thread.MIN_PRIORITY);
|
||||
_isRunning = true;
|
||||
_precalcThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that this stops the singleton precalc thread.
|
||||
* You don't want to do this if there are multiple routers in the JVM.
|
||||
* Fix this if you care. See Router.shutdown().
|
||||
* @since 0.8.8
|
||||
*/
|
||||
public static void shutdown() {
|
||||
_isRunning = false;
|
||||
_precalcThread.interrupt();
|
||||
_builders.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only required if shutdown() previously called.
|
||||
* @since 0.8.8
|
||||
*/
|
||||
public static void restart() {
|
||||
synchronized(DHSessionKeyBuilder.class) {
|
||||
if (!_isRunning)
|
||||
startPrecalc();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new DH key builder
|
||||
* or pulls a prebuilt one from the queue.
|
||||
*/
|
||||
public DHSessionKeyBuilder() {
|
||||
_context.statManager().addRateData("crypto.DHUsed", 1, 0);
|
||||
DHSessionKeyBuilder builder = _builders.poll();
|
||||
if (builder != null) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Removing a builder. # left = " + _builders.size());
|
||||
_myPrivateValue = builder._myPrivateValue;
|
||||
_myPublicValue = builder._myPublicValue;
|
||||
// these two are still null after precalc
|
||||
//_peerValue = builder._peerValue;
|
||||
//_sessionKey = builder._sessionKey;
|
||||
_extraExchangedBytes = builder._extraExchangedBytes;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("No more builders, creating one now");
|
||||
_context.statManager().addRateData("crypto.DHEmpty", 1, 0);
|
||||
// sets _myPrivateValue as a side effect
|
||||
_myPublicValue = generateMyValue();
|
||||
_extraExchangedBytes = new ByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only for internal use
|
||||
* @parameter usePool unused, just to make it different from other constructor
|
||||
*/
|
||||
private DHSessionKeyBuilder(boolean usePool) {
|
||||
DHSessionKeyBuilder(RandomSource random) {
|
||||
_myPrivateValue = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, random);
|
||||
_myPublicValue = CryptoConstants.elgg.modPow(_myPrivateValue, CryptoConstants.elgp);
|
||||
_extraExchangedBytes = new ByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Conduct a DH exchange over the streams, returning the resulting data.
|
||||
*
|
||||
* @deprecated unused
|
||||
* unused
|
||||
* @return exchanged data
|
||||
* @throws IOException if there is an error (but does not close the streams
|
||||
*/
|
||||
/****
|
||||
public static DHSessionKeyBuilder exchangeKeys(InputStream in, OutputStream out) throws IOException {
|
||||
DHSessionKeyBuilder builder = new DHSessionKeyBuilder();
|
||||
|
||||
@@ -191,10 +111,12 @@ public class DHSessionKeyBuilder {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
****/
|
||||
|
||||
/**
|
||||
* @deprecated unused
|
||||
* unused
|
||||
*/
|
||||
/****
|
||||
private static BigInteger readBigI(InputStream in) throws IOException {
|
||||
byte Y[] = new byte[256];
|
||||
int read = DataHelper.read(in, Y);
|
||||
@@ -211,14 +133,16 @@ public class DHSessionKeyBuilder {
|
||||
}
|
||||
return new NativeBigInteger(1, Y);
|
||||
}
|
||||
****/
|
||||
|
||||
/**
|
||||
* Write out the integer as a 256 byte value. This left pads with 0s so
|
||||
* to keep in 2s complement, and if it is already 257 bytes (due to
|
||||
* the sign bit) ignore that first byte.
|
||||
*
|
||||
* @deprecated unused
|
||||
* unused
|
||||
*/
|
||||
/****
|
||||
private static void writeBigI(OutputStream out, BigInteger val) throws IOException {
|
||||
byte x[] = val.toByteArray();
|
||||
for (int i = x.length; i < 256; i++)
|
||||
@@ -232,50 +156,22 @@ public class DHSessionKeyBuilder {
|
||||
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private static final int getSize() {
|
||||
return _builders.size();
|
||||
}
|
||||
|
||||
/** @return true if successful, false if full */
|
||||
private static final boolean addBuilder(DHSessionKeyBuilder builder) {
|
||||
return _builders.offer(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new private value for the DH exchange, and return the number to
|
||||
* be exchanged, leaving the actual private value accessible through getMyPrivateValue()
|
||||
*
|
||||
*/
|
||||
public BigInteger generateMyValue() {
|
||||
long start = System.currentTimeMillis();
|
||||
_myPrivateValue = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, _context.random());
|
||||
BigInteger myValue = CryptoConstants.elgg.modPow(_myPrivateValue, CryptoConstants.elgp);
|
||||
long end = System.currentTimeMillis();
|
||||
long diff = end - start;
|
||||
_context.statManager().addRateData("crypto.dhGeneratePublicTime", diff, diff);
|
||||
if (diff > 1000) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Took more than a second (" + diff + "ms) to generate local DH value");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Took " + diff + "ms to generate local DH value");
|
||||
}
|
||||
return myValue;
|
||||
}
|
||||
****/
|
||||
|
||||
/**
|
||||
* Retrieve the private value used by the local participant in the DH exchange
|
||||
* unused
|
||||
*/
|
||||
/*
|
||||
public BigInteger getMyPrivateValue() {
|
||||
return _myPrivateValue;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieve the public value used by the local participant in the DH exchange,
|
||||
* generating it if necessary
|
||||
*/
|
||||
public BigInteger getMyPublicValue() {
|
||||
if (_myPublicValue == null) _myPublicValue = generateMyValue();
|
||||
return _myPublicValue;
|
||||
}
|
||||
|
||||
@@ -309,14 +205,17 @@ public class DHSessionKeyBuilder {
|
||||
_peerValue = peerVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param val 256 bytes
|
||||
*/
|
||||
public void setPeerPublicValue(byte val[]) throws InvalidPublicParameterException {
|
||||
if (val.length != 256)
|
||||
throw new IllegalArgumentException("Peer public value must be exactly 256 bytes");
|
||||
|
||||
if (1 == (val[0] & 0x80)) {
|
||||
// high bit set, need to inject an additional byte to keep 2s complement
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("High bit set");
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("High bit set");
|
||||
byte val2[] = new byte[257];
|
||||
System.arraycopy(val, 0, val2, 1, 256);
|
||||
val = val2;
|
||||
@@ -329,6 +228,11 @@ public class DHSessionKeyBuilder {
|
||||
return _peerValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a 256 byte representation of his public key, with leading 0s
|
||||
* if necessary.
|
||||
*
|
||||
*/
|
||||
public byte[] getPeerPublicValueBytes() {
|
||||
return toByteArray(getPeerPublicValue());
|
||||
}
|
||||
@@ -338,10 +242,9 @@ public class DHSessionKeyBuilder {
|
||||
*
|
||||
* @return session key exchanged, or null if the exchange is not complete
|
||||
*/
|
||||
public SessionKey getSessionKey() {
|
||||
public synchronized SessionKey getSessionKey() {
|
||||
if (_sessionKey != null) return _sessionKey;
|
||||
if (_peerValue != null) {
|
||||
if (_myPrivateValue == null) generateMyValue();
|
||||
_sessionKey = calculateSessionKey(_myPrivateValue, _peerValue);
|
||||
} else {
|
||||
//System.err.println("Not ready yet.. privateValue and peerValue must be set ("
|
||||
@@ -367,7 +270,7 @@ public class DHSessionKeyBuilder {
|
||||
*
|
||||
*/
|
||||
private final SessionKey calculateSessionKey(BigInteger myPrivateValue, BigInteger publicPeerValue) {
|
||||
long start = System.currentTimeMillis();
|
||||
//long start = System.currentTimeMillis();
|
||||
SessionKey key = new SessionKey();
|
||||
BigInteger exchangedKey = publicPeerValue.modPow(myPrivateValue, CryptoConstants.elgp);
|
||||
byte buf[] = exchangedKey.toByteArray();
|
||||
@@ -376,28 +279,28 @@ public class DHSessionKeyBuilder {
|
||||
System.arraycopy(buf, 0, val, 0, buf.length);
|
||||
byte remaining[] = SHA256Generator.getInstance().calculateHash(val).getData();
|
||||
_extraExchangedBytes.setData(remaining);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Storing " + remaining.length + " bytes from the DH exchange by SHA256 the session key");
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Storing " + remaining.length + " bytes from the DH exchange by SHA256 the session key");
|
||||
} else { // (buf.length >= val.length)
|
||||
System.arraycopy(buf, 0, val, 0, val.length);
|
||||
// feed the extra bytes into the PRNG
|
||||
_context.random().harvester().feedEntropy("DH", buf, val.length, buf.length-val.length);
|
||||
RandomSource.getInstance().harvester().feedEntropy("DH", buf, val.length, buf.length-val.length);
|
||||
byte remaining[] = new byte[buf.length - val.length];
|
||||
System.arraycopy(buf, val.length, remaining, 0, remaining.length);
|
||||
_extraExchangedBytes.setData(remaining);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Storing " + remaining.length + " bytes from the end of the DH exchange");
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Storing " + remaining.length + " bytes from the end of the DH exchange");
|
||||
}
|
||||
key.setData(val);
|
||||
long end = System.currentTimeMillis();
|
||||
long diff = end - start;
|
||||
//long end = System.currentTimeMillis();
|
||||
//long diff = end - start;
|
||||
|
||||
_context.statManager().addRateData("crypto.dhCalculateSessionTime", diff, diff);
|
||||
if (diff > 1000) {
|
||||
if (_log.shouldLog(Log.WARN)) _log.warn("Generating session key took too long (" + diff + " ms");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Generating session key " + diff + " ms");
|
||||
}
|
||||
//_context.statManager().addRateData("crypto.dhCalculateSessionTime", diff, diff);
|
||||
//if (diff > 1000) {
|
||||
// if (_log.shouldLog(Log.WARN)) _log.warn("Generating session key took too long (" + diff + " ms");
|
||||
//} else {
|
||||
// if (_log.shouldLog(Log.DEBUG)) _log.debug("Generating session key " + diff + " ms");
|
||||
//}
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -504,19 +407,70 @@ public class DHSessionKeyBuilder {
|
||||
}
|
||||
******/
|
||||
|
||||
private static class DHSessionKeyBuilderPrecalcRunner implements Runnable {
|
||||
/**
|
||||
* @since 0.9
|
||||
*/
|
||||
public interface Factory {
|
||||
/**
|
||||
* Construct a new DH key builder
|
||||
* or pulls a prebuilt one from the queue.
|
||||
*/
|
||||
public DHSessionKeyBuilder getBuilder();
|
||||
}
|
||||
|
||||
public static class PrecalcRunner extends I2PThread implements Factory {
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private final int _minSize;
|
||||
private final int _maxSize;
|
||||
private final int _calcDelay;
|
||||
private final LinkedBlockingQueue<DHSessionKeyBuilder> _builders;
|
||||
private volatile boolean _isRunning;
|
||||
|
||||
/** check every 30 seconds whether we have less than the minimum */
|
||||
private long _checkDelay = 30 * 1000;
|
||||
|
||||
private DHSessionKeyBuilderPrecalcRunner(int minSize, int maxSize) {
|
||||
_minSize = minSize;
|
||||
_maxSize = maxSize;
|
||||
public PrecalcRunner(I2PAppContext ctx) {
|
||||
super("DH Precalc");
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(DHSessionKeyBuilder.class);
|
||||
ctx.statManager().createRateStat("crypto.dhGeneratePublicTime", "How long it takes to create x and X", "Encryption", new long[] { 60*60*1000 });
|
||||
//ctx.statManager().createRateStat("crypto.dhCalculateSessionTime", "How long it takes to create the session key", "Encryption", new long[] { 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.DHUsed", "Need a DH from the queue", "Encryption", new long[] { 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.DHEmpty", "DH queue empty", "Encryption", new long[] { 60*60*1000 });
|
||||
|
||||
// add to the defaults for every 128MB of RAM, up to 512MB
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
if (maxMemory == Long.MAX_VALUE)
|
||||
maxMemory = 127*1024*1024l;
|
||||
int factor = (int) Math.max(1l, Math.min(4l, 1 + (maxMemory / (128*1024*1024l))));
|
||||
int defaultMin = DEFAULT_DH_PRECALC_MIN * factor;
|
||||
int defaultMax = DEFAULT_DH_PRECALC_MAX * factor;
|
||||
_minSize = ctx.getProperty(PROP_DH_PRECALC_MIN, defaultMin);
|
||||
_maxSize = ctx.getProperty(PROP_DH_PRECALC_MAX, defaultMax);
|
||||
_calcDelay = ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("DH Precalc (minimum: " + _minSize + " max: " + _maxSize + ", delay: "
|
||||
+ _calcDelay + ")");
|
||||
_builders = new LinkedBlockingQueue(_maxSize);
|
||||
setPriority(Thread.MIN_PRIORITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that this stops the singleton precalc thread.
|
||||
* You don't want to do this if there are multiple routers in the JVM.
|
||||
* Fix this if you care. See Router.shutdown().
|
||||
* @since 0.8.8
|
||||
*/
|
||||
public void shutdown() {
|
||||
_isRunning = false;
|
||||
this.interrupt();
|
||||
_builders.clear();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
while (_isRunning) {
|
||||
//long start = System.currentTimeMillis();
|
||||
int startSize = getSize();
|
||||
@@ -535,7 +489,7 @@ public class DHSessionKeyBuilder {
|
||||
long curCalc = System.currentTimeMillis() - curStart;
|
||||
// for some relief...
|
||||
try {
|
||||
Thread.sleep(CALC_DELAY + (curCalc * 3));
|
||||
Thread.sleep(_calcDelay + (curCalc * 3));
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
}
|
||||
@@ -557,11 +511,47 @@ public class DHSessionKeyBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private static DHSessionKeyBuilder precalc() {
|
||||
DHSessionKeyBuilder builder = new DHSessionKeyBuilder(false);
|
||||
builder.getMyPublicValue();
|
||||
/**
|
||||
* Construct a new DH key builder
|
||||
* or pulls a prebuilt one from the queue.
|
||||
*
|
||||
* @since 0.9 moved from DHSKB
|
||||
*/
|
||||
public DHSessionKeyBuilder getBuilder() {
|
||||
_context.statManager().addRateData("crypto.DHUsed", 1, 0);
|
||||
DHSessionKeyBuilder builder = _builders.poll();
|
||||
if (builder == null) {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("No more builders, creating one now");
|
||||
_context.statManager().addRateData("crypto.DHEmpty", 1, 0);
|
||||
builder = precalc();
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private DHSessionKeyBuilder precalc() {
|
||||
long start = System.currentTimeMillis();
|
||||
DHSessionKeyBuilder builder = new DHSessionKeyBuilder(_context.random());
|
||||
long end = System.currentTimeMillis();
|
||||
long diff = end - start;
|
||||
_context.statManager().addRateData("crypto.dhGeneratePublicTime", diff, diff);
|
||||
if (diff > 1000) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Took more than a second (" + diff + "ms) to generate local DH value");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Took " + diff + "ms to generate local DH value");
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
/** @return true if successful, false if full */
|
||||
private final boolean addBuilder(DHSessionKeyBuilder builder) {
|
||||
return _builders.offer(builder);
|
||||
}
|
||||
|
||||
private final int getSize() {
|
||||
return _builders.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class InvalidPublicParameterException extends I2PException {
|
@@ -12,7 +12,6 @@ import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.Certificate;
|
||||
import net.i2p.data.DataFormatException;
|
||||
@@ -27,6 +26,7 @@ import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.SigningPublicKey;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -70,12 +70,12 @@ import net.i2p.util.Log;
|
||||
*
|
||||
*/
|
||||
class EstablishState {
|
||||
private RouterContext _context;
|
||||
private Log _log;
|
||||
private final RouterContext _context;
|
||||
private final Log _log;
|
||||
|
||||
// bob receives (and alice sends)
|
||||
private byte _X[];
|
||||
private byte _hX_xor_bobIdentHash[];
|
||||
private final byte _X[];
|
||||
private final byte _hX_xor_bobIdentHash[];
|
||||
private int _aliceIdentSize;
|
||||
/** contains the decrypted aliceIndexSize + aliceIdent + tsA + padding + aliceSig */
|
||||
private ByteArrayOutputStream _sz_aliceIdent_tsA_padding_aliceSig;
|
||||
@@ -100,7 +100,7 @@ class EstablishState {
|
||||
*/
|
||||
private int _curEncryptedOffset;
|
||||
/** decryption buffer */
|
||||
private byte _curDecrypted[];
|
||||
private final byte _curDecrypted[];
|
||||
|
||||
/** bytes received so far */
|
||||
private int _received;
|
||||
@@ -109,10 +109,10 @@ class EstablishState {
|
||||
|
||||
private byte _extra[];
|
||||
|
||||
private DHSessionKeyBuilder _dh;
|
||||
private final DHSessionKeyBuilder _dh;
|
||||
|
||||
private NTCPTransport _transport;
|
||||
private NTCPConnection _con;
|
||||
private final NTCPTransport _transport;
|
||||
private final NTCPConnection _con;
|
||||
private boolean _corrupt;
|
||||
/** error causing the corruption */
|
||||
private String _err;
|
||||
@@ -127,15 +127,14 @@ class EstablishState {
|
||||
_log = ctx.logManager().getLog(getClass());
|
||||
_transport = transport;
|
||||
_con = con;
|
||||
_dh = new DHSessionKeyBuilder();
|
||||
_dh = _transport.getDHBuilder();
|
||||
_hX_xor_bobIdentHash = new byte[Hash.HASH_LENGTH];
|
||||
if (_con.isInbound()) {
|
||||
_X = new byte[256];
|
||||
_hX_xor_bobIdentHash = new byte[Hash.HASH_LENGTH];
|
||||
_sz_aliceIdent_tsA_padding_aliceSig = new ByteArrayOutputStream(512);
|
||||
} else {
|
||||
_X = _dh.getMyPublicValueBytes();
|
||||
_Y = new byte[256];
|
||||
_hX_xor_bobIdentHash = new byte[Hash.HASH_LENGTH];
|
||||
byte hx[] = ctx.sha().calculateHash(_X).getData();
|
||||
DataHelper.xor(hx, 0, con.getRemotePeer().calculateHash().getData(), 0, _hX_xor_bobIdentHash, 0, hx.length);
|
||||
}
|
||||
|
@@ -31,13 +31,14 @@ import net.i2p.router.transport.CommSystemFacadeImpl;
|
||||
import net.i2p.router.transport.Transport;
|
||||
import net.i2p.router.transport.TransportBid;
|
||||
import net.i2p.router.transport.TransportImpl;
|
||||
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.Translate;
|
||||
|
||||
/**
|
||||
*
|
||||
* The NIO TCP transport
|
||||
*/
|
||||
public class NTCPTransport extends TransportImpl {
|
||||
private final Log _log;
|
||||
@@ -64,6 +65,7 @@ public class NTCPTransport extends TransportImpl {
|
||||
public static final String PROP_BIND_INTERFACE = "i2np.ntcp.bindInterface";
|
||||
|
||||
private final NTCPSendFinisher _finisher;
|
||||
private final DHSessionKeyBuilder.Factory _dhFactory;
|
||||
private long _lastBadSkew;
|
||||
private static final long[] RATES = { 10*60*1000 };
|
||||
|
||||
@@ -71,9 +73,9 @@ public class NTCPTransport extends TransportImpl {
|
||||
//private static final String THINSP = " / ";
|
||||
private static final String THINSP = " / ";
|
||||
|
||||
public NTCPTransport(RouterContext ctx) {
|
||||
public NTCPTransport(RouterContext ctx, DHSessionKeyBuilder.Factory dh) {
|
||||
super(ctx);
|
||||
|
||||
_dhFactory = dh;
|
||||
_log = ctx.logManager().getLog(getClass());
|
||||
|
||||
_context.statManager().createRateStat("ntcp.sendTime", "Total message lifetime when sent completely", "ntcp", RATES);
|
||||
@@ -585,6 +587,13 @@ public class NTCPTransport extends TransportImpl {
|
||||
public String getStyle() { return STYLE; }
|
||||
EventPumper getPumper() { return _pumper; }
|
||||
|
||||
/**
|
||||
* @since 0.9
|
||||
*/
|
||||
DHSessionKeyBuilder getDHBuilder() {
|
||||
return _dhFactory.getBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* how long from initial connection attempt (accept() or connect()) until
|
||||
* the con must be established to avoid premature close()ing
|
||||
|
@@ -9,7 +9,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.RouterAddress;
|
||||
@@ -22,6 +21,7 @@ import net.i2p.router.OutNetMessage;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
|
||||
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
@@ -212,7 +212,7 @@ class EstablishmentManager {
|
||||
}
|
||||
state = new OutboundEstablishState(_context, remAddr, port,
|
||||
msg.getTarget().getIdentity(),
|
||||
sessionKey, addr);
|
||||
sessionKey, addr, _transport.getDHBuilder());
|
||||
OutboundEstablishState oldState = _outboundStates.putIfAbsent(to, state);
|
||||
boolean isNew = oldState == null;
|
||||
if (!isNew)
|
||||
@@ -303,7 +303,8 @@ class EstablishmentManager {
|
||||
}
|
||||
if (!_transport.allowConnection())
|
||||
return; // drop the packet
|
||||
state = new InboundEstablishState(_context, from.getIP(), from.getPort(), _transport.getLocalPort());
|
||||
state = new InboundEstablishState(_context, from.getIP(), from.getPort(), _transport.getLocalPort(),
|
||||
_transport.getDHBuilder());
|
||||
state.receiveSessionRequest(reader.getSessionRequestReader());
|
||||
InboundEstablishState oldState = _inboundStates.putIfAbsent(from, state);
|
||||
isNew = oldState == null;
|
||||
|
@@ -3,7 +3,6 @@ package net.i2p.router.transport.udp;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.i2p.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataFormatException;
|
||||
@@ -12,6 +11,7 @@ import net.i2p.data.RouterIdentity;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -29,8 +29,7 @@ class InboundEstablishState {
|
||||
private byte _receivedX[];
|
||||
private byte _bobIP[];
|
||||
private final int _bobPort;
|
||||
// try to fix NPE in getSentY() ?????
|
||||
private volatile DHSessionKeyBuilder _keyBuilder;
|
||||
private final DHSessionKeyBuilder _keyBuilder;
|
||||
// SessionCreated message
|
||||
private byte _sentY[];
|
||||
private final byte _aliceIP[];
|
||||
@@ -68,7 +67,8 @@ class InboundEstablishState {
|
||||
/** we are explicitly failing it */
|
||||
public static final int STATE_FAILED = 5;
|
||||
|
||||
public InboundEstablishState(RouterContext ctx, byte remoteIP[], int remotePort, int localPort) {
|
||||
public InboundEstablishState(RouterContext ctx, byte remoteIP[], int remotePort, int localPort,
|
||||
DHSessionKeyBuilder dh) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(InboundEstablishState.class);
|
||||
_aliceIP = remoteIP;
|
||||
@@ -77,6 +77,7 @@ class InboundEstablishState {
|
||||
_bobPort = localPort;
|
||||
_currentState = STATE_UNKNOWN;
|
||||
_establishBegin = ctx.clock().now();
|
||||
_keyBuilder = dh;
|
||||
}
|
||||
|
||||
public synchronized int getState() { return _currentState; }
|
||||
@@ -106,7 +107,6 @@ class InboundEstablishState {
|
||||
|
||||
public synchronized void generateSessionKey() throws DHSessionKeyBuilder.InvalidPublicParameterException {
|
||||
if (_sessionKey != null) return;
|
||||
_keyBuilder = new DHSessionKeyBuilder();
|
||||
_keyBuilder.setPeerPublicValue(_receivedX);
|
||||
_sessionKey = _keyBuilder.getSessionKey();
|
||||
ByteArray extra = _keyBuilder.getExtraBytes();
|
||||
@@ -130,7 +130,6 @@ class InboundEstablishState {
|
||||
|
||||
public synchronized byte[] getSentY() {
|
||||
if (_sentY == null)
|
||||
// Rare NPE seen here...
|
||||
_sentY = _keyBuilder.getMyPublicValueBytes();
|
||||
return _sentY;
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@ import java.net.InetAddress;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import net.i2p.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataHelper;
|
||||
@@ -13,6 +12,7 @@ import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.router.OutNetMessage;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -26,10 +26,10 @@ class OutboundEstablishState {
|
||||
private final RouterContext _context;
|
||||
private final Log _log;
|
||||
// SessionRequest message
|
||||
private byte _sentX[];
|
||||
private final byte _sentX[];
|
||||
private byte _bobIP[];
|
||||
private int _bobPort;
|
||||
private DHSessionKeyBuilder _keyBuilder;
|
||||
private final DHSessionKeyBuilder _keyBuilder;
|
||||
// SessionCreated message
|
||||
private byte _receivedY[];
|
||||
private byte _aliceIP[];
|
||||
@@ -73,7 +73,8 @@ class OutboundEstablishState {
|
||||
public static final int STATE_PENDING_INTRO = 5;
|
||||
|
||||
public OutboundEstablishState(RouterContext ctx, InetAddress remoteHost, int remotePort,
|
||||
RouterIdentity remotePeer, SessionKey introKey, UDPAddress addr) {
|
||||
RouterIdentity remotePeer, SessionKey introKey, UDPAddress addr,
|
||||
DHSessionKeyBuilder dh) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(OutboundEstablishState.class);
|
||||
if ( (remoteHost != null) && (remotePort > 0) ) {
|
||||
@@ -92,6 +93,8 @@ class OutboundEstablishState {
|
||||
_establishBegin = ctx.clock().now();
|
||||
_remoteAddress = addr;
|
||||
_introductionNonce = -1;
|
||||
_keyBuilder = dh;
|
||||
_sentX = new byte[UDPPacketReader.SessionRequestReader.X_LENGTH];
|
||||
prepareSessionRequest();
|
||||
if ( (addr != null) && (addr.getIntroducerCount() > 0) ) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -128,10 +131,7 @@ class OutboundEstablishState {
|
||||
|
||||
/** called from constructor, no need to synch */
|
||||
private void prepareSessionRequest() {
|
||||
_keyBuilder = new DHSessionKeyBuilder();
|
||||
byte X[] = _keyBuilder.getMyPublicValue().toByteArray();
|
||||
if (_sentX == null)
|
||||
_sentX = new byte[UDPPacketReader.SessionRequestReader.X_LENGTH];
|
||||
if (X.length == 257)
|
||||
System.arraycopy(X, 1, _sentX, 0, _sentX.length);
|
||||
else if (X.length == 256)
|
||||
|
@@ -34,6 +34,7 @@ import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.transport.Transport;
|
||||
import net.i2p.router.transport.TransportBid;
|
||||
import net.i2p.router.transport.TransportImpl;
|
||||
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
||||
import net.i2p.router.util.RandomIterator;
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
@@ -43,7 +44,7 @@ import net.i2p.util.SimpleTimer;
|
||||
import net.i2p.util.Translate;
|
||||
|
||||
/**
|
||||
*
|
||||
* The SSU transport
|
||||
*/
|
||||
public class UDPTransport extends TransportImpl implements TimedWeightedPriorityMessageQueue.FailedListener {
|
||||
private final Log _log;
|
||||
@@ -70,6 +71,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
private long _reachabilityStatusLastUpdated;
|
||||
private long _introducersSelectedOn;
|
||||
private long _lastInboundReceivedOn;
|
||||
private final DHSessionKeyBuilder.Factory _dhFactory;
|
||||
|
||||
/** do we need to rebuild our external router address asap? */
|
||||
private boolean _needsRebuild;
|
||||
@@ -178,8 +180,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
//private static final String THINSP = " / ";
|
||||
private static final String THINSP = " / ";
|
||||
|
||||
public UDPTransport(RouterContext ctx) {
|
||||
public UDPTransport(RouterContext ctx, DHSessionKeyBuilder.Factory dh) {
|
||||
super(ctx);
|
||||
_dhFactory = dh;
|
||||
_log = ctx.logManager().getLog(UDPTransport.class);
|
||||
_peersByIdent = new ConcurrentHashMap(128);
|
||||
_peersByRemoteHost = new ConcurrentHashMap(128);
|
||||
@@ -227,7 +230,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_context.statManager().createRateStat("udp.proactiveReestablish", "How long a session was idle for when we proactively reestablished it", "udp", RATES);
|
||||
_context.statManager().createRateStat("udp.dropPeerDroplist", "How many peers currently have their packets dropped outright when a new peer is added to the list?", "udp", RATES);
|
||||
_context.statManager().createRateStat("udp.dropPeerConsecutiveFailures", "How many consecutive failed sends to a peer did we attempt before giving up and reestablishing a new session (lifetime is inactivity perood)", "udp", RATES);
|
||||
__instance = this;
|
||||
|
||||
SimpleScheduler.getInstance().addPeriodicEvent(new PingIntroducers(), MIN_EXPIRE_TIMEOUT * 3 / 4);
|
||||
}
|
||||
@@ -1623,22 +1625,11 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
return skews;
|
||||
}
|
||||
|
||||
private static UDPTransport __instance;
|
||||
/** **internal, do not use** */
|
||||
public static final UDPTransport _instance() { return __instance; }
|
||||
/** **internal, do not use** return the peers (Hash) of active peers. */
|
||||
public List<Hash> _getActivePeers() {
|
||||
List<Hash> peers = new ArrayList(128);
|
||||
peers.addAll(_peersByIdent.keySet());
|
||||
|
||||
long now = _context.clock().now();
|
||||
for (Iterator<Hash> iter = peers.iterator(); iter.hasNext(); ) {
|
||||
Hash peer = iter.next();
|
||||
PeerState state = getPeerState(peer);
|
||||
if (now-state.getLastReceiveTime() > 5*60*1000)
|
||||
iter.remove(); // don't include old peers
|
||||
}
|
||||
return peers;
|
||||
/**
|
||||
* @since 0.9
|
||||
*/
|
||||
DHSessionKeyBuilder getDHBuilder() {
|
||||
return _dhFactory.getBuilder();
|
||||
}
|
||||
|
||||
private static final int FLAG_ALPHA = 0;
|
||||
|
Reference in New Issue
Block a user