forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p.libgmp' (head 41a57954f7e78e57f8eb5e30e8ebde7fd75b15dc)
to branch 'i2p.i2p' (head d174e772ebd4f3e3eac5c9b5abd7f736c2527eb2)
This commit is contained in:
@@ -21,20 +21,51 @@
|
||||
<target name="compile" depends="depend">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac srcdir="./src" debug="true" source="1.5" target="1.5" deprecation="on" destdir="./build/obj" classpath="${javac.classpath}" >
|
||||
<javac srcdir="./src" debug="true" source="1.5" target="1.5" deprecation="on"
|
||||
includeAntRuntime="false"
|
||||
destdir="./build/obj" classpath="${javac.classpath}" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="compileTest">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac srcdir="./src:./test" debug="true" source="1.5" target="1.5" deprecation="on" destdir="./build/obj" >
|
||||
<!-- junit classes are in ant runtime -->
|
||||
<javac srcdir="./src:./test" debug="true" source="1.5" target="1.5" deprecation="on"
|
||||
includeAntRuntime="true"
|
||||
destdir="./build/obj" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
</target>
|
||||
<target name="jar" depends="compile">
|
||||
<jar destfile="./build/i2p.jar" basedir="./build/obj" includes="**/*.class" />
|
||||
|
||||
<target name="jar" depends="compile, jarUpToDate" unless="jar.uptodate" >
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
</exec>
|
||||
<jar destfile="./build/i2p.jar" basedir="./build/obj" includes="**/*.class" >
|
||||
<manifest>
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="jarUpToDate" >
|
||||
<uptodate property="jar.uptodate" targetfile="build/i2p.jar" >
|
||||
<srcfiles dir= "build/obj" includes="**/*.class" />
|
||||
</uptodate>
|
||||
</target>
|
||||
|
||||
<target name="jarTest" depends="compileTest">
|
||||
<jar destfile="./build/i2ptest.jar" basedir="./build/obj" includes="**/*.class" />
|
||||
</target>
|
||||
@@ -43,15 +74,35 @@
|
||||
<mkdir dir="./build/javadoc" />
|
||||
<javadoc sourcepath="./src:./test" destdir="./build/javadoc" packagenames="*" use="true" splitindex="true" windowtitle="I2P SDK" />
|
||||
</target>
|
||||
<target name="test" depends="clean, compileTest">
|
||||
<junit printsummary="on" fork="yes">
|
||||
<target name="prepareTest" depends="compileTest" if="with.cobertura">
|
||||
<taskdef classpath="${with.cobertura}" resource="tasks.properties" onerror="report" />
|
||||
<mkdir dir="./build/obj_test" />
|
||||
<cobertura-instrument todir="./build/obj_test">
|
||||
<fileset dir="./build/obj">
|
||||
<include name="**/*.class"/>
|
||||
<exclude name="**/*Test.class" />
|
||||
</fileset>
|
||||
</cobertura-instrument>
|
||||
</target>
|
||||
<target name="test" depends="clean, compileTest, prepareTest">
|
||||
<delete>
|
||||
<fileset dir="../../reports/core/junit">
|
||||
<include name="TEST-*.xml"/>
|
||||
</fileset>
|
||||
</delete>
|
||||
<mkdir dir="../../reports/" />
|
||||
<mkdir dir="../../reports/core/" />
|
||||
<mkdir dir="../../reports/core/junit/" />
|
||||
<junit printsummary="on" fork="yes" maxmemory="384m">
|
||||
<sysproperty key="net.sourceforge.cobertura.datafile" file="./cobertura.ser" />
|
||||
<classpath>
|
||||
<pathelement path="${classpath}" />
|
||||
<pathelement location="./build/obj_test" />
|
||||
<pathelement location="./build/obj" />
|
||||
<pathelement location="../../installer/lib/jbigi/jbigi.jar" />
|
||||
<pathelement path="${ant.home}/lib/clover.jar"/>
|
||||
<pathelement location="${with.cobertura}" />
|
||||
</classpath>
|
||||
<batchtest>
|
||||
<batchtest todir="../../reports/core/junit/">
|
||||
<fileset dir="./test/">
|
||||
<include name="**/*Test.java" />
|
||||
<exclude name="**/ElGamalAESEngineTest.java" />
|
||||
@@ -60,24 +111,11 @@
|
||||
</batchtest>
|
||||
<formatter type="xml"/>
|
||||
</junit>
|
||||
<mkdir dir="../../reports/" />
|
||||
<mkdir dir="../../reports/core/" />
|
||||
<mkdir dir="../../reports/core/junit/" />
|
||||
<delete>
|
||||
<fileset dir="../../reports/core/junit">
|
||||
<include name="TEST-*.xml"/>
|
||||
</fileset>
|
||||
</delete>
|
||||
<copy todir="../../reports/core/junit">
|
||||
<fileset dir=".">
|
||||
<include name="TEST-*.xml"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<delete>
|
||||
<fileset dir=".">
|
||||
<include name="TEST-*.xml"/>
|
||||
</fileset>
|
||||
</delete>
|
||||
</target>
|
||||
<target name="cobertura" depends="test" if="with.cobertura">
|
||||
<mkdir dir="../../reports/core/cobertura" />
|
||||
<cobertura-report format="xml" srcdir="./src" destdir="../../reports/core/cobertura" />
|
||||
<delete file="./cobertura.ser" />
|
||||
</target>
|
||||
<target name="junit.report">
|
||||
<junitreport todir="../../reports/core/junit">
|
||||
@@ -87,28 +125,8 @@
|
||||
<report format="frames" todir="../../reports/core/html/junit"/>
|
||||
</junitreport>
|
||||
</target>
|
||||
<target name="clover.report">
|
||||
<taskdef resource="clovertasks"/>
|
||||
<mkdir dir="../../reports/" />
|
||||
<mkdir dir="../../reports/core" />
|
||||
<mkdir dir="../../reports/core/clover" />
|
||||
<clover-setup initString="../../reports/core/clover/coverage.db"/>
|
||||
<clover-report>
|
||||
<current outfile="../../reports/core/html/clover">
|
||||
<format type="html"/>
|
||||
</current>
|
||||
</clover-report>
|
||||
</target>
|
||||
<target name="test.report" depends="junit.report, clover.report"/>
|
||||
<target name="useclover">
|
||||
<taskdef resource="clovertasks"/>
|
||||
<mkdir dir="../../reports/" />
|
||||
<mkdir dir="../../reports/core/" />
|
||||
<mkdir dir="../../reports/core/clover" />
|
||||
<clover-setup initString="../../reports/core/clover/coverage.db"/>
|
||||
</target>
|
||||
<target name="test.report" depends="junit.report"/>
|
||||
<target name="fulltest" depends="test, junit.report" />
|
||||
<target name="fullclovertest" depends="useclover, test, test.report" />
|
||||
<target name="clean">
|
||||
<delete dir="./build" />
|
||||
</target>
|
||||
|
||||
@@ -324,18 +324,26 @@ public class CPUID {
|
||||
return getCPUFamily() > 6 || (getCPUFamily() == 6 && getCPUModel() >=3);
|
||||
}
|
||||
public boolean IsPentium3Compatible()
|
||||
{
|
||||
return getCPUFamily() > 6 || (getCPUFamily() == 6 && getCPUModel() >=7);
|
||||
{
|
||||
// Atom
|
||||
if (getCPUExtendedModel() == 1 && (getCPUFamily() == 6 && (getCPUModel() == 12))){
|
||||
return true;
|
||||
// ??
|
||||
} else if (getCPUExtendedModel() == 0 && (getCPUFamily() > 6 || (getCPUFamily() == 6 && getCPUModel() >=7))){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean IsPentium4Compatible()
|
||||
{
|
||||
// P4
|
||||
// P4
|
||||
if (getCPUFamily() >= 15){
|
||||
return true;
|
||||
// Xeon MP (45nm) or Core i7
|
||||
// Xeon MP (45nm) or Core i7
|
||||
} else if (getCPUExtendedModel() == 1 && (getCPUFamily() == 6 && (getCPUModel() == 10 || getCPUModel() == 13))){
|
||||
return true;
|
||||
// Core 2 Duo
|
||||
// Core 2 Duo
|
||||
} else if (getCPUExtendedModel() == 0 && getCPUFamily() == 6 && getCPUModel() == 15){
|
||||
return true;
|
||||
} else {
|
||||
@@ -417,17 +425,18 @@ public class CPUID {
|
||||
case 15:
|
||||
return "Core 2 (Conroe)";
|
||||
}
|
||||
}
|
||||
if (getCPUExtendedModel() == 1){
|
||||
switch(getCPUModel()){
|
||||
case 10:
|
||||
return "Core i7";
|
||||
case 12:
|
||||
return "Atom";
|
||||
case 13:
|
||||
return "Xeon MP";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (getCPUExtendedModel() == 1){
|
||||
switch(getCPUModel()){
|
||||
case 10:
|
||||
return "Core i7";
|
||||
case 12:
|
||||
return "Atom";
|
||||
case 13:
|
||||
return "Xeon MP";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(getCPUFamily() == 7){
|
||||
switch(getCPUModel()){
|
||||
|
||||
@@ -16,7 +16,7 @@ package net.i2p;
|
||||
public class CoreVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = "0.8.2";
|
||||
public final static String VERSION = "0.8.6";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
||||
@@ -30,11 +30,13 @@ import net.i2p.util.Clock;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.FortunaRandomSource;
|
||||
import net.i2p.util.I2PProperties;
|
||||
import net.i2p.util.KeyRing;
|
||||
import net.i2p.util.LogManager;
|
||||
//import net.i2p.util.PooledRandomSource;
|
||||
import net.i2p.util.RandomSource;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
import net.i2p.util.I2PProperties.I2PPropertyCallback;
|
||||
|
||||
/**
|
||||
* <p>Provide a base scope for accessing singletons that I2P exposes. Rather than
|
||||
@@ -63,9 +65,9 @@ import net.i2p.util.SecureDirectory;
|
||||
*/
|
||||
public class I2PAppContext {
|
||||
/** the context that components without explicit root are bound */
|
||||
protected static I2PAppContext _globalAppContext;
|
||||
protected static volatile I2PAppContext _globalAppContext;
|
||||
|
||||
private Properties _overrideProps;
|
||||
protected I2PProperties _overrideProps;
|
||||
|
||||
private StatManager _statManager;
|
||||
private SessionKeyManager _sessionKeyManager;
|
||||
@@ -117,7 +119,8 @@ public class I2PAppContext {
|
||||
*
|
||||
*/
|
||||
public static I2PAppContext getGlobalContext() {
|
||||
// skip the global lock
|
||||
// skip the global lock - _gAC must be volatile
|
||||
// http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
|
||||
I2PAppContext rv = _globalAppContext;
|
||||
if (rv != null)
|
||||
return rv;
|
||||
@@ -168,7 +171,9 @@ public class I2PAppContext {
|
||||
_globalAppContext = this;
|
||||
}
|
||||
}
|
||||
_overrideProps = envProps;
|
||||
_overrideProps = new I2PProperties();
|
||||
if (envProps != null)
|
||||
_overrideProps.putAll(envProps);
|
||||
_statManager = null;
|
||||
_sessionKeyManager = null;
|
||||
_namingService = null;
|
||||
@@ -474,6 +479,9 @@ public class I2PAppContext {
|
||||
* provided during the context construction, as well as the ones included in
|
||||
* System.getProperties.
|
||||
*
|
||||
* WARNING - not overridden in RouterContext, doesn't contain router config settings,
|
||||
* use getProperties() instead.
|
||||
*
|
||||
* @return set of Strings containing the names of defined system properties
|
||||
*/
|
||||
public Set getPropertyNames() {
|
||||
@@ -483,6 +491,29 @@ public class I2PAppContext {
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the configuration attributes of this context, listing the properties
|
||||
* provided during the context construction, as well as the ones included in
|
||||
* System.getProperties.
|
||||
*
|
||||
* @return new Properties with system and context properties
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public Properties getProperties() {
|
||||
Properties rv = new Properties();
|
||||
rv.putAll(System.getProperties());
|
||||
rv.putAll(_overrideProps);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback, which will fire upon changes in the property
|
||||
* given in the specific callback.
|
||||
* Unimplemented in I2PAppContext: this only makes sense in a router context.
|
||||
* @param callback The implementation of the callback.
|
||||
*/
|
||||
public void addPropertyCallback(I2PPropertyCallback callback) {}
|
||||
|
||||
/**
|
||||
* The statistics component with which we can track various events
|
||||
* over time.
|
||||
@@ -757,7 +788,7 @@ public class I2PAppContext {
|
||||
* enable simulators to play with clock skew among different instances.
|
||||
*
|
||||
*/
|
||||
public Clock clock() { // overridden in RouterContext
|
||||
public Clock clock() {
|
||||
if (!_clockInitialized)
|
||||
initializeClock();
|
||||
return _clock;
|
||||
|
||||
@@ -26,11 +26,13 @@ class DestReplyMessageHandler extends HandlerImpl {
|
||||
_log.debug("Handle message " + message);
|
||||
DestReplyMessage msg = (DestReplyMessage) message;
|
||||
Destination d = msg.getDestination();
|
||||
if (d != null)
|
||||
if (d != null) {
|
||||
session.destReceived(d);
|
||||
Hash h = msg.getHash();
|
||||
if (h != null)
|
||||
session.destLookupFailed(h);
|
||||
} else {
|
||||
Hash h = msg.getHash();
|
||||
if (h != null)
|
||||
session.destLookupFailed(h);
|
||||
}
|
||||
// else let it time out
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ package net.i2p.client;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataFormatException;
|
||||
@@ -41,22 +43,51 @@ import net.i2p.util.Log;
|
||||
* @author jrandom
|
||||
*/
|
||||
class I2CPMessageProducer {
|
||||
private final static Log _log = new Log(I2CPMessageProducer.class);
|
||||
private final Log _log;
|
||||
private final I2PAppContext _context;
|
||||
private int _sendBps;
|
||||
private long _sendPeriodBytes;
|
||||
private long _sendPeriodBeginTime;
|
||||
private int _maxBytesPerSecond;
|
||||
private volatile int _sendPeriodBytes;
|
||||
private volatile long _sendPeriodBeginTime;
|
||||
private final ReentrantLock _lock;
|
||||
private static final String PROP_MAX_BW = "i2cp.outboundBytesPerSecond";
|
||||
/** see ConnectionOptions in streaming - MTU + streaming overhead + gzip overhead */
|
||||
private static final int TYP_SIZE = 1730 + 28 + 23;
|
||||
private static final int MIN_RATE = 2 * TYP_SIZE;
|
||||
|
||||
public I2CPMessageProducer(I2PAppContext context) {
|
||||
_context = context;
|
||||
context.statManager().createRateStat("client.sendBpsRaw", "How fast we pump out I2CP data messages", "ClientMessages", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
|
||||
_log = context.logManager().getLog(I2CPMessageProducer.class);
|
||||
_lock = new ReentrantLock(true);
|
||||
context.statManager().createRateStat("client.sendThrottled", "Times waited for bandwidth", "ClientMessages", new long[] { 60*1000 });
|
||||
context.statManager().createRateStat("client.sendDropped", "Length of msg dropped waiting for bandwidth", "ClientMessages", new long[] { 60*1000 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the bandwidth setting
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void updateBandwidth(I2PSessionImpl session) {
|
||||
String max = session.getOptions().getProperty(PROP_MAX_BW);
|
||||
if (max != null) {
|
||||
try {
|
||||
int iMax = Integer.parseInt(max);
|
||||
if (iMax > 0)
|
||||
// round up to next higher TYP_SIZE for efficiency, then add some fudge for small messages
|
||||
_maxBytesPerSecond = 256 + Math.max(MIN_RATE, TYP_SIZE * ((iMax + TYP_SIZE - 1) / TYP_SIZE));
|
||||
else
|
||||
_maxBytesPerSecond = 0;
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Setting " + _maxBytesPerSecond + " BPS max");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send all the messages that a client needs to send to a router to establish
|
||||
* a new session.
|
||||
*/
|
||||
public void connect(I2PSessionImpl session) throws I2PSessionException {
|
||||
updateBandwidth(session);
|
||||
CreateSessionMessage msg = new CreateSessionMessage();
|
||||
SessionConfig cfg = new SessionConfig(session.getMyDestination());
|
||||
cfg.setOptions(session.getOptions());
|
||||
@@ -99,32 +130,135 @@ class I2CPMessageProducer {
|
||||
*/
|
||||
public void sendMessage(I2PSessionImpl session, Destination dest, long nonce, byte[] payload, SessionTag tag,
|
||||
SessionKey key, Set tags, SessionKey newKey, long expires) throws I2PSessionException {
|
||||
sendMessage(session, dest, nonce, payload, expires, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Package up and send the payload to the router for delivery
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void sendMessage(I2PSessionImpl session, Destination dest, long nonce, byte[] payload,
|
||||
long expires, int flags) throws I2PSessionException {
|
||||
|
||||
if (!updateBps(payload.length, expires))
|
||||
// drop the message... send fail notification?
|
||||
return;
|
||||
SendMessageMessage msg;
|
||||
if (expires > 0) {
|
||||
msg = new SendMessageExpiresMessage();
|
||||
((SendMessageExpiresMessage)msg).setExpiration(new Date(expires));
|
||||
if (expires > 0 || flags > 0) {
|
||||
SendMessageExpiresMessage smsg = new SendMessageExpiresMessage();
|
||||
smsg.setExpiration(expires);
|
||||
smsg.setFlags(flags);
|
||||
msg = smsg;
|
||||
} else
|
||||
msg = new SendMessageMessage();
|
||||
msg.setDestination(dest);
|
||||
msg.setSessionId(session.getSessionId());
|
||||
msg.setNonce(nonce);
|
||||
Payload data = createPayload(dest, payload, tag, key, tags, newKey);
|
||||
Payload data = createPayload(dest, payload, null, null, null, null);
|
||||
msg.setPayload(data);
|
||||
session.sendMessage(msg);
|
||||
updateBps(payload.length);
|
||||
}
|
||||
|
||||
private void updateBps(int len) {
|
||||
long now = _context.clock().now();
|
||||
float period = ((float)now-_sendPeriodBeginTime)/1000f;
|
||||
if (period >= 1f) {
|
||||
// first term decays on slow transmission
|
||||
_sendBps = (int)(((float)0.9f * (float)_sendBps) + ((float)0.1f*((float)_sendPeriodBytes)/period));
|
||||
_sendPeriodBytes = len;
|
||||
_sendPeriodBeginTime = now;
|
||||
_context.statManager().addRateData("client.sendBpsRaw", _sendBps, 0);
|
||||
} else {
|
||||
_sendPeriodBytes += len;
|
||||
/**
|
||||
* Super-simple bandwidth throttler.
|
||||
* We only calculate on a one-second basis, so large messages
|
||||
* (compared to the one-second limit) may exceed the limits.
|
||||
* Tuned for streaming, may not work well for large datagrams.
|
||||
*
|
||||
* This does poorly with low rate limits since it doesn't credit
|
||||
* bandwidth across two periods. So the limit is rounded up,
|
||||
* and the min limit is set to 2x the typ size, above.
|
||||
*
|
||||
* Blocking so this could be very bad for retransmissions,
|
||||
* as it could clog StreamingTimer.
|
||||
* Waits are somewhat "fair" using ReentrantLock.
|
||||
* While out-of-order transmission is acceptable, fairness
|
||||
* reduces the chance of starvation. ReentrantLock does not
|
||||
* guarantee in-order execution due to thread priority issues,
|
||||
* so out-of-order may still occur. But shouldn't happen within
|
||||
* the same thread anyway... Also note that small messages may
|
||||
* go ahead of large ones that are waiting for the next window.
|
||||
* Also, threads waiting a second time go to the back of the line.
|
||||
*
|
||||
* Since this is at the I2CP layer, it includes streaming overhead,
|
||||
* streaming acks and retransmissions,
|
||||
* gzip overhead (or "underhead" for compression),
|
||||
* repliable datagram overhead, etc.
|
||||
* However, it does not, of course, include the substantial overhead
|
||||
* imposed by the router for the leaseset, tags, encryption,
|
||||
* and fixed-size tunnel messages.
|
||||
*
|
||||
* @param expires if > 0, an expiration date
|
||||
* @return true if we should send the message, false to drop it
|
||||
*/
|
||||
private boolean updateBps(int len, long expires) {
|
||||
if (_maxBytesPerSecond <= 0)
|
||||
return true;
|
||||
//synchronized(this) {
|
||||
_lock.lock();
|
||||
try {
|
||||
int waitCount = 0;
|
||||
while (true) {
|
||||
long now = _context.clock().now();
|
||||
if (waitCount > 0 && expires > 0 && expires < now) {
|
||||
// just say no to bufferbloat... drop the message right here
|
||||
_context.statManager().addRateData("client.sendDropped", len, 0);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Dropping " + len + " byte msg expired in queue");
|
||||
return false;
|
||||
}
|
||||
|
||||
long period = now - _sendPeriodBeginTime;
|
||||
if (period >= 2000) {
|
||||
// start new period, always let it through no matter how big
|
||||
_sendPeriodBytes = len;
|
||||
_sendPeriodBeginTime = now;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("New period after idle, " + len + " bytes");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (period >= 1000) {
|
||||
// start new period
|
||||
// Allow burst within 2 sec, only advance window by 1 sec, and
|
||||
// every other second give credit for unused bytes in previous period
|
||||
if (_sendPeriodBytes > 0 && ((_sendPeriodBeginTime / 1000) & 0x01) == 0)
|
||||
_sendPeriodBytes += len - _maxBytesPerSecond;
|
||||
else
|
||||
_sendPeriodBytes = len;
|
||||
_sendPeriodBeginTime += 1000;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("New period, " + len + " bytes");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_sendPeriodBytes + len <= _maxBytesPerSecond) {
|
||||
// still bytes available in this period
|
||||
_sendPeriodBytes += len;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Sending " + len + ", Elapsed " + period + "ms, total " + _sendPeriodBytes + " bytes");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (waitCount >= 2) {
|
||||
// just say no to bufferbloat... drop the message right here
|
||||
_context.statManager().addRateData("client.sendDropped", len, 0);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Dropping " + len + " byte msg after waiting " + waitCount + " times");
|
||||
return false;
|
||||
}
|
||||
|
||||
// wait until next period
|
||||
_context.statManager().addRateData("client.sendThrottled", ++waitCount, 0);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Throttled " + len + " bytes, wait #" + waitCount + ' ' + (1000 - period) + "ms" /*, new Exception()*/);
|
||||
try {
|
||||
//this.wait(1000 - period);
|
||||
_lock.newCondition().await(1000 - period, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
} finally {
|
||||
_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ package net.i2p.client;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
@@ -20,17 +21,20 @@ import net.i2p.data.SigningPrivateKey;
|
||||
/**
|
||||
* <p>Define the standard means of sending and receiving messages on the
|
||||
* I2P network by using the I2CP (the client protocol). This is done over a
|
||||
* bidirectional TCP socket and never sends any private keys - all end to end
|
||||
* encryption is done transparently within the client's I2PSession
|
||||
* itself. Periodically the router will ask the client to authorize a new set of
|
||||
* bidirectional TCP socket and never sends any private keys.
|
||||
*
|
||||
* End to end encryption in I2PSession was disabled in release 0.6.
|
||||
*
|
||||
* Periodically the router will ask the client to authorize a new set of
|
||||
* tunnels to be allocated to the client, which the client can accept by sending a
|
||||
* {@link net.i2p.data.LeaseSet} signed by the {@link net.i2p.data.Destination}.
|
||||
* In addition, the router may on occation provide the client with an updated
|
||||
* In addition, the router may on occasion provide the client with an updated
|
||||
* clock offset so that the client can stay in sync with the network (even if
|
||||
* the host computer's clock is off).</p>
|
||||
*
|
||||
*/
|
||||
public interface I2PSession {
|
||||
|
||||
/** Send a new message to the given destination, containing the specified
|
||||
* payload, returning true if the router feels confident that the message
|
||||
* was delivered.
|
||||
@@ -39,11 +43,18 @@ public interface I2PSession {
|
||||
* @return whether it was accepted by the router for delivery or not
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException;
|
||||
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size) throws I2PSessionException;
|
||||
/** See I2PSessionMuxedImpl for details */
|
||||
|
||||
/**
|
||||
* See I2PSessionMuxedImpl for proto/port details.
|
||||
* @since 0.7.1
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int proto, int fromport, int toport) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* End-to-End Crypto is disabled, tags and keys are ignored!
|
||||
*
|
||||
* Like sendMessage above, except the key used and the tags sent are exposed to the
|
||||
* application. <p />
|
||||
*
|
||||
@@ -61,25 +72,62 @@ public interface I2PSession {
|
||||
*
|
||||
* @param dest location to send the message
|
||||
* @param payload body of the message to be sent (unencrypted)
|
||||
* @param keyUsed session key delivered to the destination for association with the tags sent. This is essentially
|
||||
* @param keyUsed UNUSED, IGNORED. Session key delivered to the destination for association with the tags sent. This is essentially
|
||||
* an output parameter - keyUsed.getData() is ignored during this call, but after the call completes,
|
||||
* it will be filled with the bytes of the session key delivered. Typically the key delivered is the
|
||||
* same one as the key encrypted with, but not always. If this is null then the key data will not be
|
||||
* exposed.
|
||||
* @param tagsSent set of tags delivered to the peer and associated with the keyUsed. This is also an output parameter -
|
||||
* @param tagsSent UNUSED, IGNORED. Set of tags delivered to the peer and associated with the keyUsed. This is also an output parameter -
|
||||
* the contents of the set is ignored during the call, but afterwards it contains a set of SessionTag
|
||||
* objects that were sent along side the given keyUsed.
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* End-to-End Crypto is disabled, tags and keys are ignored.
|
||||
* @param keyUsed UNUSED, IGNORED.
|
||||
* @param tagsSent UNUSED, IGNORED.
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* End-to-End Crypto is disabled, tags and keys are ignored.
|
||||
* @param keyUsed UNUSED, IGNORED.
|
||||
* @param tagsSent UNUSED, IGNORED.
|
||||
* @since 0.7.1
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire) throws I2PSessionException;
|
||||
/** See I2PSessionMuxedImpl for details */
|
||||
|
||||
/**
|
||||
* See I2PSessionMuxedImpl for proto/port details.
|
||||
* End-to-End Crypto is disabled, tags and keys are ignored.
|
||||
* @param keyUsed UNUSED, IGNORED.
|
||||
* @param tagsSent UNUSED, IGNORED.
|
||||
* @since 0.7.1
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
|
||||
int proto, int fromport, int toport) throws I2PSessionException;
|
||||
/** See I2PSessionMuxedImpl for details */
|
||||
|
||||
/**
|
||||
* See I2PSessionMuxedImpl for proto/port details.
|
||||
* End-to-End Crypto is disabled, tags and keys are ignored.
|
||||
* @param keyUsed UNUSED, IGNORED.
|
||||
* @param tagsSent UNUSED, IGNORED.
|
||||
* @since 0.7.1
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
|
||||
int proto, int fromport, int toport) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* See I2PSessionMuxedImpl for proto/port details.
|
||||
* End-to-End Crypto is disabled, tags and keys are ignored.
|
||||
* @param keyUsed UNUSED, IGNORED.
|
||||
* @param tagsSent UNUSED, IGNORED.
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
|
||||
int proto, int fromport, int toport, int flags) throws I2PSessionException;
|
||||
|
||||
/** Receive a message that the router has notified the client about, returning
|
||||
* the payload.
|
||||
* @param msgId message to fetch
|
||||
@@ -151,8 +199,16 @@ public interface I2PSession {
|
||||
*/
|
||||
public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* Does not remove properties previously present but missing from this options parameter.
|
||||
* @param options non-null
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void updateOptions(Properties options);
|
||||
|
||||
/**
|
||||
* Get the current bandwidth limits. Blocking.
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public int[] bandwidthLimits() throws I2PSessionException;
|
||||
|
||||
|
||||
@@ -221,20 +221,32 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
}
|
||||
}
|
||||
|
||||
/** save some memory, don't pass along the pointless properties */
|
||||
private Properties filter(Properties options) {
|
||||
Properties rv = new Properties();
|
||||
for (Iterator iter = options.keySet().iterator(); iter.hasNext();) {
|
||||
String key = (String) iter.next();
|
||||
String val = options.getProperty(key);
|
||||
if (key.startsWith("java") ||
|
||||
key.startsWith("user") ||
|
||||
key.startsWith("os") ||
|
||||
key.startsWith("sun") ||
|
||||
key.startsWith("file") ||
|
||||
key.startsWith("line") ||
|
||||
key.startsWith("wrapper")) {
|
||||
if (key.startsWith("java.") ||
|
||||
key.startsWith("user.") ||
|
||||
key.startsWith("os.") ||
|
||||
key.startsWith("sun.") ||
|
||||
key.startsWith("file.") ||
|
||||
key.equals("line.separator") ||
|
||||
key.equals("path.separator") ||
|
||||
key.equals("prng.buffers") ||
|
||||
key.equals("router.trustedUpdateKeys") ||
|
||||
key.startsWith("router.update") ||
|
||||
key.startsWith("routerconsole.") ||
|
||||
key.startsWith("time.") ||
|
||||
key.startsWith("stat.") ||
|
||||
key.startsWith("gnu.") || // gnu JVM
|
||||
key.startsWith("net.i2p.router.web.") || // console nonces
|
||||
key.startsWith("wrapper.")) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Skipping property: " + key);
|
||||
} else if ((key.length() > 255) || (val.length() > 255)) {
|
||||
continue;
|
||||
}
|
||||
String val = options.getProperty(key);
|
||||
if ((key.length() > 255) || (val.length() > 255)) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + "Not passing on property ["
|
||||
+ key
|
||||
@@ -247,6 +259,18 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the tunnel and bandwidth settings
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void updateOptions(Properties options) {
|
||||
_options.putAll(filter(options));
|
||||
_producer.updateBandwidth(this);
|
||||
try {
|
||||
_producer.updateTunnels(this, 0);
|
||||
} catch (I2PSessionException ise) {}
|
||||
}
|
||||
|
||||
void setLeaseSet(LeaseSet ls) {
|
||||
_leaseSet = ls;
|
||||
if (ls != null) {
|
||||
@@ -397,7 +421,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
*
|
||||
*/
|
||||
public byte[] receiveMessage(int msgId) throws I2PSessionException {
|
||||
MessagePayloadMessage msg = _availableMessages.remove(new Long(msgId));
|
||||
MessagePayloadMessage msg = _availableMessages.remove(Long.valueOf(msgId));
|
||||
if (msg == null) {
|
||||
_log.error("Receive message " + msgId + " had no matches");
|
||||
return null;
|
||||
@@ -414,21 +438,6 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
_producer.reportAbuse(this, msgId, severity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the data to the destination.
|
||||
* TODO: this currently always returns true, regardless of whether the message was
|
||||
* delivered successfully. make this wait for at least ACCEPTED
|
||||
*
|
||||
*/
|
||||
public abstract boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* @param keyUsed unused - no end-to-end crypto
|
||||
* @param tagsSent unused - no end-to-end crypto
|
||||
*/
|
||||
public abstract boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed,
|
||||
Set tagsSent) throws I2PSessionException;
|
||||
|
||||
public abstract void receiveStatus(int msgId, long nonce, int status);
|
||||
|
||||
/****** no end-to-end crypto
|
||||
@@ -444,7 +453,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
* Recieve a payload message and let the app know its available
|
||||
*/
|
||||
public void addNewMessage(MessagePayloadMessage msg) {
|
||||
Long mid = new Long(msg.getMessageId());
|
||||
Long mid = Long.valueOf(msg.getMessageId());
|
||||
_availableMessages.put(mid, msg);
|
||||
long id = msg.getMessageId();
|
||||
byte data[] = msg.getPayload().getUnencryptedData();
|
||||
@@ -494,7 +503,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
|
||||
public void available(long msgId, int size) {
|
||||
synchronized (AvailabilityNotifier.this) {
|
||||
_pendingIds.add(new Long(msgId));
|
||||
_pendingIds.add(Long.valueOf(msgId));
|
||||
_pendingSizes.add(Integer.valueOf(size));
|
||||
AvailabilityNotifier.this.notifyAll();
|
||||
}
|
||||
|
||||
@@ -130,6 +130,10 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
int proto, int fromport, int toport) throws I2PSessionException {
|
||||
throw new IllegalArgumentException("Use MuxedImpl");
|
||||
}
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
|
||||
int proto, int fromport, int toport, int flags) throws I2PSessionException {
|
||||
throw new IllegalArgumentException("Use MuxedImpl");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException {
|
||||
@@ -222,14 +226,23 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
private static final int NUM_TAGS = 50;
|
||||
|
||||
/**
|
||||
* TODO - Don't need to save MessageState since actuallyWait is false...
|
||||
* But for now just use sendNoEffort() instead.
|
||||
*
|
||||
* @param keyUsed unused - no end-to-end crypto
|
||||
* @param tagsSent unused - no end-to-end crypto
|
||||
*/
|
||||
protected boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent, long expires)
|
||||
throws I2PSessionException {
|
||||
return sendBestEffort(dest, payload, expires, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO - Don't need to save MessageState since actuallyWait is false...
|
||||
* But for now just use sendNoEffort() instead.
|
||||
*
|
||||
* @param flags to be passed to the router
|
||||
* @since 0.8.4
|
||||
*/
|
||||
protected boolean sendBestEffort(Destination dest, byte payload[], long expires, int flags)
|
||||
throws I2PSessionException {
|
||||
//SessionKey key = null;
|
||||
//SessionKey newKey = null;
|
||||
//SessionTag tag = null;
|
||||
@@ -324,7 +337,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
+ " sync took " + (inSendingSync-beforeSendingSync)
|
||||
+ " add took " + (afterSendingSync-inSendingSync));
|
||||
//_producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey, expires);
|
||||
_producer.sendMessage(this, dest, nonce, payload, null, null, null, null, expires);
|
||||
_producer.sendMessage(this, dest, nonce, payload, expires, flags);
|
||||
|
||||
// since this is 'best effort', all we're waiting for is a status update
|
||||
// saying that the router received it - in theory, that should come back
|
||||
|
||||
@@ -162,12 +162,34 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession {
|
||||
* 255 disallowed
|
||||
* @param fromPort 1-65535 or 0 for unset
|
||||
* @param toPort 1-65535 or 0 for unset
|
||||
* @since 0.7.1
|
||||
*/
|
||||
@Override
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
|
||||
SessionKey keyUsed, Set tagsSent, long expires,
|
||||
int proto, int fromPort, int toPort)
|
||||
throws I2PSessionException {
|
||||
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, proto, fromPort, toPort, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param keyUsed unused - no end-to-end crypto
|
||||
* @param tagsSent unused - no end-to-end crypto
|
||||
* @param proto 1-254 or 0 for unset; recommended:
|
||||
* I2PSession.PROTO_UNSPECIFIED
|
||||
* I2PSession.PROTO_STREAMING
|
||||
* I2PSession.PROTO_DATAGRAM
|
||||
* 255 disallowed
|
||||
* @param fromPort 1-65535 or 0 for unset
|
||||
* @param toPort 1-65535 or 0 for unset
|
||||
* @param flags to be passed to the router
|
||||
* @since 0.8.4
|
||||
*/
|
||||
@Override
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
|
||||
SessionKey keyUsed, Set tagsSent, long expires,
|
||||
int proto, int fromPort, int toPort, int flags)
|
||||
throws I2PSessionException {
|
||||
if (isClosed()) throw new I2PSessionException("Already closed");
|
||||
updateActivity();
|
||||
|
||||
@@ -183,7 +205,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession {
|
||||
|
||||
_context.statManager().addRateData("i2cp.tx.msgCompressed", payload.length, 0);
|
||||
_context.statManager().addRateData("i2cp.tx.msgExpanded", size, 0);
|
||||
return sendBestEffort(dest, payload, keyUsed, tagsSent, expires);
|
||||
return sendBestEffort(dest, payload, expires, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,7 +213,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession {
|
||||
*/
|
||||
@Override
|
||||
public void addNewMessage(MessagePayloadMessage msg) {
|
||||
Long mid = new Long(msg.getMessageId());
|
||||
Long mid = Long.valueOf(msg.getMessageId());
|
||||
_availableMessages.put(mid, msg);
|
||||
long id = msg.getMessageId();
|
||||
byte data[] = msg.getPayload().getUnencryptedData();
|
||||
|
||||
@@ -98,10 +98,17 @@ class I2PSimpleSession extends I2PSessionImpl2 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore, does nothing
|
||||
* @since 0.8.4
|
||||
*/
|
||||
@Override
|
||||
public void updateOptions(Properties options) {}
|
||||
|
||||
/**
|
||||
* Only map message handlers that we will use
|
||||
*/
|
||||
class SimpleMessageHandlerMap extends I2PClientMessageHandlerMap {
|
||||
private static class SimpleMessageHandlerMap extends I2PClientMessageHandlerMap {
|
||||
public SimpleMessageHandlerMap(I2PAppContext context) {
|
||||
int highest = Math.max(DestReplyMessage.MESSAGE_TYPE, BandwidthLimitsMessage.MESSAGE_TYPE);
|
||||
_handlers = new I2CPMessageHandler[highest+1];
|
||||
|
||||
@@ -30,10 +30,10 @@ public final class I2PDatagramDissector {
|
||||
|
||||
private static Log _log = new Log(I2PDatagramDissector.class);
|
||||
|
||||
private static int DGRAM_BUFSIZE = 32768;
|
||||
private static final int DGRAM_BUFSIZE = 32768;
|
||||
|
||||
private DSAEngine dsaEng = DSAEngine.getInstance();
|
||||
private SHA256Generator hashGen = SHA256Generator.getInstance();
|
||||
private final DSAEngine dsaEng = DSAEngine.getInstance();
|
||||
private final SHA256Generator hashGen = SHA256Generator.getInstance();
|
||||
|
||||
private Hash rxHash = null;
|
||||
|
||||
@@ -41,7 +41,7 @@ public final class I2PDatagramDissector {
|
||||
|
||||
private Destination rxDest;
|
||||
|
||||
private byte[] rxPayload = new byte[DGRAM_BUFSIZE];
|
||||
private final byte[] rxPayload = new byte[DGRAM_BUFSIZE];
|
||||
|
||||
private int rxPayloadLen = 0;
|
||||
|
||||
@@ -63,36 +63,36 @@ public final class I2PDatagramDissector {
|
||||
public void loadI2PDatagram(byte[] dgram) throws DataFormatException {
|
||||
ByteArrayInputStream dgStream = new ByteArrayInputStream(dgram);
|
||||
byte[] rxTrimmedPayload;
|
||||
|
||||
// set invalid(very important!)
|
||||
this.valid = false;
|
||||
|
||||
|
||||
// set invalid(very important!)
|
||||
this.valid = false;
|
||||
|
||||
try {
|
||||
rxDest = new Destination();
|
||||
rxSign = new Signature();
|
||||
|
||||
// read destination
|
||||
|
||||
// read destination
|
||||
rxDest.readBytes(dgStream);
|
||||
|
||||
// read signature
|
||||
|
||||
// read signature
|
||||
rxSign.readBytes(dgStream);
|
||||
|
||||
// read payload
|
||||
|
||||
// read payload
|
||||
rxPayloadLen = dgStream.read(rxPayload);
|
||||
|
||||
// calculate the hash of the payload
|
||||
|
||||
// calculate the hash of the payload
|
||||
this.rxHash = hashGen.calculateHash(rxPayload, 0, rxPayloadLen);
|
||||
assert this.hashGen.calculateHash(this.extractPayload()).equals(this.rxHash);
|
||||
assert this.hashGen.calculateHash(this.extractPayload()).equals(this.rxHash);
|
||||
} catch (IOException e) {
|
||||
_log.error("Caught IOException - INCONSISTENT STATE!", e);
|
||||
} catch(AssertionError e) {
|
||||
_log.error("Assertion failed!", e);
|
||||
}
|
||||
|
||||
_log.error("Assertion failed!", e);
|
||||
}
|
||||
|
||||
//_log.debug("Datagram payload size: " + rxPayloadLen + "; content:\n"
|
||||
// + HexDump.dump(rxPayload, 0, rxPayloadLen));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the payload carried by an I2P repliable datagram (previously loaded
|
||||
* with the loadI2PDatagram() method), verifying the datagram signature.
|
||||
@@ -106,7 +106,7 @@ public final class I2PDatagramDissector {
|
||||
|
||||
return this.extractPayload();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the sender of an I2P repliable datagram (previously loaded with the
|
||||
* loadI2PDatagram() method), verifying the datagram signature.
|
||||
@@ -118,23 +118,23 @@ public final class I2PDatagramDissector {
|
||||
public Destination getSender() throws I2PInvalidDatagramException {
|
||||
this.verifySignature();
|
||||
|
||||
return this.extractSender();
|
||||
return this.extractSender();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the hash of the payload of an I2P repliable datagram (previously
|
||||
* loaded with the loadI2PDatagram() method), verifying the datagram
|
||||
* signature.
|
||||
* @return The hash of the payload of the I2P repliable datagram
|
||||
* @throws I2PInvalidDatagramException if the signature verification fails
|
||||
*/
|
||||
public Hash getHash() throws I2PInvalidDatagramException {
|
||||
// make sure it has a valid signature
|
||||
this.verifySignature();
|
||||
|
||||
return this.extractHash();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the hash of the payload of an I2P repliable datagram (previously
|
||||
* loaded with the loadI2PDatagram() method), verifying the datagram
|
||||
* signature.
|
||||
* @return The hash of the payload of the I2P repliable datagram
|
||||
* @throws I2PInvalidDatagramException if the signature verification fails
|
||||
*/
|
||||
public Hash getHash() throws I2PInvalidDatagramException {
|
||||
// make sure it has a valid signature
|
||||
this.verifySignature();
|
||||
|
||||
return this.extractHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the payload carried by an I2P repliable datagram (previously
|
||||
* loaded with the loadI2PDatagram() method), without verifying the
|
||||
@@ -145,10 +145,10 @@ public final class I2PDatagramDissector {
|
||||
public byte[] extractPayload() {
|
||||
byte[] retPayload = new byte[this.rxPayloadLen];
|
||||
System.arraycopy(this.rxPayload, 0, retPayload, 0, this.rxPayloadLen);
|
||||
|
||||
|
||||
return retPayload;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the sender of an I2P repliable datagram (previously loaded with
|
||||
* the loadI2PDatagram() method), without verifying the datagram signature.
|
||||
@@ -168,31 +168,30 @@ public final class I2PDatagramDissector {
|
||||
|
||||
return retDest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the hash of the payload of an I2P repliable datagram (previously
|
||||
* loaded with the loadI2PDatagram() method), without verifying the datagram
|
||||
* signature.
|
||||
* @return The hash of the payload of the I2P repliable datagram
|
||||
*/
|
||||
public Hash extractHash() {
|
||||
return this.rxHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the hash of the payload of an I2P repliable datagram (previously
|
||||
* loaded with the loadI2PDatagram() method), without verifying the datagram
|
||||
* signature.
|
||||
* @return The hash of the payload of the I2P repliable datagram
|
||||
*/
|
||||
public Hash extractHash() {
|
||||
return this.rxHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the signature of this datagram (previously loaded with the
|
||||
* loadI2PDatagram() method)
|
||||
* @throws I2PInvalidDatagramException if the signature is invalid
|
||||
* @throws I2PInvalidDatagramException if the signature is invalid
|
||||
*/
|
||||
public void verifySignature() throws I2PInvalidDatagramException {
|
||||
// first check if it already got validated
|
||||
if(this.valid)
|
||||
return;
|
||||
|
||||
if (rxSign == null || rxSign.getData() == null ||
|
||||
rxDest == null || rxDest.getSigningPublicKey() == null)
|
||||
if (rxSign == null || rxSign.getData() == null || rxDest == null || rxDest.getSigningPublicKey() == null)
|
||||
throw new I2PInvalidDatagramException("Datagram not yet read");
|
||||
|
||||
|
||||
// now validate
|
||||
if (!this.dsaEng.verifySignature(rxSign, rxHash.getData(), rxDest.getSigningPublicKey()))
|
||||
throw new I2PInvalidDatagramException("Incorrect I2P repliable datagram signature");
|
||||
|
||||
@@ -28,15 +28,15 @@ public final class I2PDatagramMaker {
|
||||
|
||||
private static Log _log = new Log(I2PDatagramMaker.class);
|
||||
|
||||
private static int DGRAM_BUFSIZE = 32768;
|
||||
private static final int DGRAM_BUFSIZE = 32768;
|
||||
|
||||
private SHA256Generator hashGen = SHA256Generator.getInstance();
|
||||
private DSAEngine dsaEng = DSAEngine.getInstance();
|
||||
private final SHA256Generator hashGen = SHA256Generator.getInstance();
|
||||
private final DSAEngine dsaEng = DSAEngine.getInstance();
|
||||
|
||||
private SigningPrivateKey sxPrivKey = null;
|
||||
private byte[] sxDestBytes = null;
|
||||
|
||||
private ByteArrayOutputStream sxDGram = new ByteArrayOutputStream(DGRAM_BUFSIZE);
|
||||
private final ByteArrayOutputStream sxDGram = new ByteArrayOutputStream(DGRAM_BUFSIZE);
|
||||
|
||||
/**
|
||||
* Construct a new I2PDatagramMaker that will be able to create I2P
|
||||
@@ -45,8 +45,8 @@ public final class I2PDatagramMaker {
|
||||
* @param session I2PSession used to send I2PDatagrams through
|
||||
*/
|
||||
public I2PDatagramMaker(I2PSession session) {
|
||||
sxPrivKey = session.getPrivateKey();
|
||||
sxDestBytes = session.getMyDestination().toByteArray();
|
||||
this();
|
||||
this.setI2PDatagramMaker(session);
|
||||
}
|
||||
/**
|
||||
* Construct a new I2PDatagramMaker that is null.
|
||||
@@ -70,12 +70,12 @@ public final class I2PDatagramMaker {
|
||||
|
||||
try {
|
||||
sxDGram.write(sxDestBytes);
|
||||
|
||||
|
||||
dsaEng.sign(hashGen.calculateHash(payload).toByteArray(),
|
||||
sxPrivKey).writeBytes(sxDGram);
|
||||
|
||||
|
||||
sxDGram.write(payload);
|
||||
|
||||
|
||||
return sxDGram.toByteArray();
|
||||
} catch (IOException e) {
|
||||
_log.error("Caught IOException", e);
|
||||
|
||||
@@ -16,10 +16,10 @@ package net.i2p.client.datagram;
|
||||
public class I2PInvalidDatagramException extends Exception {
|
||||
|
||||
public I2PInvalidDatagramException() {
|
||||
super();
|
||||
super();
|
||||
}
|
||||
|
||||
public I2PInvalidDatagramException(String s) {
|
||||
super(s);
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public class CryptixAESEngine extends AESEngine {
|
||||
@Override
|
||||
public final void decryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte rv[], int outIndex) {
|
||||
if ( (payload == null) || (rv == null) )
|
||||
throw new IllegalArgumentException("null block args [payload=" + payload + " rv="+rv);
|
||||
throw new IllegalArgumentException("null block args");
|
||||
if (payload.length - inIndex > rv.length - outIndex)
|
||||
throw new IllegalArgumentException("bad block args [payload.len=" + payload.length
|
||||
+ " inIndex=" + inIndex + " rv.len=" + rv.length
|
||||
|
||||
@@ -82,7 +82,9 @@ public class DHSessionKeyBuilder {
|
||||
|
||||
// add to the defaults for every 128MB of RAM, up to 512MB
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
int factor = Math.min(4, (int) (1 + (maxMemory / (128*1024*1024l))));
|
||||
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);
|
||||
|
||||
@@ -10,6 +10,7 @@ package net.i2p.crypto;
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -527,8 +528,6 @@ public class ElGamalAESEngine {
|
||||
return aesEncr;
|
||||
}
|
||||
|
||||
private final static Set EMPTY_SET = new HashSet();
|
||||
|
||||
/**
|
||||
* For both scenarios, this method encrypts the AES area using the given key, iv
|
||||
* and making sure the resulting data is at least as long as the paddedSize and
|
||||
@@ -552,7 +551,7 @@ public class ElGamalAESEngine {
|
||||
long paddedSize, int prefixBytes) {
|
||||
//_log.debug("iv for encryption: " + DataHelper.toString(iv, 16));
|
||||
//_log.debug("Encrypting AES");
|
||||
if (tagsForDelivery == null) tagsForDelivery = EMPTY_SET;
|
||||
if (tagsForDelivery == null) tagsForDelivery = Collections.EMPTY_SET;
|
||||
int size = 2 // sizeof(tags)
|
||||
+ tagsForDelivery.size()
|
||||
+ SessionTag.BYTE_LENGTH*tagsForDelivery.size()
|
||||
|
||||
@@ -23,13 +23,18 @@ public final class SHA256Generator {
|
||||
return I2PAppContext.getGlobalContext().sha();
|
||||
}
|
||||
|
||||
/** Calculate the SHA-256 has of the source
|
||||
/**
|
||||
* Calculate the SHA-256 hash of the source and cache the result.
|
||||
* @param source what to hash
|
||||
* @return hash of the source
|
||||
*/
|
||||
public final Hash calculateHash(byte[] source) {
|
||||
return calculateHash(source, 0, source.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hash and cache the result.
|
||||
*/
|
||||
public final Hash calculateHash(byte[] source, int start, int len) {
|
||||
Sha256Standalone digest = acquireGnu();
|
||||
digest.update(source, start, len);
|
||||
@@ -39,6 +44,10 @@ public final class SHA256Generator {
|
||||
return Hash.create(rv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this if you only need the data, not a Hash object.
|
||||
* Does not cache.
|
||||
*/
|
||||
public final void calculateHash(byte[] source, int start, int len, byte out[], int outOffset) {
|
||||
Sha256Standalone digest = acquireGnu();
|
||||
digest.update(source, start, len);
|
||||
|
||||
@@ -60,7 +60,9 @@ class YKGenerator {
|
||||
|
||||
// add to the defaults for every 128MB of RAM, up to 1GB
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
int factor = Math.min(8, (int) (1 + (maxMemory / (128*1024*1024l))));
|
||||
if (maxMemory == Long.MAX_VALUE)
|
||||
maxMemory = 127*1024*1024l;
|
||||
int factor = (int) Math.max(1l, Math.min(8l, 1 + (maxMemory / (128*1024*1024l))));
|
||||
int defaultMin = DEFAULT_YK_PRECALC_MIN * factor;
|
||||
int defaultMax = DEFAULT_YK_PRECALC_MAX * factor;
|
||||
MIN_NUM_BUILDERS = ctx.getProperty(PROP_YK_PRECALC_MIN, defaultMin);
|
||||
|
||||
@@ -72,13 +72,13 @@ public class Base32 {
|
||||
}
|
||||
|
||||
private static void runApp(String args[]) {
|
||||
if ("encodestring".equalsIgnoreCase(args[0])) {
|
||||
System.out.println(encode(args[1].getBytes()));
|
||||
return;
|
||||
}
|
||||
InputStream in = System.in;
|
||||
OutputStream out = System.out;
|
||||
try {
|
||||
if ("encodestring".equalsIgnoreCase(args[0])) {
|
||||
System.out.println(encode(args[1].getBytes()));
|
||||
return;
|
||||
}
|
||||
InputStream in = System.in;
|
||||
OutputStream out = System.out;
|
||||
if (args.length >= 3) {
|
||||
out = new FileOutputStream(args[2]);
|
||||
}
|
||||
@@ -95,6 +95,9 @@ public class Base32 {
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace(System.err);
|
||||
} finally {
|
||||
try { in.close(); } catch (IOException e) {}
|
||||
try { out.close(); } catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -178,13 +178,13 @@ public class Base64 {
|
||||
}
|
||||
|
||||
private static void runApp(String args[]) {
|
||||
if ("encodestring".equalsIgnoreCase(args[0])) {
|
||||
System.out.println(encode(args[1].getBytes()));
|
||||
return;
|
||||
}
|
||||
InputStream in = System.in;
|
||||
OutputStream out = System.out;
|
||||
try {
|
||||
if ("encodestring".equalsIgnoreCase(args[0])) {
|
||||
System.out.println(encode(args[1].getBytes()));
|
||||
return;
|
||||
}
|
||||
InputStream in = System.in;
|
||||
OutputStream out = System.out;
|
||||
if (args.length >= 3) {
|
||||
out = new FileOutputStream(args[2]);
|
||||
}
|
||||
@@ -201,6 +201,9 @@ public class Base64 {
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace(System.err);
|
||||
} finally {
|
||||
try { in.close(); } catch (IOException e) {}
|
||||
try { out.close(); } catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ public class ByteArray implements Serializable, Comparable {
|
||||
public ByteArray() {
|
||||
}
|
||||
|
||||
/** Sets valid */
|
||||
public ByteArray(byte[] data) {
|
||||
_data = data;
|
||||
_valid = (data != null ? data.length : 0);
|
||||
@@ -38,6 +39,7 @@ public class ByteArray implements Serializable, Comparable {
|
||||
return _data;
|
||||
}
|
||||
|
||||
/** Warning, does not set valid */
|
||||
public void setData(byte[] data) {
|
||||
_data = data;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class Certificate extends DataStructureImpl {
|
||||
public final static int CERTIFICATE_TYPE_MULTIPLE = 4;
|
||||
|
||||
/**
|
||||
* Pull from cache or return new
|
||||
* If null cert, return immutable static instance, else create new
|
||||
* @throws AIOOBE if not enough bytes
|
||||
* @since 0.8.3
|
||||
*/
|
||||
@@ -57,7 +57,7 @@ public class Certificate extends DataStructureImpl {
|
||||
if (length == 0)
|
||||
return new Certificate(type, null);
|
||||
byte[] payload = new byte[length];
|
||||
System.arraycopy(data, off = 3, payload, 0, length);
|
||||
System.arraycopy(data, off + 3, payload, 0, length);
|
||||
return new Certificate(type, payload);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -178,6 +179,7 @@ public class DataHelper {
|
||||
* @param props source
|
||||
* @return new offset
|
||||
*/
|
||||
@Deprecated
|
||||
public static int toProperties(byte target[], int offset, Properties props) throws DataFormatException, IOException {
|
||||
if (props != null) {
|
||||
OrderedProperties p = new OrderedProperties();
|
||||
@@ -218,6 +220,7 @@ public class DataHelper {
|
||||
* @param target returned Properties
|
||||
* @return new offset
|
||||
*/
|
||||
@Deprecated
|
||||
public static int fromProperties(byte source[], int offset, Properties target) throws DataFormatException, IOException {
|
||||
int size = (int)fromLong(source, offset, 2);
|
||||
offset += 2;
|
||||
@@ -253,6 +256,7 @@ public class DataHelper {
|
||||
*
|
||||
* @throws RuntimeException if either is too long.
|
||||
*/
|
||||
@Deprecated
|
||||
public static byte[] toProperties(Properties opts) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(2);
|
||||
@@ -543,6 +547,7 @@ public class DataHelper {
|
||||
}
|
||||
|
||||
/** @deprecated unused */
|
||||
@Deprecated
|
||||
public static byte[] toDate(Date date) throws IllegalArgumentException {
|
||||
if (date == null)
|
||||
return toLong(DATE_LENGTH, 0L);
|
||||
@@ -677,6 +682,7 @@ public class DataHelper {
|
||||
* @throws IOException if there is an IO error writing the boolean
|
||||
* @deprecated unused
|
||||
*/
|
||||
@Deprecated
|
||||
public static void writeBoolean(OutputStream out, Boolean bool)
|
||||
throws DataFormatException, IOException {
|
||||
if (bool == null)
|
||||
@@ -688,6 +694,7 @@ public class DataHelper {
|
||||
}
|
||||
|
||||
/** @deprecated unused */
|
||||
@Deprecated
|
||||
public static Boolean fromBoolean(byte data[], int offset) {
|
||||
if (data[offset] == BOOLEAN_TRUE)
|
||||
return Boolean.TRUE;
|
||||
@@ -698,11 +705,13 @@ public class DataHelper {
|
||||
}
|
||||
|
||||
/** @deprecated unused */
|
||||
@Deprecated
|
||||
public static void toBoolean(byte data[], int offset, boolean value) {
|
||||
data[offset] = (value ? BOOLEAN_TRUE : BOOLEAN_FALSE);
|
||||
}
|
||||
|
||||
/** @deprecated unused */
|
||||
@Deprecated
|
||||
public static void toBoolean(byte data[], int offset, Boolean value) {
|
||||
if (value == null)
|
||||
data[offset] = BOOLEAN_UNKNOWN;
|
||||
@@ -711,12 +720,16 @@ public class DataHelper {
|
||||
}
|
||||
|
||||
/** deprecated - used only in DatabaseLookupMessage */
|
||||
@Deprecated
|
||||
public static final byte BOOLEAN_TRUE = 0x1;
|
||||
/** deprecated - used only in DatabaseLookupMessage */
|
||||
@Deprecated
|
||||
public static final byte BOOLEAN_FALSE = 0x0;
|
||||
/** @deprecated unused */
|
||||
@Deprecated
|
||||
public static final byte BOOLEAN_UNKNOWN = 0x2;
|
||||
/** @deprecated unused */
|
||||
@Deprecated
|
||||
public static final int BOOLEAN_LENGTH = 1;
|
||||
|
||||
//
|
||||
@@ -768,17 +781,17 @@ public class DataHelper {
|
||||
* This treats (null == null) as true, (null == (!null)) as false,
|
||||
* and unequal length arrays as false.
|
||||
*
|
||||
* @return Arrays.equals(lhs, rhs)
|
||||
*/
|
||||
public final static boolean eq(byte lhs[], byte rhs[]) {
|
||||
// this appears to be the way Arrays.equals is defined, so all the extra tests are unnecessary?
|
||||
boolean eq = (((lhs == null) && (rhs == null)) || ((lhs != null) && (rhs != null) && (Arrays.equals(lhs, rhs))));
|
||||
return eq;
|
||||
return Arrays.equals(lhs, rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two integers, really just for consistency.
|
||||
* @deprecated inefficient
|
||||
*/
|
||||
@Deprecated
|
||||
public final static boolean eq(int lhs, int rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
@@ -787,6 +800,7 @@ public class DataHelper {
|
||||
* Compare two longs, really just for consistency.
|
||||
* @deprecated inefficient
|
||||
*/
|
||||
@Deprecated
|
||||
public final static boolean eq(long lhs, long rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
@@ -795,6 +809,7 @@ public class DataHelper {
|
||||
* Compare two bytes, really just for consistency.
|
||||
* @deprecated inefficient
|
||||
*/
|
||||
@Deprecated
|
||||
public final static boolean eq(byte lhs, byte rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
@@ -844,7 +859,7 @@ public class DataHelper {
|
||||
*/
|
||||
public final static void xor(byte lhs[], int startLeft, byte rhs[], int startRight, byte out[], int startOut, int len) {
|
||||
if ( (lhs == null) || (rhs == null) || (out == null) )
|
||||
throw new NullPointerException("Invalid params to xor (" + lhs + ", " + rhs + ", " + out + ")");
|
||||
throw new NullPointerException("Null params to xor");
|
||||
if (lhs.length < startLeft + len)
|
||||
throw new IllegalArgumentException("Left hand side is too short");
|
||||
if (rhs.length < startRight + len)
|
||||
@@ -973,6 +988,7 @@ public class DataHelper {
|
||||
* @return true if the line was read, false if eof was reached before a
|
||||
* newline was found
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean readLine(InputStream in, StringBuffer buf) throws IOException {
|
||||
return readLine(in, buf, null);
|
||||
}
|
||||
@@ -986,6 +1002,7 @@ public class DataHelper {
|
||||
* Warning - 8KB line length limit as of 0.7.13, @throws IOException if exceeded
|
||||
* @deprecated use StringBuilder version
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean readLine(InputStream in, StringBuffer buf, Sha256Standalone hash) throws IOException {
|
||||
int c = -1;
|
||||
int i = 0;
|
||||
@@ -1040,25 +1057,45 @@ public class DataHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort based on the Hash of the DataStructure
|
||||
* Sort based on the Hash of the DataStructure.
|
||||
* Warning - relatively slow.
|
||||
* Only used by RouterInfo
|
||||
* Why? Just because it has to be consistent so signing will work?
|
||||
* WARNING - this sort order must be consistent network-wide, so while the order is arbitrary,
|
||||
* it cannot be changed.
|
||||
* Why? Just because it has to be consistent so signing will work.
|
||||
* How to spec as returning the same type as the param?
|
||||
* DEPRECATED - Only used by RouterInfo.
|
||||
*/
|
||||
public static List<? extends DataStructure> sortStructures(Collection<? extends DataStructure> dataStructures) {
|
||||
if (dataStructures == null) return Collections.EMPTY_LIST;
|
||||
ArrayList<DataStructure> rv = new ArrayList(dataStructures.size());
|
||||
TreeMap<String, DataStructure> tm = new TreeMap();
|
||||
for (DataStructure struct : dataStructures) {
|
||||
tm.put(struct.calculateHash().toString(), struct);
|
||||
}
|
||||
for (DataStructure struct : tm.values()) {
|
||||
rv.add(struct);
|
||||
}
|
||||
|
||||
// This used to use Hash.toString(), which is insane, since a change to toString()
|
||||
// would break the whole network. Now use Hash.toBase64().
|
||||
// Note that the Base64 sort order is NOT the same as the raw byte sort order,
|
||||
// despite what you may read elsewhere.
|
||||
|
||||
//ArrayList<DataStructure> rv = new ArrayList(dataStructures.size());
|
||||
//TreeMap<String, DataStructure> tm = new TreeMap();
|
||||
//for (DataStructure struct : dataStructures) {
|
||||
// tm.put(struct.calculateHash().toString(), struct);
|
||||
//}
|
||||
//for (DataStructure struct : tm.values()) {
|
||||
// rv.add(struct);
|
||||
//}
|
||||
ArrayList<DataStructure> rv = new ArrayList(dataStructures);
|
||||
Collections.sort(rv, new DataStructureComparator());
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* See sortStructures() comments.
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private static class DataStructureComparator implements Comparator<DataStructure> {
|
||||
public int compare(DataStructure l, DataStructure r) {
|
||||
return l.calculateHash().toBase64().compareTo(r.calculateHash().toBase64());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: formatDuration2() recommended in most cases for readability
|
||||
*/
|
||||
@@ -1157,6 +1194,10 @@ public class DataHelper {
|
||||
case 2: return str + "M";
|
||||
case 3: return str + "G";
|
||||
case 4: return str + "T";
|
||||
case 5: return str + "P";
|
||||
case 6: return str + "E";
|
||||
case 7: return str + "Z";
|
||||
case 8: return str + "Y";
|
||||
default: return bytes + "";
|
||||
}
|
||||
}
|
||||
@@ -1183,12 +1224,17 @@ public class DataHelper {
|
||||
case 2: return str + " M";
|
||||
case 3: return str + " G";
|
||||
case 4: return str + " T";
|
||||
case 5: return str + " P";
|
||||
case 6: return str + " E";
|
||||
case 7: return str + " Z";
|
||||
case 8: return str + " Y";
|
||||
default: return bytes + " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip out any HTML (simply removing any less than / greater than symbols)
|
||||
* @param orig may be null, returns empty string if null
|
||||
*/
|
||||
public static String stripHTML(String orig) {
|
||||
if (orig == null) return "";
|
||||
|
||||
139
core/java/src/net/i2p/data/DateAndFlags.java
Normal file
139
core/java/src/net/i2p/data/DateAndFlags.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package net.i2p.data;
|
||||
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* A six-byte Date and 2 bytes of flags, since a Date won't encroach
|
||||
* on the top two bytes until the year 10889.
|
||||
*
|
||||
* The flag format is not specified here. The bits may be used in
|
||||
* an application-specific manner. The application should
|
||||
* be designed so that a flags value of 0 is the default, for
|
||||
* compatibility with an 8-byte Date.
|
||||
*
|
||||
* If we really need some more bits we could use the first few bits
|
||||
* of the third byte.
|
||||
*
|
||||
* @author zzz
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public class DateAndFlags extends DataStructureImpl {
|
||||
private int _flags;
|
||||
private long _date;
|
||||
|
||||
public DateAndFlags() {}
|
||||
|
||||
/**
|
||||
* @param flags 0 - 65535
|
||||
*/
|
||||
public DateAndFlags(long date, int flags) {
|
||||
_flags = flags;
|
||||
_date = date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param flags 0 - 65535
|
||||
*/
|
||||
public DateAndFlags(Date date, int flags) {
|
||||
_flags = flags;
|
||||
_date = date.getTime();
|
||||
}
|
||||
|
||||
public int getFlags() {
|
||||
return _flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param flags 0 - 65535
|
||||
*/
|
||||
public void setFlags(int flags) {
|
||||
_flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Date object is created here, it is not cached.
|
||||
* Use getTime() if you only need the long value.
|
||||
*/
|
||||
public Date getDate() {
|
||||
return new Date(_date);
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return (_date);
|
||||
}
|
||||
|
||||
public void setDate(long date) {
|
||||
_date = date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
_date = date.getTime();
|
||||
}
|
||||
|
||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||
_flags = (int) DataHelper.readLong(in, 2);
|
||||
_date = DataHelper.readLong(in, 6);
|
||||
}
|
||||
|
||||
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
||||
DataHelper.writeLong(out, 2, _flags);
|
||||
DataHelper.writeLong(out, 6, _date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden for efficiency.
|
||||
*/
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
byte[] rv = DataHelper.toLong(8, _date);
|
||||
rv[0] = (byte) ((_flags >> 8) & 0xff);
|
||||
rv[1] = (byte) (_flags & 0xff);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden for efficiency.
|
||||
* @param data non-null
|
||||
* @throws DataFormatException if null or wrong length
|
||||
*/
|
||||
@Override
|
||||
public void fromByteArray(byte data[]) throws DataFormatException {
|
||||
if (data == null) throw new DataFormatException("Null data passed in");
|
||||
if (data.length != 8) throw new DataFormatException("Bad data length");
|
||||
_flags = (int) DataHelper.fromLong(data, 0, 2);
|
||||
_date = DataHelper.fromLong(data, 2, 6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if ((object == null) || !(object instanceof DateAndFlags)) return false;
|
||||
DateAndFlags daf = (DateAndFlags) object;
|
||||
return _date == daf._date && _flags == daf._flags;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return _flags + (int) _date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(64);
|
||||
buf.append("[DateAndFlags: ");
|
||||
buf.append("\n\tDate: ").append((new Date(_date)).toString());
|
||||
buf.append("\n\tFlags: 0x").append(Integer.toHexString(_flags));
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,9 @@ import net.i2p.crypto.KeyGenerator;
|
||||
* A private key is 256byte Integer. The private key represents only the
|
||||
* exponent, not the primes, which are constant and defined in the crypto spec.
|
||||
*
|
||||
* Note that we use short exponents, so all but the last 28.25 bytes are zero.
|
||||
* See http://www.i2p2.i2p/how_cryptography for details.
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
public class PrivateKey extends SimpleDataStructure {
|
||||
@@ -50,4 +53,24 @@ public class PrivateKey extends SimpleDataStructure {
|
||||
return KeyGenerator.getPublicKey(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* We assume the data has enough randomness in it, so use the last 4 bytes for speed.
|
||||
* Overridden since we use short exponents, so the first 227 bytes are all zero.
|
||||
* Not that we are storing PrivateKeys in any Sets or Maps anywhere.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (_data == null)
|
||||
return 0;
|
||||
int rv = _data[KEYSIZE_BYTES - 4];
|
||||
for (int i = 1; i < 4; i++)
|
||||
rv ^= (_data[i + (KEYSIZE_BYTES - 4)] << (i*8));
|
||||
return rv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ((obj == null) || !(obj instanceof PrivateKey)) return false;
|
||||
return DataHelper.eq(_data, ((PrivateKey) obj)._data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,9 +133,15 @@ public class PrivateKeyFile {
|
||||
*/
|
||||
public Destination createIfAbsent() throws I2PException, IOException, DataFormatException {
|
||||
if(!this.file.exists()) {
|
||||
FileOutputStream out = new FileOutputStream(this.file);
|
||||
this.client.createDestination(out);
|
||||
out.close();
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(this.file);
|
||||
this.client.createDestination(out);
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return getDestination();
|
||||
}
|
||||
@@ -243,29 +249,36 @@ public class PrivateKeyFile {
|
||||
public I2PSession open() throws I2PSessionException, IOException {
|
||||
return this.open(new Properties());
|
||||
}
|
||||
|
||||
public I2PSession open(Properties opts) throws I2PSessionException, IOException {
|
||||
// open input file
|
||||
FileInputStream in = new FileInputStream(this.file);
|
||||
|
||||
// create sesssion
|
||||
I2PSession s = this.client.createSession(in, opts);
|
||||
|
||||
// close file
|
||||
in.close();
|
||||
|
||||
return s;
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(this.file);
|
||||
I2PSession s = this.client.createSession(in, opts);
|
||||
return s;
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from I2PClientImpl.createDestination()
|
||||
*/
|
||||
public void write() throws IOException, DataFormatException {
|
||||
FileOutputStream out = new FileOutputStream(this.file);
|
||||
this.dest.writeBytes(out);
|
||||
this.privKey.writeBytes(out);
|
||||
this.signingPrivKey.writeBytes(out);
|
||||
out.flush();
|
||||
out.close();
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(this.file);
|
||||
this.dest.writeBytes(out);
|
||||
this.privKey.writeBytes(out);
|
||||
this.signingPrivKey.writeBytes(out);
|
||||
out.flush();
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -377,7 +390,8 @@ public class PrivateKeyFile {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ioe) {
|
||||
} catch (DataFormatException dfe) {
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
// not found, continue to the next file
|
||||
}
|
||||
|
||||
@@ -131,10 +131,13 @@ public class RouterAddress extends DataStructureImpl {
|
||||
&& DataHelper.eq(_transportStyle, addr.getTransportStyle());
|
||||
}
|
||||
|
||||
/** the style should be sufficient, for speed */
|
||||
/**
|
||||
* Just use style and hashCode for speed (expiration is always null).
|
||||
* If we add multiple addresses of the same style, this may need to be changed.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return DataHelper.hashCode(_transportStyle);
|
||||
return DataHelper.hashCode(_transportStyle) ^ _cost;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -39,7 +40,8 @@ public class RouterInfo extends DatabaseEntry {
|
||||
private RouterIdentity _identity;
|
||||
private volatile long _published;
|
||||
private final Set<RouterAddress> _addresses;
|
||||
private final Set<Hash> _peers;
|
||||
/** may be null to save memory, no longer final */
|
||||
private Set<Hash> _peers;
|
||||
private /* FIXME final FIXME */ Properties _options;
|
||||
private volatile boolean _validated;
|
||||
private volatile boolean _isValid;
|
||||
@@ -47,6 +49,11 @@ public class RouterInfo extends DatabaseEntry {
|
||||
private volatile byte _byteified[];
|
||||
private volatile int _hashCode;
|
||||
private volatile boolean _hashCodeInitialized;
|
||||
/** should we cache the byte and string versions _byteified ? **/
|
||||
private boolean _shouldCache;
|
||||
/** maybe we should check if we are floodfill? */
|
||||
private static final boolean CACHE_ALL = Runtime.getRuntime().maxMemory() > 128*1024*1024l &&
|
||||
Runtime.getRuntime().maxMemory() < Long.MAX_VALUE;
|
||||
|
||||
public static final String PROP_NETWORK_ID = "netId";
|
||||
public static final String PROP_CAPABILITIES = "caps";
|
||||
@@ -58,7 +65,6 @@ public class RouterInfo extends DatabaseEntry {
|
||||
|
||||
public RouterInfo() {
|
||||
_addresses = new HashSet(2);
|
||||
_peers = new HashSet(0);
|
||||
_options = new OrderedProperties();
|
||||
}
|
||||
|
||||
@@ -70,6 +76,7 @@ public class RouterInfo extends DatabaseEntry {
|
||||
setPeers(old.getPeers());
|
||||
setOptions(old.getOptions());
|
||||
setSignature(old.getSignature());
|
||||
// copy over _byteified?
|
||||
}
|
||||
|
||||
public long getDate() {
|
||||
@@ -105,6 +112,11 @@ public class RouterInfo extends DatabaseEntry {
|
||||
public void setIdentity(RouterIdentity ident) {
|
||||
_identity = ident;
|
||||
resetCache();
|
||||
// We only want to cache the bytes for our own RI, which is frequently written.
|
||||
// To cache for all RIs doubles the RI memory usage.
|
||||
// setIdentity() is only called when we are creating our own RI.
|
||||
// Otherwise, the data is populated with readBytes().
|
||||
_shouldCache = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,6 +171,8 @@ public class RouterInfo extends DatabaseEntry {
|
||||
* @deprecated Implemented here but unused elsewhere
|
||||
*/
|
||||
public Set<Hash> getPeers() {
|
||||
if (_peers == null)
|
||||
return Collections.EMPTY_SET;
|
||||
return _peers;
|
||||
}
|
||||
|
||||
@@ -169,9 +183,15 @@ public class RouterInfo extends DatabaseEntry {
|
||||
* @deprecated Implemented here but unused elsewhere
|
||||
*/
|
||||
public void setPeers(Set<Hash> peers) {
|
||||
if (peers == null || peers.isEmpty()) {
|
||||
_peers = null;
|
||||
return;
|
||||
}
|
||||
if (_peers == null)
|
||||
_peers = new HashSet(2);
|
||||
synchronized (_peers) {
|
||||
_peers.clear();
|
||||
if (peers != null) _peers.addAll(peers);
|
||||
_peers.addAll(peers);
|
||||
}
|
||||
resetCache();
|
||||
}
|
||||
@@ -223,7 +243,6 @@ public class RouterInfo extends DatabaseEntry {
|
||||
if (_byteified != null) return _byteified;
|
||||
if (_identity == null) throw new DataFormatException("Router identity isn't set? wtf!");
|
||||
if (_addresses == null) throw new DataFormatException("Router addressess isn't set? wtf!");
|
||||
if (_peers == null) throw new DataFormatException("Router peers isn't set? wtf!");
|
||||
if (_options == null) throw new DataFormatException("Router options isn't set? wtf!");
|
||||
|
||||
long before = Clock.getInstance().now();
|
||||
@@ -239,6 +258,9 @@ public class RouterInfo extends DatabaseEntry {
|
||||
DataHelper.writeLong(out, 1, sz);
|
||||
Collection<RouterAddress> addresses = _addresses;
|
||||
if (sz > 1)
|
||||
// WARNING this sort algorithm cannot be changed, as it must be consistent
|
||||
// network-wide. The signature is not checked at readin time, but only
|
||||
// later, and the addresses are stored in a Set, not a List.
|
||||
addresses = (Collection<RouterAddress>) DataHelper.sortStructures(addresses);
|
||||
for (RouterAddress addr : addresses) {
|
||||
addr.writeBytes(out);
|
||||
@@ -248,12 +270,14 @@ public class RouterInfo extends DatabaseEntry {
|
||||
// answer: they're always empty... they're a placeholder for one particular
|
||||
// method of trusted links, which isn't implemented in the router
|
||||
// at the moment, and may not be later.
|
||||
// fixme to reduce objects - allow _peers == null
|
||||
int psz = _peers.size();
|
||||
int psz = _peers == null ? 0 : _peers.size();
|
||||
DataHelper.writeLong(out, 1, psz);
|
||||
if (psz > 0) {
|
||||
Collection<Hash> peers = _peers;
|
||||
if (psz > 1)
|
||||
// WARNING this sort algorithm cannot be changed, as it must be consistent
|
||||
// network-wide. The signature is not checked at readin time, but only
|
||||
// later, and the hashes are stored in a Set, not a List.
|
||||
peers = (Collection<Hash>) DataHelper.sortStructures(peers);
|
||||
for (Hash peerHash : peers) {
|
||||
peerHash.writeBytes(out);
|
||||
@@ -266,7 +290,8 @@ public class RouterInfo extends DatabaseEntry {
|
||||
byte data[] = out.toByteArray();
|
||||
long after = Clock.getInstance().now();
|
||||
_log.debug("getBytes() took " + (after - before) + "ms");
|
||||
_byteified = data;
|
||||
if (CACHE_ALL || _shouldCache)
|
||||
_byteified = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -466,10 +491,15 @@ public class RouterInfo extends DatabaseEntry {
|
||||
_addresses.add(address);
|
||||
}
|
||||
int numPeers = (int) DataHelper.readLong(in, 1);
|
||||
for (int i = 0; i < numPeers; i++) {
|
||||
Hash peerIdentityHash = new Hash();
|
||||
peerIdentityHash.readBytes(in);
|
||||
_peers.add(peerIdentityHash);
|
||||
if (numPeers == 0) {
|
||||
_peers = null;
|
||||
} else {
|
||||
_peers = new HashSet(numPeers);
|
||||
for (int i = 0; i < numPeers; i++) {
|
||||
Hash peerIdentityHash = new Hash();
|
||||
peerIdentityHash.readBytes(in);
|
||||
_peers.add(peerIdentityHash);
|
||||
}
|
||||
}
|
||||
_options = DataHelper.readProperties(in);
|
||||
_signature = new Signature();
|
||||
@@ -504,7 +534,7 @@ public class RouterInfo extends DatabaseEntry {
|
||||
&& _published == info.getPublished()
|
||||
&& DataHelper.eq(_addresses, info.getAddresses())
|
||||
&& DataHelper.eq(_options, info.getOptions())
|
||||
&& DataHelper.eq(_peers, info.getPeers());
|
||||
&& DataHelper.eq(getPeers(), info.getPeers());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -530,7 +560,7 @@ public class RouterInfo extends DatabaseEntry {
|
||||
RouterAddress addr = (RouterAddress) iter.next();
|
||||
buf.append("\n\t\tAddress: ").append(addr);
|
||||
}
|
||||
Set peers = _peers; // getPeers()
|
||||
Set peers = getPeers();
|
||||
buf.append("\n\tPeers: #: ").append(peers.size());
|
||||
for (Iterator iter = peers.iterator(); iter.hasNext();) {
|
||||
Hash hash = (Hash) iter.next();
|
||||
|
||||
@@ -50,6 +50,8 @@ public class SDSCache<V extends SimpleDataStructure> {
|
||||
private static final double FACTOR;
|
||||
static {
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
if (maxMemory == Long.MAX_VALUE)
|
||||
maxMemory = 96*1024*1024l;
|
||||
FACTOR = Math.max(MIN_FACTOR, Math.min(MAX_FACTOR, maxMemory / (128*1024*1024d)));
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public abstract class SimpleDataStructure extends DataStructureImpl {
|
||||
|
||||
/**
|
||||
* Sets the data.
|
||||
* @param data of correct length, or null
|
||||
* @param in the stream to read
|
||||
* @throws RuntimeException if data already set.
|
||||
*/
|
||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||
|
||||
@@ -50,6 +50,26 @@ public class TunnelId extends DataStructureImpl {
|
||||
DataHelper.writeLong(out, 4, _tunnelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden for efficiency.
|
||||
*/
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return DataHelper.toLong(4, _tunnelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden for efficiency.
|
||||
* @param data non-null
|
||||
* @throws DataFormatException if null or wrong length
|
||||
*/
|
||||
@Override
|
||||
public void fromByteArray(byte data[]) throws DataFormatException {
|
||||
if (data == null) throw new DataFormatException("Null data passed in");
|
||||
if (data.length != 4) throw new DataFormatException("Bad data length");
|
||||
_tunnelId = (int) DataHelper.fromLong(data, 0, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( (obj == null) || !(obj instanceof TunnelId))
|
||||
|
||||
@@ -74,10 +74,11 @@ public class DestReplyMessage extends I2CPMessageImpl {
|
||||
}
|
||||
|
||||
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
|
||||
if (_dest == null && _hash == null)
|
||||
return new byte[0]; // null response allowed
|
||||
if (_dest == null && _hash != null)
|
||||
if (_dest == null) {
|
||||
if (_hash == null)
|
||||
return new byte[0]; // null response allowed
|
||||
return _hash.getData();
|
||||
}
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(_dest.size());
|
||||
try {
|
||||
_dest.writeBytes(os);
|
||||
|
||||
@@ -16,32 +16,66 @@ import java.util.Date;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.DateAndFlags;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Payload;
|
||||
|
||||
/**
|
||||
* Same as SendMessageMessage, but with an expiration to be passed to the router
|
||||
*
|
||||
* As of 0.8.4, retrofitted to use DateAndFlags. Backwards compatible.
|
||||
*
|
||||
* @author zzz
|
||||
*/
|
||||
public class SendMessageExpiresMessage extends SendMessageMessage {
|
||||
/* FIXME hides another field FIXME */
|
||||
public final static int MESSAGE_TYPE = 36;
|
||||
private SessionId _sessionId;
|
||||
private Destination _destination;
|
||||
private Payload _payload;
|
||||
private Date _expiration;
|
||||
private final DateAndFlags _daf;
|
||||
|
||||
public SendMessageExpiresMessage() {
|
||||
super();
|
||||
_daf = new DateAndFlags();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Date object is created here, it is not cached.
|
||||
* Use getExpirationTime() if you only need the long value.
|
||||
*/
|
||||
public Date getExpiration() {
|
||||
return _expiration;
|
||||
return _daf.getDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this instead of getExpiration().getTime()
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public long getExpirationTime() {
|
||||
return _daf.getTime();
|
||||
}
|
||||
|
||||
public void setExpiration(Date d) {
|
||||
_expiration = d;
|
||||
_daf.setDate(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void setExpiration(long d) {
|
||||
_daf.setDate(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public int getFlags() {
|
||||
return _daf.getFlags();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void setFlags(int f) {
|
||||
_daf.setFlags(f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +88,7 @@ public class SendMessageExpiresMessage extends SendMessageMessage {
|
||||
super.readMessage(in, length, type);
|
||||
|
||||
try {
|
||||
_expiration = DataHelper.readDate(in);
|
||||
_daf.readBytes(in);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2CPMessageException("Unable to load the message data", dfe);
|
||||
}
|
||||
@@ -68,7 +102,7 @@ public class SendMessageExpiresMessage extends SendMessageMessage {
|
||||
*/
|
||||
@Override
|
||||
public void writeMessage(OutputStream out) throws I2CPMessageException, IOException {
|
||||
if ((getSessionId() == null) || (getDestination() == null) || (getPayload() == null) || (getNonce() <= 0) || (_expiration == null))
|
||||
if ((getSessionId() == null) || (getDestination() == null) || (getPayload() == null) || (getNonce() <= 0))
|
||||
throw new I2CPMessageException("Unable to write out the message as there is not enough data");
|
||||
int len = 2 + getDestination().size() + getPayload().getSize() + 4 + 4 + DataHelper.DATE_LENGTH;
|
||||
|
||||
@@ -79,7 +113,7 @@ public class SendMessageExpiresMessage extends SendMessageMessage {
|
||||
getDestination().writeBytes(out);
|
||||
getPayload().writeBytes(out);
|
||||
DataHelper.writeLong(out, 4, getNonce());
|
||||
DataHelper.writeDate(out, _expiration);
|
||||
_daf.writeBytes(out);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2CPMessageException("Error writing the msg", dfe);
|
||||
}
|
||||
@@ -96,7 +130,7 @@ public class SendMessageExpiresMessage extends SendMessageMessage {
|
||||
if ((object != null) && (object instanceof SendMessageExpiresMessage)) {
|
||||
SendMessageExpiresMessage msg = (SendMessageExpiresMessage) object;
|
||||
return super.equals(object)
|
||||
&& DataHelper.eq(getExpiration(), msg.getExpiration());
|
||||
&& _daf.equals(msg._daf);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -5,7 +5,7 @@ import net.i2p.data.i2cp.I2CPMessageReader;
|
||||
import net.i2p.util.I2PThread;
|
||||
|
||||
/**
|
||||
* Get messages off an In-JVM queue, zero-copy
|
||||
* Get messages off an In-JVM queue, zero-copy.
|
||||
*
|
||||
* @author zzz
|
||||
* @since 0.8.3
|
||||
@@ -13,6 +13,9 @@ import net.i2p.util.I2PThread;
|
||||
public class QueuedI2CPMessageReader extends I2CPMessageReader {
|
||||
private final I2CPMessageQueue in;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this QueuedMessageReader and spawns a pumper thread.
|
||||
*/
|
||||
public QueuedI2CPMessageReader(I2CPMessageQueue in, I2CPMessageEventListener lsnr) {
|
||||
super(lsnr);
|
||||
this.in = in;
|
||||
@@ -25,13 +28,19 @@ public class QueuedI2CPMessageReader extends I2CPMessageReader {
|
||||
public QueuedI2CPMessageReaderRunner() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shuts the pumper down.
|
||||
*/
|
||||
@Override
|
||||
public void cancelRunner() {
|
||||
super.cancelRunner();
|
||||
_readerThread.interrupt();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pumps messages from the incoming message queue to the listener.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
while (_stayAlive) {
|
||||
@@ -40,11 +49,15 @@ public class QueuedI2CPMessageReader extends I2CPMessageReader {
|
||||
I2CPMessage msg = null;
|
||||
try {
|
||||
msg = in.take();
|
||||
if (msg.getType() == PoisonI2CPMessage.MESSAGE_TYPE)
|
||||
if (msg.getType() == PoisonI2CPMessage.MESSAGE_TYPE) {
|
||||
_listener.disconnected(QueuedI2CPMessageReader.this);
|
||||
cancelRunner();
|
||||
else
|
||||
} else {
|
||||
_listener.messageReceived(QueuedI2CPMessageReader.this, msg);
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
// hint that we probably should check the continue running flag
|
||||
}
|
||||
}
|
||||
// ??? unused
|
||||
if (_stayAlive && !_doRun) {
|
||||
|
||||
@@ -89,7 +89,7 @@ public class FrequencyStat {
|
||||
/** @since 0.8.2 */
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ((obj == null) || (obj.getClass() != FrequencyStat.class)) return false;
|
||||
if ((obj == null) || !(obj instanceof FrequencyStat)) return false;
|
||||
return _statName.equals(((FrequencyStat)obj)._statName);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package net.i2p.stat;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/** object orientation gives you hairy palms. */
|
||||
/**
|
||||
* Output rate data.
|
||||
* This is used via ProfilePersistenceHelper and the output
|
||||
* must be compatible.
|
||||
*/
|
||||
class PersistenceHelper {
|
||||
private final static Log _log = new Log(PersistenceHelper.class);
|
||||
private final static String NL = System.getProperty("line.separator");
|
||||
@@ -15,6 +21,18 @@ class PersistenceHelper {
|
||||
buf.append(prefix).append(name).append('=').append(value).append(NL).append(NL);
|
||||
}
|
||||
|
||||
/** @since 0.8.5 */
|
||||
public final static void addDate(StringBuilder buf, String prefix, String name, String description, long value) {
|
||||
String when = value > 0 ? (new Date(value)).toString() : "Never";
|
||||
add(buf, prefix, name, description + ' ' + when, value);
|
||||
}
|
||||
|
||||
/** @since 0.8.5 */
|
||||
public final static void addTime(StringBuilder buf, String prefix, String name, String description, long value) {
|
||||
String when = DataHelper.formatDuration(value);
|
||||
add(buf, prefix, name, description + ' ' + when, value);
|
||||
}
|
||||
|
||||
public final static void add(StringBuilder buf, String prefix, String name, String description, long value) {
|
||||
buf.append("# ").append(prefix).append(name).append(NL);
|
||||
buf.append("# ").append(description).append(NL);
|
||||
@@ -48,4 +66,4 @@ class PersistenceHelper {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.i2p.stat;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -399,42 +400,41 @@ public class Rate {
|
||||
}
|
||||
|
||||
public void store(String prefix, StringBuilder buf) throws IOException {
|
||||
PersistenceHelper.add(buf, prefix, ".period", "Number of milliseconds in the period", _period);
|
||||
PersistenceHelper.add(buf, prefix, ".creationDate",
|
||||
"When was this rate created? (milliseconds since the epoch, GMT)", _creationDate);
|
||||
PersistenceHelper.add(buf, prefix, ".lastCoalesceDate",
|
||||
"When did we last coalesce this rate? (milliseconds since the epoch, GMT)",
|
||||
PersistenceHelper.addTime(buf, prefix, ".period", "Length of the period:", _period);
|
||||
PersistenceHelper.addDate(buf, prefix, ".creationDate",
|
||||
"When was this rate created?", _creationDate);
|
||||
PersistenceHelper.addDate(buf, prefix, ".lastCoalesceDate",
|
||||
"When did we last coalesce this rate?",
|
||||
_lastCoalesceDate);
|
||||
PersistenceHelper.add(buf, prefix, ".currentDate",
|
||||
"When did this data get written? (milliseconds since the epoch, GMT)", now());
|
||||
PersistenceHelper.addDate(buf, prefix, ".currentDate",
|
||||
"When was this data written?", now());
|
||||
PersistenceHelper.add(buf, prefix, ".currentTotalValue",
|
||||
"Total value of data points in the current (uncoalesced) period", _currentTotalValue);
|
||||
PersistenceHelper
|
||||
.add(buf, prefix, ".currentEventCount",
|
||||
PersistenceHelper.add(buf, prefix, ".currentEventCount",
|
||||
"How many events have occurred in the current (uncoalesced) period?", _currentEventCount);
|
||||
PersistenceHelper.add(buf, prefix, ".currentTotalEventTime",
|
||||
"How many milliseconds have the events in the current (uncoalesced) period consumed?",
|
||||
PersistenceHelper.addTime(buf, prefix, ".currentTotalEventTime",
|
||||
"How much time have the events in the current (uncoalesced) period consumed?",
|
||||
_currentTotalEventTime);
|
||||
PersistenceHelper.add(buf, prefix, ".lastTotalValue",
|
||||
"Total value of data points in the most recent (coalesced) period", _lastTotalValue);
|
||||
PersistenceHelper.add(buf, prefix, ".lastEventCount",
|
||||
"How many events have occurred in the most recent (coalesced) period?", _lastEventCount);
|
||||
PersistenceHelper.add(buf, prefix, ".lastTotalEventTime",
|
||||
"How many milliseconds have the events in the most recent (coalesced) period consumed?",
|
||||
PersistenceHelper.addTime(buf, prefix, ".lastTotalEventTime",
|
||||
"How much time have the events in the most recent (coalesced) period consumed?",
|
||||
_lastTotalEventTime);
|
||||
PersistenceHelper.add(buf, prefix, ".extremeTotalValue",
|
||||
"Total value of data points in the most extreme period", _extremeTotalValue);
|
||||
PersistenceHelper.add(buf, prefix, ".extremeEventCount",
|
||||
"How many events have occurred in the most extreme period?", _extremeEventCount);
|
||||
PersistenceHelper.add(buf, prefix, ".extremeTotalEventTime",
|
||||
"How many milliseconds have the events in the most extreme period consumed?",
|
||||
PersistenceHelper.addTime(buf, prefix, ".extremeTotalEventTime",
|
||||
"How much time have the events in the most extreme period consumed?",
|
||||
_extremeTotalEventTime);
|
||||
PersistenceHelper.add(buf, prefix, ".lifetimeTotalValue",
|
||||
"Total value of data points since this stat was created", _lifetimeTotalValue);
|
||||
PersistenceHelper.add(buf, prefix, ".lifetimeEventCount",
|
||||
"How many events have occurred since this stat was created?", _lifetimeEventCount);
|
||||
PersistenceHelper.add(buf, prefix, ".lifetimeTotalEventTime",
|
||||
"How many milliseconds have the events since this stat was created consumed?",
|
||||
PersistenceHelper.addTime(buf, prefix, ".lifetimeTotalEventTime",
|
||||
"How much total time was consumed by the events since this stat was created?",
|
||||
_lifetimeTotalEventTime);
|
||||
}
|
||||
|
||||
@@ -471,48 +471,28 @@ public class Rate {
|
||||
coalesce();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used in StatSummarizer and SummaryListener.
|
||||
* We base it on the stat we are tracking, not the stored data.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ((obj == null) || (obj.getClass() != Rate.class)) return false;
|
||||
if ((obj == null) || !(obj instanceof Rate)) return false;
|
||||
if (obj == this) return true;
|
||||
Rate r = (Rate) obj;
|
||||
return _period == r.getPeriod() && _creationDate == r.getCreationDate() &&
|
||||
//_lastCoalesceDate == r.getLastCoalesceDate() &&
|
||||
_currentTotalValue == r.getCurrentTotalValue() && _currentEventCount == r.getCurrentEventCount()
|
||||
&& _currentTotalEventTime == r.getCurrentTotalEventTime() && _lastTotalValue == r.getLastTotalValue()
|
||||
&& _lastEventCount == r.getLastEventCount() && _lastTotalEventTime == r.getLastTotalEventTime()
|
||||
&& _extremeTotalValue == r.getExtremeTotalValue() && _extremeEventCount == r.getExtremeEventCount()
|
||||
&& _extremeTotalEventTime == r.getExtremeTotalEventTime()
|
||||
&& _lifetimeTotalValue == r.getLifetimeTotalValue() && _lifetimeEventCount == r.getLifetimeEventCount()
|
||||
&& _lifetimeTotalEventTime == r.getLifetimeTotalEventTime();
|
||||
// do this the easy way to avoid NPEs.
|
||||
// Alternative: compare name and group name (very carefully to avoid NPEs)
|
||||
_stat == r._stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* It doesn't appear that Rates are ever stored in a Set or Map
|
||||
* (RateStat stores in an array) so let's make this easy.
|
||||
* We can always make something faster if it's actually used.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
/*****
|
||||
int hash = 5;
|
||||
hash = 67 * hash + (int)(Double.doubleToLongBits(this._currentTotalValue) ^ (Double.doubleToLongBits(this._currentTotalValue) >>> 32));
|
||||
hash = 67 * hash + (int)(this._currentEventCount ^ (this._currentEventCount >>> 32));
|
||||
hash = 67 * hash + (int)(this._currentTotalEventTime ^ (this._currentTotalEventTime >>> 32));
|
||||
hash = 67 * hash + (int)(Double.doubleToLongBits(this._lastTotalValue) ^ (Double.doubleToLongBits(this._lastTotalValue) >>> 32));
|
||||
hash = 67 * hash + (int)(this._lastEventCount ^ (this._lastEventCount >>> 32));
|
||||
hash = 67 * hash + (int)(this._lastTotalEventTime ^ (this._lastTotalEventTime >>> 32));
|
||||
hash = 67 * hash + (int)(Double.doubleToLongBits(this._extremeTotalValue) ^ (Double.doubleToLongBits(this._extremeTotalValue) >>> 32));
|
||||
hash = 67 * hash + (int)(this._extremeEventCount ^ (this._extremeEventCount >>> 32));
|
||||
hash = 67 * hash + (int)(this._extremeTotalEventTime ^ (this._extremeTotalEventTime >>> 32));
|
||||
hash = 67 * hash + (int)(Double.doubleToLongBits(this._lifetimeTotalValue) ^ (Double.doubleToLongBits(this._lifetimeTotalValue) >>> 32));
|
||||
hash = 67 * hash + (int)(this._lifetimeEventCount ^ (this._lifetimeEventCount >>> 32));
|
||||
hash = 67 * hash + (int)(this._lifetimeTotalEventTime ^ (this._lifetimeTotalEventTime >>> 32));
|
||||
hash = 67 * hash + (int)(this._creationDate ^ (this._creationDate >>> 32));
|
||||
hash = 67 * hash + (int)(this._period ^ (this._period >>> 32));
|
||||
return hash;
|
||||
******/
|
||||
return toString().hashCode();
|
||||
return DataHelper.hashCode(_stat) ^ ((int)_period) ^ ((int) _creationDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -108,7 +108,7 @@ public class RateStat {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ((obj == null) || (obj.getClass() != RateStat.class)) return false;
|
||||
if ((obj == null) || !(obj instanceof RateStat)) return false;
|
||||
RateStat rs = (RateStat) obj;
|
||||
if (DataHelper.eq(getGroupName(), rs.getGroupName()) && DataHelper.eq(getDescription(), rs.getDescription())
|
||||
&& DataHelper.eq(getName(), rs.getName())) {
|
||||
|
||||
@@ -54,7 +54,7 @@ public class StatManager {
|
||||
"jobQueue.jobLag,netDb.successTime,peer.failedLookupRate,router.fastPeers," +
|
||||
"prng.bufferFillTime,prng.bufferWaitTime,router.memoryUsed," +
|
||||
"transport.receiveMessageSize,transport.sendMessageSize,transport.sendProcessingTime," +
|
||||
"tunnel.acceptLoad,tunnel.buildRequestTime,tunnel.rejectOverloaded,tunnel.rejectTimeout" +
|
||||
"tunnel.acceptLoad,tunnel.buildRequestTime,tunnel.rejectOverloaded,tunnel.rejectTimeout," +
|
||||
"tunnel.buildClientExpire,tunnel.buildClientReject,tunnel.buildClientSuccess," +
|
||||
"tunnel.buildExploratoryExpire,tunnel.buildExploratoryReject,tunnel.buildExploratorySuccess," +
|
||||
"tunnel.buildRatio.*,tunnel.corruptMessage,tunnel.dropLoad*," +
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.I2PThread;
|
||||
@@ -56,7 +57,7 @@ public class Timestamper implements Runnable {
|
||||
public Timestamper(I2PAppContext ctx, UpdateListener lsnr, boolean daemon) {
|
||||
// moved here to prevent problems with synchronized statements.
|
||||
_servers = new ArrayList(3);
|
||||
_listeners = new ArrayList(1);
|
||||
_listeners = new CopyOnWriteArrayList();
|
||||
// Don't bother starting a thread if we are disabled.
|
||||
// This means we no longer check every 5 minutes to see if we got enabled,
|
||||
// so the property must be set at startup.
|
||||
@@ -92,24 +93,16 @@ public class Timestamper implements Runnable {
|
||||
public boolean getIsDisabled() { return _disabled; }
|
||||
|
||||
public void addListener(UpdateListener lsnr) {
|
||||
synchronized (_listeners) {
|
||||
_listeners.add(lsnr);
|
||||
}
|
||||
}
|
||||
public void removeListener(UpdateListener lsnr) {
|
||||
synchronized (_listeners) {
|
||||
_listeners.remove(lsnr);
|
||||
}
|
||||
}
|
||||
public int getListenerCount() {
|
||||
synchronized (_listeners) {
|
||||
return _listeners.size();
|
||||
}
|
||||
}
|
||||
public UpdateListener getListener(int index) {
|
||||
synchronized (_listeners) {
|
||||
return _listeners.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
private void startTimestamper() {
|
||||
@@ -257,11 +250,8 @@ public class Timestamper implements Runnable {
|
||||
*/
|
||||
private void stampTime(long now, int stratum) {
|
||||
long before = _context.clock().now();
|
||||
synchronized (_listeners) {
|
||||
for (int i = 0; i < _listeners.size(); i++) {
|
||||
UpdateListener lsnr = _listeners.get(i);
|
||||
lsnr.setNow(now, stratum);
|
||||
}
|
||||
for (UpdateListener lsnr : _listeners) {
|
||||
lsnr.setNow(now, stratum);
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Stamped the time as " + now + " (delta=" + (now-before) + ")");
|
||||
|
||||
@@ -69,6 +69,8 @@ public final class ByteCache {
|
||||
private static final int MAX_CACHE;
|
||||
static {
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
if (maxMemory == Long.MAX_VALUE)
|
||||
maxMemory = 96*1024*1024l;
|
||||
MAX_CACHE = (int) Math.min(4*1024*1024l, Math.max(128*1024l, maxMemory / 128));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package net.i2p.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.time.Timestamper;
|
||||
@@ -19,19 +19,19 @@ import net.i2p.time.Timestamper;
|
||||
*
|
||||
*/
|
||||
public class Clock implements Timestamper.UpdateListener {
|
||||
protected I2PAppContext _context;
|
||||
private Timestamper _timestamper;
|
||||
protected long _startedOn;
|
||||
protected final I2PAppContext _context;
|
||||
private final Timestamper _timestamper;
|
||||
protected final long _startedOn;
|
||||
protected boolean _statCreated;
|
||||
protected volatile long _offset;
|
||||
protected boolean _alreadyChanged;
|
||||
private final Set _listeners;
|
||||
|
||||
public Clock(I2PAppContext context) {
|
||||
_context = context;
|
||||
_offset = 0;
|
||||
_alreadyChanged = false;
|
||||
_listeners = new HashSet(1);
|
||||
_listeners = new CopyOnWriteArraySet();
|
||||
_timestamper = new Timestamper(context, this);
|
||||
_startedOn = System.currentTimeMillis();
|
||||
_statCreated = false;
|
||||
}
|
||||
public static Clock getInstance() {
|
||||
return I2PAppContext.getGlobalContext().clock();
|
||||
@@ -41,10 +41,6 @@ public class Clock implements Timestamper.UpdateListener {
|
||||
|
||||
/** we fetch it on demand to avoid circular dependencies (logging uses the clock) */
|
||||
protected Log getLog() { return _context.logManager().getLog(Clock.class); }
|
||||
|
||||
protected volatile long _offset;
|
||||
protected boolean _alreadyChanged;
|
||||
private final Set _listeners;
|
||||
|
||||
/** if the clock is skewed by 3+ days, fuck 'em */
|
||||
public final static long MAX_OFFSET = 3 * 24 * 60 * 60 * 1000;
|
||||
@@ -53,14 +49,22 @@ public class Clock implements Timestamper.UpdateListener {
|
||||
/** if the clock skewed changes by less than this, ignore the update (so we don't slide all over the place) */
|
||||
public final static long MIN_OFFSET_CHANGE = 5 * 1000;
|
||||
|
||||
/**
|
||||
* Specify how far away from the "correct" time the computer is - a positive
|
||||
* value means that the system time is slow, while a negative value means the system time is fast.
|
||||
*
|
||||
* @param offsetMs the delta from System.currentTimeMillis() (NOT the delta from now())
|
||||
*/
|
||||
public void setOffset(long offsetMs) {
|
||||
setOffset(offsetMs, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify how far away from the "correct" time the computer is - a positive
|
||||
* value means that we are slow, while a negative value means we are fast.
|
||||
* value means that the system time is slow, while a negative value means the system time is fast.
|
||||
* Warning - overridden in RouterClock
|
||||
*
|
||||
* @param offsetMs the delta from System.currentTimeMillis() (NOT the delta from now())
|
||||
*/
|
||||
public void setOffset(long offsetMs, boolean force) {
|
||||
if (false) return;
|
||||
@@ -105,6 +109,9 @@ public class Clock implements Timestamper.UpdateListener {
|
||||
fireOffsetChanged(delta);
|
||||
}
|
||||
|
||||
/*
|
||||
* @return the current delta from System.currentTimeMillis() in milliseconds
|
||||
*/
|
||||
public long getOffset() {
|
||||
return _offset;
|
||||
}
|
||||
@@ -136,24 +143,18 @@ public class Clock implements Timestamper.UpdateListener {
|
||||
}
|
||||
|
||||
public void addUpdateListener(ClockUpdateListener lsnr) {
|
||||
synchronized (_listeners) {
|
||||
_listeners.add(lsnr);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeUpdateListener(ClockUpdateListener lsnr) {
|
||||
synchronized (_listeners) {
|
||||
_listeners.remove(lsnr);
|
||||
}
|
||||
}
|
||||
|
||||
protected void fireOffsetChanged(long delta) {
|
||||
synchronized (_listeners) {
|
||||
for (Iterator iter = _listeners.iterator(); iter.hasNext();) {
|
||||
ClockUpdateListener lsnr = (ClockUpdateListener) iter.next();
|
||||
lsnr.offsetChanged(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static interface ClockUpdateListener {
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public class ConcurrentHashSet<E> extends AbstractSet<E> implements Set<E> {
|
||||
private static final Object DUMMY = new Object();
|
||||
private Map<E, Object> _map;
|
||||
private final Map<E, Object> _map;
|
||||
|
||||
public ConcurrentHashSet() {
|
||||
_map = new ConcurrentHashMap();
|
||||
|
||||
@@ -20,28 +20,34 @@ import org.xlattice.crypto.filters.BloomSHA1;
|
||||
* Further analysis and tweaking for the tunnel IVV may be required.
|
||||
*/
|
||||
public class DecayingBloomFilter {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
protected final I2PAppContext _context;
|
||||
protected final Log _log;
|
||||
private BloomSHA1 _current;
|
||||
private BloomSHA1 _previous;
|
||||
private int _durationMs;
|
||||
private int _entryBytes;
|
||||
protected final int _durationMs;
|
||||
protected final int _entryBytes;
|
||||
private byte _extenders[][];
|
||||
private byte _extended[];
|
||||
private byte _longToEntry[];
|
||||
private long _longToEntryMask;
|
||||
protected long _currentDuplicates;
|
||||
private boolean _keepDecaying;
|
||||
private DecayEvent _decayEvent;
|
||||
protected volatile boolean _keepDecaying;
|
||||
protected SimpleTimer.TimedEvent _decayEvent;
|
||||
/** just for logging */
|
||||
private String _name;
|
||||
protected final String _name;
|
||||
|
||||
private static final int DEFAULT_M = 23;
|
||||
private static final int DEFAULT_K = 11;
|
||||
private static final boolean ALWAYS_MISS = false;
|
||||
|
||||
/** noop for DHS */
|
||||
public DecayingBloomFilter() {}
|
||||
/** only for extension by DHS */
|
||||
protected DecayingBloomFilter(int durationMs, int entryBytes, String name, I2PAppContext context) {
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(getClass());
|
||||
_entryBytes = entryBytes;
|
||||
_name = name;
|
||||
_durationMs = durationMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bloom filter that will decay its entries over time.
|
||||
@@ -87,7 +93,6 @@ public class DecayingBloomFilter {
|
||||
_longToEntry = new byte[_entryBytes];
|
||||
_longToEntryMask = (1l << (_entryBytes * 8l)) -1;
|
||||
}
|
||||
_currentDuplicates = 0;
|
||||
_decayEvent = new DecayEvent();
|
||||
_keepDecaying = true;
|
||||
SimpleTimer.getInstance().addEvent(_decayEvent, _durationMs);
|
||||
@@ -105,11 +110,13 @@ public class DecayingBloomFilter {
|
||||
}
|
||||
|
||||
public long getCurrentDuplicateCount() { return _currentDuplicates; }
|
||||
|
||||
public int getInsertedCount() {
|
||||
synchronized (this) {
|
||||
return _current.size() + _previous.size();
|
||||
}
|
||||
}
|
||||
|
||||
public double getFalsePositiveRate() {
|
||||
synchronized (this) {
|
||||
return _current.falsePositives();
|
||||
@@ -117,12 +124,15 @@ public class DecayingBloomFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if the entry added is a duplicate
|
||||
*
|
||||
* @return true if the entry added is a duplicate
|
||||
*/
|
||||
public boolean add(byte entry[]) {
|
||||
return add(entry, 0, entry.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the entry added is a duplicate
|
||||
*/
|
||||
public boolean add(byte entry[], int off, int len) {
|
||||
if (ALWAYS_MISS) return false;
|
||||
if (entry == null)
|
||||
@@ -131,55 +141,52 @@ public class DecayingBloomFilter {
|
||||
throw new IllegalArgumentException("Bad entry [" + len + ", expected "
|
||||
+ _entryBytes + "]");
|
||||
synchronized (this) {
|
||||
return locked_add(entry, off, len);
|
||||
return locked_add(entry, off, len, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if the entry added is a duplicate. the number of low order
|
||||
* @return true if the entry added is a duplicate. the number of low order
|
||||
* bits used is determined by the entryBytes parameter used on creation of the
|
||||
* filter.
|
||||
*
|
||||
*/
|
||||
public boolean add(long entry) {
|
||||
if (ALWAYS_MISS) return false;
|
||||
if (_entryBytes <= 7)
|
||||
entry = ((entry ^ _longToEntryMask) & ((1 << 31)-1)) | (entry ^ _longToEntryMask);
|
||||
//entry &= _longToEntryMask;
|
||||
if (entry < 0) {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, 0-entry);
|
||||
_longToEntry[0] |= (1 << 7);
|
||||
} else {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, entry);
|
||||
}
|
||||
synchronized (this) {
|
||||
if (_entryBytes <= 7)
|
||||
entry = ((entry ^ _longToEntryMask) & ((1 << 31)-1)) | (entry ^ _longToEntryMask);
|
||||
//entry &= _longToEntryMask;
|
||||
if (entry < 0) {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, 0-entry);
|
||||
_longToEntry[0] |= (1 << 7);
|
||||
} else {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, entry);
|
||||
}
|
||||
return locked_add(_longToEntry, 0, _longToEntry.length);
|
||||
return locked_add(_longToEntry, 0, _longToEntry.length, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if the entry is already known. this does NOT add the
|
||||
* @return true if the entry is already known. this does NOT add the
|
||||
* entry however.
|
||||
*
|
||||
*/
|
||||
public boolean isKnown(long entry) {
|
||||
if (ALWAYS_MISS) return false;
|
||||
if (_entryBytes <= 7)
|
||||
entry = ((entry ^ _longToEntryMask) & ((1 << 31)-1)) | (entry ^ _longToEntryMask);
|
||||
if (entry < 0) {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, 0-entry);
|
||||
_longToEntry[0] |= (1 << 7);
|
||||
} else {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, entry);
|
||||
}
|
||||
synchronized (this) {
|
||||
if (_entryBytes <= 7)
|
||||
entry = ((entry ^ _longToEntryMask) & ((1 << 31)-1)) | (entry ^ _longToEntryMask);
|
||||
if (entry < 0) {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, 0-entry);
|
||||
_longToEntry[0] |= (1 << 7);
|
||||
} else {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, entry);
|
||||
}
|
||||
return locked_add(_longToEntry, 0, _longToEntry.length, false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean locked_add(byte entry[], int offset, int len) {
|
||||
return locked_add(entry, offset, len, true);
|
||||
}
|
||||
private boolean locked_add(byte entry[], int offset, int len, boolean addIfNew) {
|
||||
if (_extended != null) {
|
||||
// extend the entry to 32 bytes
|
||||
@@ -195,7 +202,6 @@ public class DecayingBloomFilter {
|
||||
} else {
|
||||
if (addIfNew) {
|
||||
_current.locked_insert(_extended);
|
||||
_previous.locked_insert(_extended);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -208,7 +214,6 @@ public class DecayingBloomFilter {
|
||||
} else {
|
||||
if (addIfNew) {
|
||||
_current.locked_insert(entry, offset, len);
|
||||
_previous.locked_insert(entry, offset, len);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -17,12 +17,15 @@ import net.i2p.data.DataHelper;
|
||||
*
|
||||
* ./router/java/src/net/i2p/router/tunnel/BuildMessageProcessor.java:
|
||||
* 32 bytes, peak 10 entries in 1m
|
||||
* (320 peak entries seen on fast router)
|
||||
*
|
||||
* ./router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java:
|
||||
* 4 bytes, peak 150 entries in 10s
|
||||
* (1600 peak entries seen on fast router)
|
||||
*
|
||||
* ./router/java/src/net/i2p/router/MessageValidator.java:
|
||||
* 8 bytes, peak 1K entries in 2m
|
||||
* (36K peak entries seen on fast router)
|
||||
*
|
||||
* ./router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java:
|
||||
* 16 bytes, peak 15K entries in 10m
|
||||
@@ -57,19 +60,10 @@ import net.i2p.data.DataHelper;
|
||||
* @author zzz
|
||||
*/
|
||||
public class DecayingHashSet extends DecayingBloomFilter {
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private ConcurrentHashSet<ArrayWrapper> _current;
|
||||
private ConcurrentHashSet<ArrayWrapper> _previous;
|
||||
private int _durationMs;
|
||||
private int _entryBytes;
|
||||
private volatile boolean _keepDecaying;
|
||||
private final DecayEvent _decayEvent;
|
||||
/** just for logging */
|
||||
private final String _name;
|
||||
/** synchronize against this lock when switching double buffers */
|
||||
private final ReentrantReadWriteLock _reorganizeLock = new ReentrantReadWriteLock(true);
|
||||
|
||||
|
||||
/**
|
||||
* Create a double-buffered hash set that will decay its entries over time.
|
||||
@@ -83,16 +77,11 @@ public class DecayingHashSet extends DecayingBloomFilter {
|
||||
|
||||
/** @param name just for logging / debugging / stats */
|
||||
public DecayingHashSet(I2PAppContext context, int durationMs, int entryBytes, String name) {
|
||||
super(durationMs, entryBytes, name, context);
|
||||
if (entryBytes <= 0 || entryBytes > 32)
|
||||
throw new IllegalArgumentException("Bad size");
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(DecayingHashSet.class);
|
||||
_entryBytes = entryBytes;
|
||||
_name = name;
|
||||
_current = new ConcurrentHashSet(128);
|
||||
_previous = new ConcurrentHashSet(128);
|
||||
_durationMs = durationMs;
|
||||
_currentDuplicates = 0;
|
||||
_decayEvent = new DecayEvent();
|
||||
_keepDecaying = true;
|
||||
SimpleScheduler.getInstance().addEvent(_decayEvent, _durationMs);
|
||||
@@ -111,6 +100,7 @@ public class DecayingHashSet extends DecayingBloomFilter {
|
||||
public int getInsertedCount() {
|
||||
return _current.size() + _previous.size();
|
||||
}
|
||||
|
||||
/** pointless, only used for logging elsewhere */
|
||||
@Override
|
||||
public double getFalsePositiveRate() {
|
||||
@@ -121,7 +111,6 @@ public class DecayingHashSet extends DecayingBloomFilter {
|
||||
|
||||
/**
|
||||
* @return true if the entry added is a duplicate
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public boolean add(byte entry[], int off, int len) {
|
||||
@@ -130,9 +119,10 @@ public class DecayingHashSet extends DecayingBloomFilter {
|
||||
if (len != _entryBytes)
|
||||
throw new IllegalArgumentException("Bad entry [" + len + ", expected "
|
||||
+ _entryBytes + "]");
|
||||
ArrayWrapper w = new ArrayWrapper(entry, off, len);
|
||||
getReadLock();
|
||||
try {
|
||||
return locked_add(entry, off, len, true);
|
||||
return locked_add(w, true);
|
||||
} finally { releaseReadLock(); }
|
||||
}
|
||||
|
||||
@@ -158,35 +148,30 @@ public class DecayingHashSet extends DecayingBloomFilter {
|
||||
}
|
||||
|
||||
private boolean add(long entry, boolean addIfNew) {
|
||||
int len = Math.min(8, _entryBytes);
|
||||
byte[] b = toLong(len, entry);
|
||||
ArrayWrapper w = new ArrayWrapper(entry);
|
||||
getReadLock();
|
||||
try {
|
||||
return locked_add(b, 0, len, addIfNew);
|
||||
return locked_add(w, addIfNew);
|
||||
} finally { releaseReadLock(); }
|
||||
}
|
||||
|
||||
/** from DataHelper, except negative values ok */
|
||||
private static byte[] toLong(int numBytes, long value) {
|
||||
byte target[] = new byte[numBytes];
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
target[numBytes-i-1] = (byte)(value >>> (i*8));
|
||||
return target;
|
||||
}
|
||||
|
||||
/** so many questions... */
|
||||
private boolean locked_add(byte entry[], int offset, int len, boolean addIfNew) {
|
||||
ArrayWrapper w = new ArrayWrapper(entry, offset, len);
|
||||
boolean seen = _current.contains(w);
|
||||
seen = seen || _previous.contains(w);
|
||||
/**
|
||||
* @param addIfNew if true, add the element to current if it is not already there;
|
||||
* if false, only check
|
||||
* @return if the element is in either the current or previous set
|
||||
*/
|
||||
private boolean locked_add(ArrayWrapper w, boolean addIfNew) {
|
||||
boolean seen;
|
||||
// only access _current once. This adds to _current even if seen in _previous.
|
||||
if (addIfNew)
|
||||
seen = !_current.add(w);
|
||||
else
|
||||
seen = _current.contains(w);
|
||||
if (!seen)
|
||||
seen = _previous.contains(w);
|
||||
if (seen) {
|
||||
// why increment if addIfNew == false?
|
||||
// why not add to current if only in previous?
|
||||
// why increment if addIfNew == false? Only used for stats...
|
||||
_currentDuplicates++;
|
||||
} else if (addIfNew) {
|
||||
_current.add(w);
|
||||
// why add to previous?
|
||||
_previous.add(w);
|
||||
}
|
||||
return seen;
|
||||
}
|
||||
@@ -270,14 +255,22 @@ public class DecayingHashSet extends DecayingBloomFilter {
|
||||
* the maximum entropy given the length of the data.
|
||||
*/
|
||||
private static class ArrayWrapper {
|
||||
private long _longhashcode;
|
||||
private final long _longhashcode;
|
||||
|
||||
public ArrayWrapper(byte[] b, int offset, int len) {
|
||||
int idx = offset;
|
||||
int shift = Math.min(8, 64 / len);
|
||||
long lhc = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
// xor better than + in tests
|
||||
_longhashcode ^= (((long) b[idx++]) << (i * shift));
|
||||
lhc ^= (((long) b[idx++]) << (i * shift));
|
||||
}
|
||||
_longhashcode = lhc;
|
||||
}
|
||||
|
||||
/** faster version for when storing <= 8 bytes */
|
||||
public ArrayWrapper(long b) {
|
||||
_longhashcode = b;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
|
||||
@@ -28,21 +28,21 @@ import net.i2p.util.InternalSocket;
|
||||
* Bug: a malformed url http://example.i2p (no trailing '/') fails cryptically
|
||||
*/
|
||||
public class EepGet {
|
||||
protected I2PAppContext _context;
|
||||
protected Log _log;
|
||||
protected boolean _shouldProxy;
|
||||
private String _proxyHost;
|
||||
private int _proxyPort;
|
||||
protected int _numRetries;
|
||||
private long _minSize; // minimum and maximum acceptable response size, -1 signifies unlimited,
|
||||
private long _maxSize; // applied both against whole responses and chunks
|
||||
protected String _outputFile;
|
||||
protected OutputStream _outputStream;
|
||||
protected final I2PAppContext _context;
|
||||
protected final Log _log;
|
||||
protected final boolean _shouldProxy;
|
||||
private final String _proxyHost;
|
||||
private final int _proxyPort;
|
||||
protected final int _numRetries;
|
||||
private final long _minSize; // minimum and maximum acceptable response size, -1 signifies unlimited,
|
||||
private final long _maxSize; // applied both against whole responses and chunks
|
||||
protected final String _outputFile;
|
||||
protected final OutputStream _outputStream;
|
||||
/** url we were asked to fetch */
|
||||
protected String _url;
|
||||
protected final String _url;
|
||||
/** the URL we actually fetch from (may differ from the _url in case of redirect) */
|
||||
protected String _actualURL;
|
||||
private String _postData;
|
||||
private final String _postData;
|
||||
private boolean _allowCaching;
|
||||
protected final List<StatusListener> _listeners;
|
||||
|
||||
@@ -106,7 +106,7 @@ public class EepGet {
|
||||
String outputFile, OutputStream outputStream, String url, boolean allowCaching,
|
||||
String etag, String lastModified, String postData) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(EepGet.class);
|
||||
_log = ctx.logManager().getLog(getClass());
|
||||
_shouldProxy = (proxyHost != null) && (proxyHost.length() > 0) && (proxyPort > 0) && shouldProxy;
|
||||
_proxyHost = proxyHost;
|
||||
_proxyPort = proxyPort;
|
||||
@@ -118,13 +118,7 @@ public class EepGet {
|
||||
_url = url;
|
||||
_actualURL = url;
|
||||
_postData = postData;
|
||||
_alreadyTransferred = 0;
|
||||
_bytesTransferred = 0;
|
||||
_bytesRemaining = -1;
|
||||
_currentAttempt = 0;
|
||||
_transferFailed = false;
|
||||
_headersRead = false;
|
||||
_aborted = false;
|
||||
_fetchHeaderTimeout = CONNECT_TIMEOUT;
|
||||
_listeners = new ArrayList(1);
|
||||
_etag = etag;
|
||||
@@ -255,9 +249,9 @@ public class EepGet {
|
||||
public void attempting(String url);
|
||||
}
|
||||
protected class CLIStatusListener implements StatusListener {
|
||||
private int _markSize;
|
||||
private int _lineSize;
|
||||
private long _startedOn;
|
||||
private final int _markSize;
|
||||
private final int _lineSize;
|
||||
private final long _startedOn;
|
||||
private long _written;
|
||||
private long _previousWritten;
|
||||
private long _discarded;
|
||||
@@ -271,9 +265,6 @@ public class EepGet {
|
||||
public CLIStatusListener(int markSize, int lineSize) {
|
||||
_markSize = markSize;
|
||||
_lineSize = lineSize;
|
||||
_written = 0;
|
||||
_previousWritten = 0;
|
||||
_discarded = 0;
|
||||
_lastComplete = _context.clock().now();
|
||||
_startedOn = _lastComplete;
|
||||
_firstTime = true;
|
||||
@@ -430,29 +421,33 @@ public class EepGet {
|
||||
_log.debug("Fetching (proxied? " + _shouldProxy + ") url=" + _actualURL);
|
||||
while (_keepFetching) {
|
||||
SocketTimeout timeout = null;
|
||||
if (_fetchHeaderTimeout > 0)
|
||||
if (_fetchHeaderTimeout > 0) {
|
||||
timeout = new SocketTimeout(_fetchHeaderTimeout);
|
||||
final SocketTimeout stimeout = timeout; // ugly - why not use sotimeout?
|
||||
timeout.setTimeoutCommand(new Runnable() {
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("timeout reached on " + _url + ": " + stimeout);
|
||||
_aborted = true;
|
||||
}
|
||||
});
|
||||
timeout.setTotalTimeoutPeriod(_fetchEndTime);
|
||||
final SocketTimeout stimeout = timeout; // ugly - why not use sotimeout?
|
||||
timeout.setTimeoutCommand(new Runnable() {
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("timeout reached on " + _url + ": " + stimeout);
|
||||
_aborted = true;
|
||||
}
|
||||
});
|
||||
timeout.setTotalTimeoutPeriod(_fetchEndTime);
|
||||
}
|
||||
try {
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
_listeners.get(i).attempting(_url);
|
||||
sendRequest(timeout);
|
||||
timeout.resetTimer();
|
||||
if (timeout != null)
|
||||
timeout.resetTimer();
|
||||
doFetch(timeout);
|
||||
timeout.cancel();
|
||||
if (timeout != null)
|
||||
timeout.cancel();
|
||||
if (!_transferFailed)
|
||||
return true;
|
||||
break;
|
||||
} catch (IOException ioe) {
|
||||
timeout.cancel();
|
||||
if (timeout != null)
|
||||
timeout.cancel();
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
_listeners.get(i).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, ioe);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -492,7 +487,10 @@ public class EepGet {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** single fetch */
|
||||
/**
|
||||
* single fetch
|
||||
* @param timeout may be null
|
||||
*/
|
||||
protected void doFetch(SocketTimeout timeout) throws IOException {
|
||||
_headersRead = false;
|
||||
_aborted = false;
|
||||
@@ -504,11 +502,13 @@ public class EepGet {
|
||||
if (_aborted)
|
||||
throw new IOException("Timed out reading the HTTP headers");
|
||||
|
||||
timeout.resetTimer();
|
||||
if (_fetchInactivityTimeout > 0)
|
||||
timeout.setInactivityTimeout(_fetchInactivityTimeout);
|
||||
else
|
||||
timeout.setInactivityTimeout(INACTIVITY_TIMEOUT);
|
||||
if (timeout != null) {
|
||||
timeout.resetTimer();
|
||||
if (_fetchInactivityTimeout > 0)
|
||||
timeout.setInactivityTimeout(_fetchInactivityTimeout);
|
||||
else
|
||||
timeout.setInactivityTimeout(INACTIVITY_TIMEOUT);
|
||||
}
|
||||
|
||||
if (_redirectLocation != null) {
|
||||
//try {
|
||||
@@ -571,7 +571,8 @@ public class EepGet {
|
||||
int read = _proxyIn.read(buf, 0, toRead);
|
||||
if (read == -1)
|
||||
break;
|
||||
timeout.resetTimer();
|
||||
if (timeout != null)
|
||||
timeout.resetTimer();
|
||||
_out.write(buf, 0, read);
|
||||
_bytesTransferred += read;
|
||||
if ((_maxSize > -1) && (_alreadyTransferred + read > _maxSize)) // could transfer a little over maxSize
|
||||
@@ -597,7 +598,8 @@ public class EepGet {
|
||||
read++;
|
||||
}
|
||||
}
|
||||
timeout.resetTimer();
|
||||
if (timeout != null)
|
||||
timeout.resetTimer();
|
||||
if (_bytesRemaining >= read) // else chunked?
|
||||
_bytesRemaining -= read;
|
||||
if (read > 0) {
|
||||
@@ -622,7 +624,8 @@ public class EepGet {
|
||||
if (_aborted)
|
||||
throw new IOException("Timed out reading the HTTP data");
|
||||
|
||||
timeout.cancel();
|
||||
if (timeout != null)
|
||||
timeout.cancel();
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Done transferring " + _bytesTransferred + " (ok? " + !_transferFailed + ")");
|
||||
@@ -867,6 +870,9 @@ public class EepGet {
|
||||
private static final byte NL = '\n';
|
||||
private static boolean isNL(byte b) { return (b == NL); }
|
||||
|
||||
/**
|
||||
* @param timeout may be null
|
||||
*/
|
||||
protected void sendRequest(SocketTimeout timeout) throws IOException {
|
||||
if (_outputStream != null) {
|
||||
// We are reading into a stream supplied by a caller,
|
||||
@@ -907,7 +913,8 @@ public class EepGet {
|
||||
_proxyIn = _proxy.getInputStream();
|
||||
_proxyOut = _proxy.getOutputStream();
|
||||
|
||||
timeout.setSocket(_proxy);
|
||||
if (timeout != null)
|
||||
timeout.setSocket(_proxy);
|
||||
|
||||
_proxyOut.write(DataHelper.getUTF8(req));
|
||||
_proxyOut.flush();
|
||||
@@ -945,8 +952,6 @@ public class EepGet {
|
||||
buf.append(_alreadyTransferred);
|
||||
buf.append("-\r\n");
|
||||
}
|
||||
if (_shouldProxy)
|
||||
buf.append("X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n");
|
||||
if (!_allowCaching) {
|
||||
buf.append("Cache-control: no-cache\r\n" +
|
||||
"Pragma: no-cache\r\n");
|
||||
|
||||
@@ -202,8 +202,6 @@ public class EepHead extends EepGet {
|
||||
buf.append("HEAD ").append(_actualURL).append(" HTTP/1.1\r\n");
|
||||
buf.append("Host: ").append(url.getHost()).append("\r\n");
|
||||
buf.append("Accept-Encoding: \r\n");
|
||||
if (_shouldProxy)
|
||||
buf.append("X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n");
|
||||
// This will be replaced if we are going through I2PTunnelHTTPClient
|
||||
buf.append("User-Agent: " + USER_AGENT + "\r\n");
|
||||
buf.append("Connection: close\r\n\r\n");
|
||||
|
||||
@@ -31,6 +31,7 @@ public class EepPost {
|
||||
_log = ctx.logManager().getLog(EepPost.class);
|
||||
}
|
||||
|
||||
/*****
|
||||
public static void main(String args[]) {
|
||||
EepPost e = new EepPost();
|
||||
Map fields = new HashMap();
|
||||
@@ -47,6 +48,8 @@ public class EepPost {
|
||||
//e.postFiles("http://localhost/cgi-bin/read.pl", null, -1, fields, null);
|
||||
//e.postFiles("http://localhost:2001/import.jsp", null, -1, fields, null);
|
||||
}
|
||||
*****/
|
||||
|
||||
/**
|
||||
* Submit an HTTP POST to the given URL (using the proxy if specified),
|
||||
* uploading the given fields. If the field's value is a File object, then
|
||||
@@ -117,7 +120,7 @@ public class EepPost {
|
||||
}
|
||||
}
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (s != null) try { s.close(); } catch (IOException ioe) {}
|
||||
|
||||
@@ -5,10 +5,10 @@ import java.util.List;
|
||||
import net.i2p.I2PAppContext;
|
||||
|
||||
class Executor implements Runnable {
|
||||
private I2PAppContext _context;
|
||||
private final I2PAppContext _context;
|
||||
private Log _log;
|
||||
private final List _readyEvents;
|
||||
private SimpleStore runn;
|
||||
private final SimpleStore runn;
|
||||
|
||||
public Executor(I2PAppContext ctx, Log log, List events, SimpleStore x) {
|
||||
_context = ctx;
|
||||
@@ -31,9 +31,10 @@ class Executor implements Runnable {
|
||||
try {
|
||||
evt.timeReached();
|
||||
} catch (Throwable t) {
|
||||
log("wtf, event borked: " + evt, t);
|
||||
log("Executing task " + evt + " exited unexpectedly, please report", t);
|
||||
}
|
||||
long time = _context.clock().now() - before;
|
||||
// FIXME _log won't be non-null unless we already had a CRIT
|
||||
if ( (time > 1000) && (_log != null) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("wtf, event execution took " + time + ": " + evt);
|
||||
}
|
||||
|
||||
@@ -122,24 +122,24 @@ public class FileUtil {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
InputStream in = null;
|
||||
FileOutputStream fos = null;
|
||||
JarOutputStream jos = null;
|
||||
try {
|
||||
InputStream in = zip.getInputStream(entry);
|
||||
in = zip.getInputStream(entry);
|
||||
if (entry.getName().endsWith(".jar.pack") || entry.getName().endsWith(".war.pack")) {
|
||||
target = new File(targetDir, entry.getName().substring(0, entry.getName().length() - ".pack".length()));
|
||||
JarOutputStream fos = new JarOutputStream(new FileOutputStream(target));
|
||||
unpack(in, fos);
|
||||
fos.close();
|
||||
jos = new JarOutputStream(new FileOutputStream(target));
|
||||
unpack(in, jos);
|
||||
System.err.println("INFO: File [" + entry.getName() + "] extracted and unpacked");
|
||||
} else {
|
||||
FileOutputStream fos = new FileOutputStream(target);
|
||||
fos = new FileOutputStream(target);
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1) {
|
||||
fos.write(buf, 0, read);
|
||||
}
|
||||
fos.close();
|
||||
System.err.println("INFO: File [" + entry.getName() + "] extracted");
|
||||
}
|
||||
in.close();
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("ERROR: Error extracting the zip entry (" + entry.getName() + ')');
|
||||
if (ioe.getMessage() != null && ioe.getMessage().indexOf("CAFED00D") >= 0)
|
||||
@@ -151,6 +151,10 @@ public class FileUtil {
|
||||
System.err.println("ERROR: Error unpacking the zip entry (" + entry.getName() +
|
||||
"), your JVM does not support unpack200");
|
||||
return false;
|
||||
} finally {
|
||||
try { if (in != null) in.close(); } catch (IOException ioe) {}
|
||||
try { if (fos != null) fos.close(); } catch (IOException ioe) {}
|
||||
try { if (jos != null) jos.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -353,6 +357,9 @@ public class FileUtil {
|
||||
* Dump the contents of the given path (relative to the root) to the output
|
||||
* stream. The path must not go above the root, either - if it does, it will
|
||||
* throw a FileNotFoundException
|
||||
*
|
||||
* Closes the OutputStream out on successful completion
|
||||
* but leaves it open when throwing IOE.
|
||||
*/
|
||||
public static void readFile(String path, String root, OutputStream out) throws IOException {
|
||||
File rootDir = new File(root);
|
||||
@@ -372,10 +379,10 @@ public class FileUtil {
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
out.write(buf, 0, read);
|
||||
out.close();
|
||||
try { out.close(); } catch (IOException ioe) {}
|
||||
} finally {
|
||||
if (in != null)
|
||||
in.close();
|
||||
try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,21 +408,24 @@ public class FileUtil {
|
||||
if (dst.exists() && !overwriteExisting) return false;
|
||||
|
||||
byte buf[] = new byte[4096];
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(src);
|
||||
FileOutputStream out = new FileOutputStream(dst);
|
||||
in = new FileInputStream(src);
|
||||
out = new FileOutputStream(dst);
|
||||
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
out.write(buf, 0, read);
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
if (!quiet)
|
||||
ioe.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
try { if (in != null) in.close(); } catch (IOException ioe) {}
|
||||
try { if (out != null) out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ package net.i2p.util;
|
||||
*/
|
||||
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Like I2PThread but with per-thread OOM listeners,
|
||||
@@ -22,7 +22,7 @@ import java.util.Set;
|
||||
*/
|
||||
public class I2PAppThread extends I2PThread {
|
||||
|
||||
private Set _threadListeners = new HashSet(0);
|
||||
private final Set _threadListeners = new CopyOnWriteArraySet();
|
||||
|
||||
public I2PAppThread() {
|
||||
super();
|
||||
|
||||
53
core/java/src/net/i2p/util/I2PProperties.java
Normal file
53
core/java/src/net/i2p/util/I2PProperties.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package net.i2p.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* This class contains a number of properties ((key,value)-pairs).
|
||||
* Additionally, it adds the possibility for callbacks,
|
||||
* to allow immediate response to changing properties.
|
||||
* @author Mathiasdm
|
||||
*
|
||||
*/
|
||||
public class I2PProperties extends Properties {
|
||||
|
||||
/**
|
||||
* Keep a list of callbacks to contact the interested parties
|
||||
* that want to know about property changes.
|
||||
*/
|
||||
private final List<I2PPropertyCallback> _callbacks = new CopyOnWriteArrayList<I2PPropertyCallback>();
|
||||
|
||||
public I2PProperties() {
|
||||
super();
|
||||
}
|
||||
|
||||
public I2PProperties(Properties defaults) {
|
||||
super(defaults);
|
||||
}
|
||||
|
||||
public void addCallBack(I2PPropertyCallback callback) {
|
||||
_callbacks.add(callback);
|
||||
}
|
||||
|
||||
public void removeCallBack(I2PPropertyCallback callback) {
|
||||
_callbacks.remove(callback);
|
||||
}
|
||||
|
||||
public Object setProperty(String key, String value) {
|
||||
Object returnValue = super.setProperty(key, value);
|
||||
for(I2PPropertyCallback callback: _callbacks) {
|
||||
callback.propertyChanged(key, value);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public interface I2PPropertyCallback {
|
||||
|
||||
public void propertyChanged(String key, String value);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,9 +10,9 @@ package net.i2p.util;
|
||||
*/
|
||||
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* In case its useful later...
|
||||
@@ -21,7 +21,7 @@ import java.util.Set;
|
||||
*/
|
||||
public class I2PThread extends Thread {
|
||||
private static volatile Log _log;
|
||||
private static Set _listeners = new HashSet(4);
|
||||
private static final Set _listeners = new CopyOnWriteArraySet();
|
||||
private String _name;
|
||||
private Exception _createdBy;
|
||||
|
||||
|
||||
@@ -205,7 +205,8 @@ public class Log {
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) throw new NullPointerException("Null object scope?");
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (obj instanceof LogScope) {
|
||||
LogScope s = (LogScope)obj;
|
||||
return s._scopeCache.equals(_scopeCache);
|
||||
|
||||
@@ -152,7 +152,9 @@ public class LogManager {
|
||||
if (_writer != null)
|
||||
return;
|
||||
_writer = new LogWriter(this);
|
||||
Thread t = new I2PThread(_writer, "LogWriter", true);
|
||||
// NOT an I2PThread, as it contains logging and we end up with problems
|
||||
Thread t = new Thread(_writer, "LogWriter");
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
@@ -164,8 +166,10 @@ public class LogManager {
|
||||
Log rv = _logs.get(scope);
|
||||
if (rv == null) {
|
||||
rv = new Log(this, cls, name);
|
||||
_logs.putIfAbsent(scope, rv);
|
||||
isNew = true;
|
||||
Log old = _logs.putIfAbsent(scope, rv);
|
||||
isNew = old == null;
|
||||
if (!isNew)
|
||||
rv = old;
|
||||
}
|
||||
if (isNew)
|
||||
updateLimit(rv);
|
||||
@@ -178,8 +182,9 @@ public class LogManager {
|
||||
}
|
||||
|
||||
void addLog(Log log) {
|
||||
_logs.putIfAbsent(log.getScope(), log);
|
||||
updateLimit(log);
|
||||
Log old = _logs.putIfAbsent(log.getScope(), log);
|
||||
if (old == null)
|
||||
updateLimit(log);
|
||||
}
|
||||
|
||||
public LogConsoleBuffer getBuffer() { return _consoleBuffer; }
|
||||
@@ -634,6 +639,7 @@ public class LogManager {
|
||||
return _dateFormatPattern;
|
||||
}
|
||||
|
||||
/*****
|
||||
public static void main(String args[]) {
|
||||
I2PAppContext ctx = new I2PAppContext();
|
||||
Log l1 = ctx.logManager().getLog("test.1");
|
||||
@@ -654,6 +660,7 @@ public class LogManager {
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
*****/
|
||||
|
||||
public void shutdown() {
|
||||
if (_writer != null) {
|
||||
|
||||
@@ -92,10 +92,13 @@ class LogRecordFormatter {
|
||||
}
|
||||
|
||||
/** don't translate */
|
||||
/****
|
||||
private static String getPriority(LogRecord rec) {
|
||||
return toString(Log.toLevelString(rec.getPriority()), MAX_PRIORITY_LENGTH);
|
||||
}
|
||||
****/
|
||||
|
||||
/** */
|
||||
private static final String BUNDLE_NAME = "net.i2p.router.web.messages";
|
||||
|
||||
/** translate @since 0.7.14 */
|
||||
|
||||
@@ -77,7 +77,8 @@ class LogWriter implements Runnable {
|
||||
writeRecord(rec);
|
||||
}
|
||||
try {
|
||||
_currentOut.flush();
|
||||
if (_currentOut != null)
|
||||
_currentOut.flush();
|
||||
} catch (IOException ioe) {
|
||||
if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
|
||||
System.err.println("Error writing the router log - disk full? " + ioe);
|
||||
@@ -180,7 +181,8 @@ class LogWriter implements Runnable {
|
||||
try {
|
||||
_currentOut = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(f), "UTF-8"));
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("Error rotating into [" + f.getAbsolutePath() + "]" + ioe);
|
||||
if (++_diskFullMessageCount < MAX_DISKFULL_MESSAGES)
|
||||
System.err.println("Error creating log file [" + f.getAbsolutePath() + "]" + ioe);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ public class LookaheadInputStream extends FilterInputStream {
|
||||
/** grab the lookahead footer */
|
||||
public byte[] getFooter() { return _footerLookahead; }
|
||||
|
||||
/*******
|
||||
public static void main(String args[]) {
|
||||
byte buf[] = new byte[32];
|
||||
for (int i = 0; i < 32; i++)
|
||||
@@ -128,4 +129,5 @@ public class LookaheadInputStream extends FilterInputStream {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
******/
|
||||
}
|
||||
|
||||
@@ -114,8 +114,6 @@ public class PartialEepGet extends EepGet {
|
||||
buf.append(_fetchSize - 1);
|
||||
buf.append("\r\n");
|
||||
|
||||
if (_shouldProxy)
|
||||
buf.append("X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n");
|
||||
buf.append("Cache-control: no-cache\r\n" +
|
||||
"Pragma: no-cache\r\n");
|
||||
// This will be replaced if we are going through I2PTunnelHTTPClient
|
||||
|
||||
@@ -146,14 +146,18 @@ public class RandomSource extends SecureRandom implements EntropyHarvester {
|
||||
public final boolean initSeed(byte buf[]) {
|
||||
// why urandom? because /dev/random blocks, and there are arguments
|
||||
// suggesting such blockages are largely meaningless
|
||||
boolean ok = seedFromFile("/dev/urandom", buf);
|
||||
boolean ok = seedFromFile(new File("/dev/urandom"), buf);
|
||||
// we merge (XOR) in the data from /dev/urandom with our own seedfile
|
||||
ok = seedFromFile("prngseed.rnd", buf) || ok;
|
||||
File localFile = new File(_context.getConfigDir(), SEEDFILE);
|
||||
ok = seedFromFile(localFile, buf) || ok;
|
||||
return ok;
|
||||
}
|
||||
|
||||
private static final boolean seedFromFile(String filename, byte buf[]) {
|
||||
File f = new File(I2PAppContext.getGlobalContext().getConfigDir(), filename);
|
||||
/**
|
||||
* @param f absolute path
|
||||
* @return success
|
||||
*/
|
||||
private static final boolean seedFromFile(File f, byte buf[]) {
|
||||
if (f.exists()) {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
|
||||
@@ -482,12 +482,14 @@ public class SSLEepGet extends EepGet {
|
||||
if (_aborted)
|
||||
throw new IOException("Timed out reading the HTTP headers");
|
||||
|
||||
timeout.resetTimer();
|
||||
if (_fetchInactivityTimeout > 0)
|
||||
timeout.setInactivityTimeout(_fetchInactivityTimeout);
|
||||
else
|
||||
timeout.setInactivityTimeout(60*1000);
|
||||
|
||||
if (timeout != null) {
|
||||
timeout.resetTimer();
|
||||
if (_fetchInactivityTimeout > 0)
|
||||
timeout.setInactivityTimeout(_fetchInactivityTimeout);
|
||||
else
|
||||
timeout.setInactivityTimeout(60*1000);
|
||||
}
|
||||
|
||||
if (_redirectLocation != null) {
|
||||
throw new IOException("Server redirect to " + _redirectLocation + " not allowed");
|
||||
}
|
||||
@@ -506,7 +508,8 @@ public class SSLEepGet extends EepGet {
|
||||
int read = _proxyIn.read(buf, 0, toRead);
|
||||
if (read == -1)
|
||||
break;
|
||||
timeout.resetTimer();
|
||||
if (timeout != null)
|
||||
timeout.resetTimer();
|
||||
_out.write(buf, 0, read);
|
||||
_bytesTransferred += read;
|
||||
|
||||
@@ -531,7 +534,8 @@ public class SSLEepGet extends EepGet {
|
||||
read++;
|
||||
}
|
||||
}
|
||||
timeout.resetTimer();
|
||||
if (timeout != null)
|
||||
timeout.resetTimer();
|
||||
if (_bytesRemaining >= read) // else chunked?
|
||||
_bytesRemaining -= read;
|
||||
if (read > 0) {
|
||||
@@ -556,7 +560,8 @@ public class SSLEepGet extends EepGet {
|
||||
if (_aborted)
|
||||
throw new IOException("Timed out reading the HTTP data");
|
||||
|
||||
timeout.cancel();
|
||||
if (timeout != null)
|
||||
timeout.cancel();
|
||||
|
||||
if (_transferFailed) {
|
||||
// 404, etc - transferFailed is called after all attempts fail, by fetch() above
|
||||
|
||||
@@ -89,7 +89,7 @@ public class ShellCommand {
|
||||
*
|
||||
* @author hypercubus
|
||||
*/
|
||||
private class StreamConsumer extends Thread {
|
||||
private static class StreamConsumer extends Thread {
|
||||
|
||||
private BufferedReader bufferedReader;
|
||||
private InputStreamReader inputStreamReader;
|
||||
@@ -123,7 +123,7 @@ public class ShellCommand {
|
||||
*
|
||||
* @author hypercubus
|
||||
*/
|
||||
private class StreamReader extends Thread {
|
||||
private static class StreamReader extends Thread {
|
||||
|
||||
private BufferedReader bufferedReader;
|
||||
private InputStreamReader inputStreamReader;
|
||||
@@ -159,7 +159,7 @@ public class ShellCommand {
|
||||
*
|
||||
* @author hypercubus
|
||||
*/
|
||||
private class StreamWriter extends Thread {
|
||||
private static class StreamWriter extends Thread {
|
||||
|
||||
private BufferedWriter bufferedWriter;
|
||||
private BufferedReader in;
|
||||
@@ -183,7 +183,7 @@ public class ShellCommand {
|
||||
bufferedWriter.write(input, 0, input.length());
|
||||
bufferedWriter.flush();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
bufferedWriter.flush();
|
||||
} catch (IOException e1) {
|
||||
|
||||
@@ -30,10 +30,10 @@ public class SimpleScheduler {
|
||||
public static SimpleScheduler getInstance() { return _instance; }
|
||||
private static final int MIN_THREADS = 2;
|
||||
private static final int MAX_THREADS = 4;
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
private ScheduledThreadPoolExecutor _executor;
|
||||
private String _name;
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private final ScheduledThreadPoolExecutor _executor;
|
||||
private final String _name;
|
||||
private int _count;
|
||||
private final int _threads;
|
||||
|
||||
@@ -42,8 +42,9 @@ public class SimpleScheduler {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(SimpleScheduler.class);
|
||||
_name = name;
|
||||
_count = 0;
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
if (maxMemory == Long.MAX_VALUE)
|
||||
maxMemory = 96*1024*1024l;
|
||||
_threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
|
||||
_executor = new ScheduledThreadPoolExecutor(_threads, new CustomThreadFactory());
|
||||
_executor.prestartAllCoreThreads();
|
||||
@@ -139,7 +140,7 @@ public class SimpleScheduler {
|
||||
try {
|
||||
_timedEvent.timeReached();
|
||||
} catch (Throwable t) {
|
||||
_log.log(Log.CRIT, _name + " wtf, event borked: " + _timedEvent, t);
|
||||
_log.log(Log.CRIT, _name + ": Scheduled task " + _timedEvent + " exited unexpectedly, please report", t);
|
||||
}
|
||||
long time = System.currentTimeMillis() - before;
|
||||
if (time > 1000 && _log.shouldLog(Log.WARN))
|
||||
|
||||
@@ -14,6 +14,8 @@ import net.i2p.I2PAppContext;
|
||||
* appropriate time. The method that is fired however should NOT block (otherwise
|
||||
* they b0rk the timer).
|
||||
*
|
||||
* WARNING - Deprecated.
|
||||
* This is an inefficient mess. Use SimpleScheduler or SimpleTimer2 if possible.
|
||||
*/
|
||||
public class SimpleTimer {
|
||||
private static final SimpleTimer _instance = new SimpleTimer();
|
||||
@@ -42,6 +44,8 @@ public class SimpleTimer {
|
||||
runner.setDaemon(true);
|
||||
runner.start();
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
if (maxMemory == Long.MAX_VALUE)
|
||||
maxMemory = 128*1024*1024l;
|
||||
int threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
|
||||
for (int i = 1; i <= threads ; i++) {
|
||||
I2PThread executor = new I2PThread(new Executor(_context, _log, _readyEvents, runn));
|
||||
@@ -90,7 +94,7 @@ public class SimpleTimer {
|
||||
int totalEvents = 0;
|
||||
long now = System.currentTimeMillis();
|
||||
long eventTime = now + timeoutMs;
|
||||
Long time = new Long(eventTime);
|
||||
Long time = Long.valueOf(eventTime);
|
||||
synchronized (_events) {
|
||||
// remove the old scheduled position, then reinsert it
|
||||
Long oldTime = (Long)_eventTimes.get(event);
|
||||
|
||||
@@ -29,10 +29,10 @@ public class SimpleTimer2 {
|
||||
public static SimpleTimer2 getInstance() { return _instance; }
|
||||
private static final int MIN_THREADS = 2;
|
||||
private static final int MAX_THREADS = 4;
|
||||
private I2PAppContext _context;
|
||||
private final I2PAppContext _context;
|
||||
private static Log _log; // static so TimedEvent can use it
|
||||
private ScheduledThreadPoolExecutor _executor;
|
||||
private String _name;
|
||||
private final ScheduledThreadPoolExecutor _executor;
|
||||
private final String _name;
|
||||
private int _count;
|
||||
private final int _threads;
|
||||
|
||||
@@ -43,6 +43,8 @@ public class SimpleTimer2 {
|
||||
_name = name;
|
||||
_count = 0;
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
if (maxMemory == Long.MAX_VALUE)
|
||||
maxMemory = 96*1024*1024l;
|
||||
_threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
|
||||
_executor = new CustomScheduledThreadPoolExecutor(_threads, new CustomThreadFactory());
|
||||
_executor.prestartAllCoreThreads();
|
||||
@@ -55,7 +57,7 @@ public class SimpleTimer2 {
|
||||
_executor.shutdownNow();
|
||||
}
|
||||
|
||||
private class CustomScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
|
||||
private static class CustomScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
|
||||
public CustomScheduledThreadPoolExecutor(int threads, ThreadFactory factory) {
|
||||
super(threads, factory);
|
||||
}
|
||||
@@ -223,7 +225,7 @@ public class SimpleTimer2 {
|
||||
try {
|
||||
timeReached();
|
||||
} catch (Throwable t) {
|
||||
_log.log(Log.CRIT, _pool + " wtf, event borked: " + this, t);
|
||||
_log.log(Log.CRIT, _pool + ": Timed task " + this + " exited unexpectedly, please report", t);
|
||||
}
|
||||
long time = System.currentTimeMillis() - before;
|
||||
if (time > 500 && _log.shouldLog(Log.WARN))
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
package net.i2p.crypto;
|
||||
/* @(#)SHA1Test.java 1.10 2004-04-24
|
||||
* This file was freely contributed to the LimeWire project and is covered
|
||||
* by its existing GPL licence, but it may be used individually as a public
|
||||
* domain implementation of a published algorithm (see below for references).
|
||||
* It was also freely contributed to the Bitzi public domain sources.
|
||||
* @author Philippe Verdy
|
||||
*/
|
||||
|
||||
/* Sun may wish to change the following package name, if integrating this
|
||||
* class in the Sun JCE Security Provider for Java 1.5 (code-named Tiger).
|
||||
*/
|
||||
//package com.bitzi.util;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class SHA1Test {
|
||||
|
||||
private static final SHA1 hash = new SHA1();
|
||||
|
||||
public static void main(String args[]) {
|
||||
// http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
|
||||
System.out.println("****************************************");
|
||||
System.out.println("* Basic FIPS PUB 180-1 test vectors... *");
|
||||
System.out.println("****************************************");
|
||||
tst(1, 1,
|
||||
"abc",
|
||||
"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D");
|
||||
tst(1, 2,
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||
"84983E44 1C3BD26e BAAE4AA1 F95129E5 E54670F1");
|
||||
tst(1, 3, /* one million bytes */
|
||||
1000000, "a",
|
||||
"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F");
|
||||
System.out.println();
|
||||
|
||||
// http://csrc.ncsl.nist.gov/cryptval/shs/SHAVS.pdf
|
||||
System.out.println("********************************************************");
|
||||
System.out.println("* SHSV Examples of the selected short messages test... *");
|
||||
System.out.println("********************************************************");
|
||||
tst(2, 2, new byte[] {/* 8 bits, i.e. 1 byte */
|
||||
(byte)0x5e},
|
||||
"5e6f80a3 4a9798ca fc6a5db9 6cc57ba4 c4db59c2");
|
||||
tst(2, 4, new byte[] {/* 128 bits, i.e. 16 bytes */
|
||||
(byte)0x9a,(byte)0x7d,(byte)0xfd,(byte)0xf1,(byte)0xec,(byte)0xea,(byte)0xd0,(byte)0x6e,
|
||||
(byte)0xd6,(byte)0x46,(byte)0xaa,(byte)0x55,(byte)0xfe,(byte)0x75,(byte)0x71,(byte)0x46},
|
||||
"82abff66 05dbe1c1 7def12a3 94fa22a8 2b544a35");
|
||||
System.out.println();
|
||||
|
||||
System.out.println("*******************************************************");
|
||||
System.out.println("* SHSV Examples of the selected long messages test... *");
|
||||
System.out.println("*******************************************************");
|
||||
tst(3, 2, new byte[] {/* 1304 bits, i.e. 163 bytes */
|
||||
(byte)0xf7,(byte)0x8f,(byte)0x92,(byte)0x14,(byte)0x1b,(byte)0xcd,(byte)0x17,(byte)0x0a,
|
||||
(byte)0xe8,(byte)0x9b,(byte)0x4f,(byte)0xba,(byte)0x15,(byte)0xa1,(byte)0xd5,(byte)0x9f,
|
||||
(byte)0x3f,(byte)0xd8,(byte)0x4d,(byte)0x22,(byte)0x3c,(byte)0x92,(byte)0x51,(byte)0xbd,
|
||||
(byte)0xac,(byte)0xbb,(byte)0xae,(byte)0x61,(byte)0xd0,(byte)0x5e,(byte)0xd1,(byte)0x15,
|
||||
(byte)0xa0,(byte)0x6a,(byte)0x7c,(byte)0xe1,(byte)0x17,(byte)0xb7,(byte)0xbe,(byte)0xea,
|
||||
(byte)0xd2,(byte)0x44,(byte)0x21,(byte)0xde,(byte)0xd9,(byte)0xc3,(byte)0x25,(byte)0x92,
|
||||
(byte)0xbd,(byte)0x57,(byte)0xed,(byte)0xea,(byte)0xe3,(byte)0x9c,(byte)0x39,(byte)0xfa,
|
||||
(byte)0x1f,(byte)0xe8,(byte)0x94,(byte)0x6a,(byte)0x84,(byte)0xd0,(byte)0xcf,(byte)0x1f,
|
||||
(byte)0x7b,(byte)0xee,(byte)0xad,(byte)0x17,(byte)0x13,(byte)0xe2,(byte)0xe0,(byte)0x95,
|
||||
(byte)0x98,(byte)0x97,(byte)0x34,(byte)0x7f,(byte)0x67,(byte)0xc8,(byte)0x0b,(byte)0x04,
|
||||
(byte)0x00,(byte)0xc2,(byte)0x09,(byte)0x81,(byte)0x5d,(byte)0x6b,(byte)0x10,(byte)0xa6,
|
||||
(byte)0x83,(byte)0x83,(byte)0x6f,(byte)0xd5,(byte)0x56,(byte)0x2a,(byte)0x56,(byte)0xca,
|
||||
(byte)0xb1,(byte)0xa2,(byte)0x8e,(byte)0x81,(byte)0xb6,(byte)0x57,(byte)0x66,(byte)0x54,
|
||||
(byte)0x63,(byte)0x1c,(byte)0xf1,(byte)0x65,(byte)0x66,(byte)0xb8,(byte)0x6e,(byte)0x3b,
|
||||
(byte)0x33,(byte)0xa1,(byte)0x08,(byte)0xb0,(byte)0x53,(byte)0x07,(byte)0xc0,(byte)0x0a,
|
||||
(byte)0xff,(byte)0x14,(byte)0xa7,(byte)0x68,(byte)0xed,(byte)0x73,(byte)0x50,(byte)0x60,
|
||||
(byte)0x6a,(byte)0x0f,(byte)0x85,(byte)0xe6,(byte)0xa9,(byte)0x1d,(byte)0x39,(byte)0x6f,
|
||||
(byte)0x5b,(byte)0x5c,(byte)0xbe,(byte)0x57,(byte)0x7f,(byte)0x9b,(byte)0x38,(byte)0x80,
|
||||
(byte)0x7c,(byte)0x7d,(byte)0x52,(byte)0x3d,(byte)0x6d,(byte)0x79,(byte)0x2f,(byte)0x6e,
|
||||
(byte)0xbc,(byte)0x24,(byte)0xa4,(byte)0xec,(byte)0xf2,(byte)0xb3,(byte)0xa4,(byte)0x27,
|
||||
(byte)0xcd,(byte)0xbb,(byte)0xfb},
|
||||
"cb0082c8 f197d260 991ba6a4 60e76e20 2bad27b3");
|
||||
System.out.println();
|
||||
|
||||
// See also http://csrc.ncsl.nist.gov/cryptval/shs/sha1-vectors.zip
|
||||
|
||||
{
|
||||
final int RETRIES = 10;
|
||||
final int ITERATIONS = 2000;
|
||||
final int BLOCKSIZE = 65536;
|
||||
byte[] input = new byte[BLOCKSIZE];
|
||||
for (int i = BLOCKSIZE; --i >= 0; )
|
||||
input[i] = (byte)i;
|
||||
long best = 0;
|
||||
for (int i = 0; i < 1000; i++) // training for stable measure
|
||||
System.currentTimeMillis();
|
||||
|
||||
for (int retry = 0; retry < RETRIES; retry++) {
|
||||
long t0 = System.currentTimeMillis();
|
||||
for (int i = ITERATIONS; --i >= 0; );
|
||||
long t1 = System.currentTimeMillis();
|
||||
for (int i = ITERATIONS; --i >= 0; )
|
||||
hash.engineUpdate(input, 0, BLOCKSIZE);
|
||||
long t2 = System.currentTimeMillis();
|
||||
long time = (t2 - t1) - (t1 - t0);
|
||||
if (retry == 0 || time < best)
|
||||
best = time;
|
||||
}
|
||||
hash.engineReset();
|
||||
double rate = 1000.0 * ITERATIONS * BLOCKSIZE / best;
|
||||
System.out.println("Our rate = " +
|
||||
(float)(rate * 8) + " bits/s = " +
|
||||
(float)(rate / (1024 * 1024)) + " Megabytes/s");
|
||||
// Java 1.5 beta-b32c, on Athlon XP 1800+:
|
||||
// with java -client: 48.21 Megabytes/s.
|
||||
// with java -server: 68.23 Megabytes/s.
|
||||
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
for (int retry = 0; retry < RETRIES; retry++) {
|
||||
long t0 = System.currentTimeMillis();
|
||||
for (int i = ITERATIONS; --i >= 0; );
|
||||
long t1 = System.currentTimeMillis();
|
||||
for (int i = ITERATIONS; --i >= 0; )
|
||||
md.update(input, 0, BLOCKSIZE);
|
||||
long t2 = System.currentTimeMillis();
|
||||
long time = (t2 - t1) - (t1 - t0);
|
||||
if (retry == 0 || time < best)
|
||||
best = time;
|
||||
}
|
||||
md.reset();
|
||||
rate = 1000.0 * ITERATIONS * BLOCKSIZE / best;
|
||||
System.out.println("JCE rate = " +
|
||||
(float)(rate * 8) + " bits/s = " +
|
||||
(float)(rate / (1024 * 1024)) + " Megabytes/s");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
System.out.println("No SHA algorithm in local JCE Security Providers");
|
||||
}
|
||||
// Java 1.5 beta-b32c, on Athlon XP 1800+:
|
||||
// with java -client: 23.20 Megabytes/s.
|
||||
// with java -server: 45.72 Megabytes/s.
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean tst(final int set, final int vector,
|
||||
final String source,
|
||||
final String expect) {
|
||||
byte[] input = new byte[source.length()];
|
||||
for (int i = 0; i < input.length; i++)
|
||||
input[i] = (byte)source.charAt(i);
|
||||
return tst(set, vector, input, expect);
|
||||
}
|
||||
|
||||
private static final boolean tst(final int set, final int vector,
|
||||
final byte[] input,
|
||||
final String expect) {
|
||||
System.out.print("Set " + set + ", vector# " + vector + ": ");
|
||||
hash.engineUpdate(input, 0, input.length);
|
||||
return tstResult(expect);
|
||||
}
|
||||
|
||||
private static final boolean tst(final int set, final int vector,
|
||||
final int times, final String source,
|
||||
final String expect) {
|
||||
byte[] input = new byte[source.length()];
|
||||
for (int i = 0; i < input.length; i++)
|
||||
input[i] = (byte)source.charAt(i);
|
||||
System.out.print("Set " + set + ", vector# " + vector + ": ");
|
||||
for (int i = 0; i < times; i++)
|
||||
hash.engineUpdate(input, 0, input.length);
|
||||
return tstResult(expect);
|
||||
}
|
||||
|
||||
private static final boolean tstResult(String expect) {
|
||||
final String result = toHex(hash.engineDigest());
|
||||
expect = expect.toUpperCase();
|
||||
if (!expect.equals(result)) {
|
||||
System.out.println("**************** WRONG ***************");
|
||||
System.out.println(" expect: " + expect);
|
||||
System.out.println(" result: " + result);
|
||||
return false;
|
||||
}
|
||||
System.out.println("OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final String toHex(final byte[] bytes) {
|
||||
StringBuilder buf = new StringBuilder(bytes.length * 2);
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
if ((i & 3) == 0 && i != 0)
|
||||
buf.append(' ');
|
||||
buf.append(HEX.charAt((bytes[i] >> 4) & 0xF))
|
||||
.append(HEX.charAt( bytes[i] & 0xF));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
private static final String HEX = "0123456789ABCDEF";
|
||||
}
|
||||
@@ -32,66 +32,19 @@ public class SHA256Test extends TestCase{
|
||||
SHA256Generator.getInstance().calculateHash(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCopyConstructor(){
|
||||
SHA256Digest orig = new SHA256Digest();
|
||||
byte[] message = "update this!".getBytes();
|
||||
orig.update(message, 0, message.length);
|
||||
|
||||
SHA256Digest copy = new SHA256Digest(orig);
|
||||
|
||||
byte[] origData = new byte[32];
|
||||
orig.doFinal(origData, 0);
|
||||
byte[] copyData = new byte[32];
|
||||
copy.doFinal(copyData, 0);
|
||||
|
||||
assertTrue(DataHelper.eq(origData, copyData));
|
||||
|
||||
}
|
||||
|
||||
public void testCheckName(){
|
||||
SHA256Digest digest = new SHA256Digest();
|
||||
assertEquals("SHA-256", digest.getAlgorithmName());
|
||||
}
|
||||
|
||||
public void testManualUpdate(){
|
||||
byte[] data = "deathnotronic".getBytes();
|
||||
|
||||
SHA256Digest one = new SHA256Digest();
|
||||
for(int i = 0; i < data.length; i++){
|
||||
one.update(data[i]);
|
||||
|
||||
/**
|
||||
* Check if the behaviour remains the same.
|
||||
*/
|
||||
public void testMultipleEquality(){
|
||||
byte[] data = "blahblah".getBytes();
|
||||
|
||||
Hash firstHash = SHA256Generator.getInstance().calculateHash(data);
|
||||
|
||||
for(int i=0; i<5; i++){
|
||||
Hash h = SHA256Generator.getInstance().calculateHash(data);
|
||||
assertEquals(firstHash, h);
|
||||
}
|
||||
|
||||
SHA256Digest two = new SHA256Digest();
|
||||
two.update(data[0]);
|
||||
two.update(data, 1, data.length-1);
|
||||
|
||||
byte[] oneData = new byte[32];
|
||||
one.doFinal(oneData, 0);
|
||||
byte[] twoData = new byte[32];
|
||||
two.doFinal(twoData, 0);
|
||||
|
||||
assertTrue(DataHelper.eq(oneData, twoData));
|
||||
}
|
||||
|
||||
public void test14Words(){
|
||||
byte message[] = new byte[56];
|
||||
_context.random().nextBytes(message);
|
||||
SHA256Digest orig = new SHA256Digest();
|
||||
orig.update(message, 0, message.length);
|
||||
orig.doFinal(new byte[32], 0);
|
||||
}
|
||||
|
||||
public void testSHA(){
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
byte orig[] = new byte[4096];
|
||||
ctx.random().nextBytes(orig);
|
||||
Hash old = ctx.sha().calculateHash(orig);
|
||||
SHA256Digest d = new SHA256Digest();
|
||||
d.update(orig, 0, orig.length);
|
||||
byte out[] = new byte[Hash.HASH_LENGTH];
|
||||
d.doFinal(out, 0);
|
||||
assertTrue(DataHelper.eq(out, old.getData()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,8 @@ public class SessionEncryptionTest extends TestCase{
|
||||
|
||||
|
||||
|
||||
_context.sessionKeyManager().tagsDelivered(pubKey, curKey, firstTags);
|
||||
TagSetHandle tsh = _context.sessionKeyManager().tagsDelivered(pubKey, curKey, firstTags);
|
||||
_context.sessionKeyManager().tagsAcked(pubKey, curKey, tsh);
|
||||
|
||||
curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
|
||||
SessionTag curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
|
||||
@@ -130,7 +131,8 @@ public class SessionEncryptionTest extends TestCase{
|
||||
|
||||
|
||||
|
||||
_context.sessionKeyManager().tagsDelivered(pubKey, curKey, secondTags);
|
||||
tsh = _context.sessionKeyManager().tagsDelivered(pubKey, curKey, secondTags);
|
||||
_context.sessionKeyManager().tagsAcked(pubKey, curKey, tsh);
|
||||
|
||||
curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
|
||||
curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
|
||||
@@ -199,7 +201,8 @@ public class SessionEncryptionTest extends TestCase{
|
||||
|
||||
|
||||
|
||||
_context.sessionKeyManager().tagsDelivered(pubKey, curKey, firstTags);
|
||||
TagSetHandle tsh = _context.sessionKeyManager().tagsDelivered(pubKey, curKey, firstTags);
|
||||
_context.sessionKeyManager().tagsAcked(pubKey, curKey, tsh);
|
||||
|
||||
curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
|
||||
SessionTag curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
|
||||
@@ -226,7 +229,8 @@ public class SessionEncryptionTest extends TestCase{
|
||||
|
||||
|
||||
|
||||
_context.sessionKeyManager().tagsDelivered(pubKey, nextKey, secondTags); // note nextKey not curKey
|
||||
tsh = _context.sessionKeyManager().tagsDelivered(pubKey, nextKey, secondTags); // note nextKey not curKey
|
||||
_context.sessionKeyManager().tagsAcked(pubKey, nextKey, tsh);
|
||||
|
||||
curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
|
||||
curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
|
||||
@@ -288,9 +292,11 @@ public class SessionEncryptionTest extends TestCase{
|
||||
|
||||
if ( (tags != null) && (tags.size() > 0) ) {
|
||||
if (nextKey == null) {
|
||||
_context.sessionKeyManager().tagsDelivered(pubKey, curKey, tags);
|
||||
TagSetHandle tsh = _context.sessionKeyManager().tagsDelivered(pubKey, curKey, tags);
|
||||
_context.sessionKeyManager().tagsAcked(pubKey, curKey, tsh);
|
||||
} else {
|
||||
_context.sessionKeyManager().tagsDelivered(pubKey, nextKey, tags);
|
||||
TagSetHandle tsh = _context.sessionKeyManager().tagsDelivered(pubKey, nextKey, tags);
|
||||
_context.sessionKeyManager().tagsAcked(pubKey, nextKey, tsh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,50 @@ public class LeaseSetTest extends StructureTest {
|
||||
return leaseSet;
|
||||
}
|
||||
public DataStructure createStructureToRead() { return new LeaseSet(); }
|
||||
|
||||
public void testGetLeaseInvalid() {
|
||||
// create test subject
|
||||
LeaseSet subj = new LeaseSet();
|
||||
|
||||
// should contain no leases now..
|
||||
try {
|
||||
assertNull(subj.getLease(0));
|
||||
} catch(RuntimeException exc) {
|
||||
// all good
|
||||
}
|
||||
|
||||
// this shouldn't work either
|
||||
try {
|
||||
assertNull(subj.getLease(-1));
|
||||
} catch(RuntimeException exc) {
|
||||
// all good
|
||||
}
|
||||
}
|
||||
|
||||
public void testAddLeaseNull() {
|
||||
// create test subject
|
||||
LeaseSet subj = new LeaseSet();
|
||||
|
||||
// now add an null lease
|
||||
try {
|
||||
subj.addLease(null);
|
||||
fail("Failed at failing.");
|
||||
} catch(IllegalArgumentException exc) {
|
||||
// all good
|
||||
}
|
||||
}
|
||||
|
||||
public void testAddLeaseInvalid() {
|
||||
// create test subject
|
||||
LeaseSet subj = new LeaseSet();
|
||||
|
||||
// try to add completely invalid lease(ie. no data)
|
||||
try {
|
||||
subj.addLease(new Lease());
|
||||
fail("Failed at failing.");
|
||||
} catch(IllegalArgumentException exc) {
|
||||
// all good
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,13 +66,15 @@ public class PrivateKeyTest extends StructureTest {
|
||||
byte data[] = new byte[56];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
data[i] = (byte)(i);
|
||||
privateKey.setData(data);
|
||||
|
||||
boolean error = false;
|
||||
try{
|
||||
privateKey.setData(data);
|
||||
privateKey.writeBytes(new ByteArrayOutputStream());
|
||||
}catch(DataFormatException dfe){
|
||||
error = true;
|
||||
}catch(IllegalArgumentException exc) {
|
||||
error = true;
|
||||
}
|
||||
assertTrue(error);
|
||||
}
|
||||
|
||||
@@ -66,13 +66,15 @@ public class PublicKeyTest extends StructureTest {
|
||||
byte data[] = new byte[56];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
data[i] = (byte)(i);
|
||||
publicKey.setData(data);
|
||||
|
||||
boolean error = false;
|
||||
try{
|
||||
publicKey.setData(data);
|
||||
publicKey.writeBytes(new ByteArrayOutputStream());
|
||||
}catch(DataFormatException dfe){
|
||||
error = true;
|
||||
}catch(IllegalArgumentException exc) {
|
||||
error = true;
|
||||
}
|
||||
assertTrue(error);
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ public class RouterAddressTest extends StructureTest {
|
||||
addr.setOptions(options);
|
||||
addr.setTransportStyle("Blah");
|
||||
assertFalse(addr.equals(null));
|
||||
assertFalse(addr.equals(""));
|
||||
}
|
||||
|
||||
public void testToString(){
|
||||
@@ -73,5 +74,7 @@ public class RouterAddressTest extends StructureTest {
|
||||
addr.setOptions(options);
|
||||
addr.setTransportStyle("Blah");
|
||||
addr.toString();
|
||||
addr.setOptions(null);
|
||||
addr.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,13 +66,15 @@ public class SigningPrivateKeyTest extends StructureTest {
|
||||
byte data[] = new byte[56];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
data[i] = (byte)(i);
|
||||
signingPrivateKey.setData(data);
|
||||
|
||||
boolean error = false;
|
||||
try{
|
||||
signingPrivateKey.setData(data);
|
||||
signingPrivateKey.writeBytes(new ByteArrayOutputStream());
|
||||
}catch(DataFormatException dfe){
|
||||
error = true;
|
||||
}catch(IllegalArgumentException exc) {
|
||||
error = true;
|
||||
}
|
||||
assertTrue(error);
|
||||
}
|
||||
|
||||
@@ -66,14 +66,17 @@ public class SigningPublicKeyTest extends StructureTest {
|
||||
byte data[] = new byte[56];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
data[i] = (byte)(i);
|
||||
publicKey.setData(data);
|
||||
|
||||
boolean error = false;
|
||||
try{
|
||||
publicKey.setData(data);
|
||||
publicKey.writeBytes(new ByteArrayOutputStream());
|
||||
}catch(DataFormatException dfe){
|
||||
error = true;
|
||||
}catch(IllegalArgumentException exc) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
assertTrue(error);
|
||||
}
|
||||
|
||||
|
||||
96
core/java/test/net/i2p/data/SimpleDataStructureTest.java
Normal file
96
core/java/test/net/i2p/data/SimpleDataStructureTest.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package net.i2p.data;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test harness for the simple data structure
|
||||
*
|
||||
* @author welterde
|
||||
*/
|
||||
public class SimpleDataStructureTest extends TestCase {
|
||||
|
||||
public void testSetDataImmutable() throws Exception {
|
||||
// create new test subject
|
||||
TestStruct struct = new TestStruct();
|
||||
|
||||
// try to set null object.. should not fail..
|
||||
struct.setData(null);
|
||||
|
||||
// set data to something
|
||||
struct.setData(new byte[3]);
|
||||
|
||||
// now setting it to null should fail
|
||||
try {
|
||||
struct.setData(null);
|
||||
fail("Should not have allowed us to change this..");
|
||||
} catch(RuntimeException exc) {
|
||||
// all good
|
||||
}
|
||||
|
||||
// setting it to something non-null should fail as well.
|
||||
try {
|
||||
struct.setData(new byte[3]);
|
||||
fail("Should not have allowed us to change this..");
|
||||
} catch(RuntimeException exc) {
|
||||
// all good
|
||||
}
|
||||
}
|
||||
|
||||
public void testReadBytesImmutable() throws Exception {
|
||||
// create new test subject
|
||||
TestStruct struct = new TestStruct();
|
||||
|
||||
// load some data using setData
|
||||
struct.setData(new byte[3]);
|
||||
|
||||
// now try to load via readBytes
|
||||
try {
|
||||
struct.readBytes(null);
|
||||
fail("blah blah blah..");
|
||||
} catch(RuntimeException exc) {
|
||||
// all good
|
||||
}
|
||||
}
|
||||
|
||||
public void testToBase64Safe() throws Exception {
|
||||
// create new test subject
|
||||
TestStruct struct = new TestStruct();
|
||||
|
||||
// now try to get the Base64.. should not throw an exception, but should not be an empty string either
|
||||
assertNull(struct.toBase64());
|
||||
}
|
||||
|
||||
public void testCalculateHashSafe() throws Exception {
|
||||
// create new test subject
|
||||
TestStruct struct = new TestStruct();
|
||||
|
||||
// now try to get the hash.. should not throw an exception
|
||||
assertNull(struct.calculateHash());
|
||||
}
|
||||
|
||||
public void testHashCodeSafe() throws Exception {
|
||||
// create new test subject
|
||||
TestStruct struct = new TestStruct();
|
||||
|
||||
// just make sure it doesn't explode in our face
|
||||
struct.hashCode();
|
||||
}
|
||||
|
||||
public class TestStruct extends SimpleDataStructure {
|
||||
public int length() {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.i2p.stat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
@@ -7,7 +8,7 @@ import junit.framework.TestCase;
|
||||
|
||||
public class RateTest extends TestCase {
|
||||
public void testRate() throws Exception{
|
||||
Rate rate = new Rate(1000);
|
||||
Rate rate = new Rate(5000);
|
||||
for (int i = 0; i < 50; i++) {
|
||||
Thread.sleep(20);
|
||||
rate.addData(i * 100, 20);
|
||||
@@ -19,10 +20,10 @@ public class RateTest extends TestCase {
|
||||
byte data[] = buf.toString().getBytes();
|
||||
|
||||
Properties props = new Properties();
|
||||
props.load(new java.io.ByteArrayInputStream(data));
|
||||
props.load(new ByteArrayInputStream(data));
|
||||
|
||||
Rate r = new Rate(props, "rate.test", true);
|
||||
|
||||
assertEquals(r, rate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.i2p.stat;
|
||||
|
||||
public class SizeTest {
|
||||
public class SizeMeasure {
|
||||
public static void main(String args[]) {
|
||||
testRateSize(100); //117KB
|
||||
testRateSize(100000); // 4.5MB
|
||||
@@ -82,28 +82,37 @@ public class LogSettingsTest extends TestCase {
|
||||
|
||||
System.setOut(pout);
|
||||
|
||||
log.debug("DEBUG" + ": debug");
|
||||
log.info("DEBUG" + ": info");
|
||||
log.warn("DEBUG" + ": warn");
|
||||
log.error("DEBUG" + ": error");
|
||||
log.log(Log.CRIT, "DEBUG" + ": crit");
|
||||
_context.logManager().shutdown();
|
||||
|
||||
String l1 = in.readLine();
|
||||
String l2 = in.readLine();
|
||||
String l3 = in.readLine();
|
||||
String l4 = in.readLine();
|
||||
String l5 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*DEBUG: debug") &&
|
||||
l2.matches(".*DEBUG: info") &&
|
||||
l3.matches(".*DEBUG: warn") &&
|
||||
l4.matches(".*DEBUG: error") &&
|
||||
l5.matches(".*DEBUG: crit")
|
||||
);
|
||||
try {
|
||||
log.debug("DEBUG" + ": debug");
|
||||
log.info("DEBUG" + ": info");
|
||||
log.warn("DEBUG" + ": warn");
|
||||
log.error("DEBUG" + ": error");
|
||||
log.log(Log.CRIT, "DEBUG" + ": crit");
|
||||
|
||||
// Wait for the LogWriter to flush, then write extra stuff so
|
||||
// the test doesn't hang on failure
|
||||
try { Thread.sleep(12*1000); } catch (InterruptedException ie) {}
|
||||
for (int i = 0; i < 5; i++)
|
||||
pout.println("");
|
||||
pout.flush();
|
||||
String l1 = in.readLine();
|
||||
String l2 = in.readLine();
|
||||
String l3 = in.readLine();
|
||||
String l4 = in.readLine();
|
||||
String l5 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*DEBUG: debug") &&
|
||||
l2.matches(".*DEBUG: info") &&
|
||||
l3.matches(".*DEBUG: warn") &&
|
||||
l4.matches(".*DEBUG: error") &&
|
||||
l5.matches(".*DEBUG: crit")
|
||||
);
|
||||
} finally {
|
||||
System.setOut(systemOut);
|
||||
pout.close();
|
||||
}
|
||||
|
||||
System.setOut(systemOut);
|
||||
|
||||
}
|
||||
|
||||
@@ -122,26 +131,35 @@ public class LogSettingsTest extends TestCase {
|
||||
|
||||
System.setOut(pout);
|
||||
|
||||
log.debug("INFO" + ": debug");
|
||||
log.info("INFO" + ": info");
|
||||
log.warn("INFO" + ": warn");
|
||||
log.error("INFO" + ": error");
|
||||
log.log(Log.CRIT, "INFO" + ": crit");
|
||||
_context.logManager().shutdown();
|
||||
|
||||
String l1 = in.readLine();
|
||||
String l2 = in.readLine();
|
||||
String l3 = in.readLine();
|
||||
String l4 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*INFO: info") &&
|
||||
l2.matches(".*INFO: warn") &&
|
||||
l3.matches(".*INFO: error") &&
|
||||
l4.matches(".*INFO: crit")
|
||||
);
|
||||
try {
|
||||
log.debug("INFO" + ": debug");
|
||||
log.info("INFO" + ": info");
|
||||
log.warn("INFO" + ": warn");
|
||||
log.error("INFO" + ": error");
|
||||
log.log(Log.CRIT, "INFO" + ": crit");
|
||||
|
||||
// Wait for the LogWriter to flush, then write extra stuff so
|
||||
// the test doesn't hang on failure
|
||||
try { Thread.sleep(12*1000); } catch (InterruptedException ie) {}
|
||||
for (int i = 0; i < 4; i++)
|
||||
pout.println("");
|
||||
pout.flush();
|
||||
String l1 = in.readLine();
|
||||
String l2 = in.readLine();
|
||||
String l3 = in.readLine();
|
||||
String l4 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*INFO: info") &&
|
||||
l2.matches(".*INFO: warn") &&
|
||||
l3.matches(".*INFO: error") &&
|
||||
l4.matches(".*INFO: crit")
|
||||
);
|
||||
} finally {
|
||||
System.setOut(systemOut);
|
||||
pout.close();
|
||||
}
|
||||
|
||||
System.setOut(systemOut);
|
||||
|
||||
}
|
||||
|
||||
@@ -160,24 +178,33 @@ public class LogSettingsTest extends TestCase {
|
||||
|
||||
System.setOut(pout);
|
||||
|
||||
log.debug("WARN" + ": debug");
|
||||
log.info("WARN" + ": info");
|
||||
log.warn("WARN" + ": warn");
|
||||
log.error("WARN" + ": error");
|
||||
log.log(Log.CRIT, "WARN" + ": crit");
|
||||
_context.logManager().shutdown();
|
||||
|
||||
String l1 = in.readLine();
|
||||
String l2 = in.readLine();
|
||||
String l3 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*WARN: warn") &&
|
||||
l2.matches(".*WARN: error") &&
|
||||
l3.matches(".*WARN: crit")
|
||||
);
|
||||
try {
|
||||
log.debug("WARN" + ": debug");
|
||||
log.info("WARN" + ": info");
|
||||
log.warn("WARN" + ": warn");
|
||||
log.error("WARN" + ": error");
|
||||
log.log(Log.CRIT, "WARN" + ": crit");
|
||||
|
||||
// Wait for the LogWriter to flush, then write extra stuff so
|
||||
// the test doesn't hang on failure
|
||||
try { Thread.sleep(12*1000); } catch (InterruptedException ie) {}
|
||||
for (int i = 0; i < 3; i++)
|
||||
pout.println("");
|
||||
pout.flush();
|
||||
String l1 = in.readLine();
|
||||
String l2 = in.readLine();
|
||||
String l3 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*WARN: warn") &&
|
||||
l2.matches(".*WARN: error") &&
|
||||
l3.matches(".*WARN: crit")
|
||||
);
|
||||
} finally {
|
||||
System.setOut(systemOut);
|
||||
pout.close();
|
||||
}
|
||||
|
||||
System.setOut(systemOut);
|
||||
}
|
||||
|
||||
public void testError() throws IOException{
|
||||
@@ -195,22 +222,31 @@ public class LogSettingsTest extends TestCase {
|
||||
|
||||
System.setOut(pout);
|
||||
|
||||
log.debug("ERROR" + ": debug");
|
||||
log.info("ERROR" + ": info");
|
||||
log.warn("ERROR" + ": warn");
|
||||
log.error("ERROR" + ": error");
|
||||
log.log(Log.CRIT, "ERROR" + ": crit");
|
||||
_context.logManager().shutdown();
|
||||
|
||||
String l1 = in.readLine();
|
||||
String l2 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*ERROR: error") &&
|
||||
l2.matches(".*ERROR: crit")
|
||||
);
|
||||
try {
|
||||
log.debug("ERROR" + ": debug");
|
||||
log.info("ERROR" + ": info");
|
||||
log.warn("ERROR" + ": warn");
|
||||
log.error("ERROR" + ": error");
|
||||
log.log(Log.CRIT, "ERROR" + ": crit");
|
||||
|
||||
// Wait for the LogWriter to flush, then write extra stuff so
|
||||
// the test doesn't hang on failure
|
||||
try { Thread.sleep(12*1000); } catch (InterruptedException ie) {}
|
||||
for (int i = 0; i < 2; i++)
|
||||
pout.println("");
|
||||
pout.flush();
|
||||
String l1 = in.readLine();
|
||||
String l2 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*ERROR: error") &&
|
||||
l2.matches(".*ERROR: crit")
|
||||
);
|
||||
} finally {
|
||||
System.setOut(systemOut);
|
||||
pout.close();
|
||||
}
|
||||
|
||||
System.setOut(systemOut);
|
||||
}
|
||||
|
||||
public void testCrit() throws IOException {
|
||||
@@ -228,21 +264,29 @@ public class LogSettingsTest extends TestCase {
|
||||
|
||||
System.setOut(pout);
|
||||
|
||||
log.debug("CRIT" + ": debug");
|
||||
log.info("CRIT" + ": info");
|
||||
log.warn("CRIT" + ": warn");
|
||||
log.error("CRIT" + ": error");
|
||||
log.log(Log.CRIT, "CRIT" + ": crit");
|
||||
_context.logManager().shutdown();
|
||||
|
||||
String l1 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*CRIT: crit")
|
||||
);
|
||||
try {
|
||||
log.debug("CRIT" + ": debug");
|
||||
log.info("CRIT" + ": info");
|
||||
log.warn("CRIT" + ": warn");
|
||||
log.error("CRIT" + ": error");
|
||||
log.log(Log.CRIT, "CRIT" + ": crit");
|
||||
|
||||
// Wait for the LogWriter to flush, then write extra stuff so
|
||||
// the test doesn't hang on failure
|
||||
try { Thread.sleep(12*1000); } catch (InterruptedException ie) {}
|
||||
pout.println("");
|
||||
pout.flush();
|
||||
String l1 = in.readLine();
|
||||
|
||||
assertTrue(
|
||||
l1.matches(".*CRIT: crit")
|
||||
);
|
||||
} finally {
|
||||
System.setOut(systemOut);
|
||||
pout.close();
|
||||
}
|
||||
|
||||
System.setOut(systemOut);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user