2005-02-16 jrandom

* (Merged the 0.5-pre branch back into CVS HEAD)
    * Replaced the old tunnel routing crypto with the one specified in
      router/doc/tunnel-alt.html, including updates to the web console to view
      and tweak it.
    * Provide the means for routers to reject tunnel requests with a wider
      range of responses:
        probabalistic rejection, due to approaching overload
        transient rejection, due to temporary overload
        bandwidth rejection, due to persistent bandwidth overload
        critical rejection, due to general router fault (or imminent shutdown)
      The different responses are factored into the profiles accordingly.
    * Replaced the old I2CP tunnel related options (tunnels.depthInbound, etc)
      with a series of new properties, relevent to the new tunnel routing code:
        inbound.nickname (used on the console)
        inbound.quantity (# of tunnels to use in any leaseSets)
        inbound.backupQuantity (# of tunnels to keep in the ready)
        inbound.length (# of remote peers in the tunnel)
        inbound.lengthVariance (if > 0, permute the length by adding a random #
                                up to the variance.  if < 0, permute the length
                                by adding or subtracting a random # up to the
                                variance)
        outbound.* (same as the inbound, except for the, uh, outbound tunnels
                    in that client's pool)
      There are other options, and more will be added later, but the above are
      the most relevent ones.
    * Replaced Jetty 4.2.21 with Jetty 5.1.2
    * Compress all profile data on disk.
    * Adjust the reseeding functionality to work even when the JVM's http proxy
      is set.
    * Enable a poor-man's interactive-flow in the streaming lib by choking the
      max window size.
    * Reduced the default streaming lib max message size to 16KB (though still
      configurable by the user), also doubling the default maximum window
      size.
    * Replaced the RouterIdentity in a Lease with its SHA256 hash.
    * Reduced the overall I2NP message checksum from a full 32 byte SHA256 to
      the first byte of the SHA256.
    * Added a new "netId" flag to let routers drop references to other routers
      who we won't be able to talk to.
    * Extended the timestamper to get a second (or third) opinion whenever it
      wants to actually adjust the clock offset.
    * Replaced that kludge of a timestamp I2NP message with a full blown
      DateMessage.
    * Substantial memory optimizations within the router and the SDK to reduce
      GC churn.  Client apps and the streaming libs have not been tuned,
      however.
    * More bugfixes thank you can shake a stick at.

2005-02-13  jrandom
    * Updated jbigi source to handle 64bit CPUs.  The bundled jbigi.jar still
      only contains 32bit versions, so build your own, placing libjbigi.so in
      your install dir if necessary.  (thanks mule!)
    * Added support for libjbigi-$os-athlon64 to NativeBigInteger and CPUID
      (thanks spaetz!)
This commit is contained in:
jrandom
2005-02-16 22:23:47 +00:00
committed by zzz
parent 36f7e98e90
commit 566a713baa
142 changed files with 3202 additions and 2535 deletions

View File

@@ -252,6 +252,10 @@ public class CPUID {
return "Athlon 64";
case 5:
return "Athlon 64 FX Opteron";
case 12:
return "Athlon 64";
default: // is this safe?
return "Athlon 64 (unknown)";
}
}
}

View File

@@ -14,8 +14,8 @@ package net.i2p;
*
*/
public class CoreVersion {
public final static String ID = "$Revision: 1.25 $ $Date: 2004/11/06 22:00:57 $";
public final static String VERSION = "0.4.2";
public final static String ID = "$Revision: 1.26.2.1 $ $Date: 2005/02/09 13:46:58 $";
public final static String VERSION = "0.5-pre";
public static void main(String args[]) {
System.out.println("I2P Core version: " + VERSION);

View File

@@ -103,8 +103,9 @@ class I2CPMessageProducer {
if (payload == null) throw new I2PSessionException("No payload specified");
Payload data = new Payload();
// randomize padding
int size = payload.length + RandomSource.getInstance().nextInt(1024);
// no padding at this level
// the garlic may pad, and the tunnels may pad, and the transports may pad
int size = payload.length;
byte encr[] = _context.elGamalAESEngine().encrypt(payload, dest.getPublicKey(), key, tags, tag, newKey, size);
// yes, in an intelligent component, newTags would be queued for confirmation along with key, and
// generateNewTags would only generate tags if necessary

View File

@@ -111,6 +111,8 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
}
}
public static final int LISTEN_PORT = 7654;
/**
* Create a new session, reading the Destination, PrivateKey, and SigningPrivateKey
* from the destKeyStream, and using the specified options to connect to the router
@@ -145,14 +147,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
_options = new Properties();
_options.putAll(filter(options));
_hostname = _options.getProperty(I2PClient.PROP_TCP_HOST, "localhost");
String portNum = _options.getProperty(I2PClient.PROP_TCP_PORT, TestServer.LISTEN_PORT + "");
String portNum = _options.getProperty(I2PClient.PROP_TCP_PORT, LISTEN_PORT + "");
try {
_portNum = Integer.parseInt(portNum);
} catch (NumberFormatException nfe) {
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix() + "Invalid port number specified, defaulting to "
+ TestServer.LISTEN_PORT, nfe);
_portNum = TestServer.LISTEN_PORT;
+ LISTEN_PORT, nfe);
_portNum = LISTEN_PORT;
}
}

View File

@@ -46,7 +46,7 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
LeaseSet leaseSet = new LeaseSet();
for (int i = 0; i < msg.getEndpoints(); i++) {
Lease lease = new Lease();
lease.setRouterIdentity(msg.getRouter(i));
lease.setGateway(msg.getRouter(i));
lease.setTunnelId(msg.getTunnelId(i));
lease.setEndDate(msg.getEndDate());
//lease.setStartDate(msg.getStartDate());

View File

@@ -602,14 +602,15 @@ class TransientSessionKeyManager extends SessionKeyManager {
long rv = 0;
if (_key != null) rv = rv * 7 + _key.hashCode();
rv = rv * 7 + _date;
if (_sessionTags != null) rv = rv * 7 + DataHelper.hashCode(_sessionTags);
// no need to hashCode the tags, key + date should be enough
return (int) rv;
}
public boolean equals(Object o) {
if ((o == null) || !(o instanceof TagSet)) return false;
TagSet ts = (TagSet) o;
return DataHelper.eq(ts.getAssociatedKey(), getAssociatedKey()) && DataHelper.eq(ts.getTags(), getTags())
return DataHelper.eq(ts.getAssociatedKey(), getAssociatedKey())
//&& DataHelper.eq(ts.getTags(), getTags())
&& ts.getDate() == getDate();
}
}

View File

@@ -19,6 +19,7 @@ import java.io.Serializable;
public class ByteArray implements Serializable, Comparable {
private byte[] _data;
private int _valid;
private int _offset;
public ByteArray() {
this(null);
@@ -28,6 +29,11 @@ public class ByteArray implements Serializable, Comparable {
_data = data;
_valid = 0;
}
public ByteArray(byte[] data, int offset, int length) {
_data = data;
_offset = offset;
_valid = length;
}
public final byte[] getData() {
return _data;
@@ -44,6 +50,8 @@ public class ByteArray implements Serializable, Comparable {
*/
public final int getValid() { return _valid; }
public final void setValid(int valid) { _valid = valid; }
public final int getOffset() { return _offset; }
public final void setOffset(int offset) { _offset = offset; }
public final boolean equals(Object o) {
if (o == null) return false;

View File

@@ -35,6 +35,7 @@ import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import net.i2p.util.ByteCache;
import net.i2p.util.CachingByteArrayOutputStream;
import net.i2p.util.OrderedProperties;
/**
@@ -123,7 +124,70 @@ public class DataHelper {
writeLong(rawStream, 2, 0);
}
}
public static int toProperties(byte target[], int offset, Properties props) throws DataFormatException, IOException {
if (props != null) {
OrderedProperties p = new OrderedProperties();
p.putAll(props);
ByteArrayOutputStream baos = new ByteArrayOutputStream(32);
for (Iterator iter = p.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
String val = p.getProperty(key);
// now make sure they're in UTF-8
//key = new String(key.getBytes(), "UTF-8");
//val = new String(val.getBytes(), "UTF-8");
writeString(baos, key);
baos.write(_equalBytes);
writeString(baos, val);
baos.write(_semicolonBytes);
}
baos.close();
byte propBytes[] = baos.toByteArray();
toLong(target, offset, 2, propBytes.length);
offset += 2;
System.arraycopy(propBytes, 0, target, offset, propBytes.length);
offset += propBytes.length;
return offset;
} else {
toLong(target, offset, 2, 0);
return offset + 2;
}
}
public static int fromProperties(byte source[], int offset, Properties target) throws DataFormatException, IOException {
int size = (int)fromLong(source, offset, 2);
offset += 2;
ByteArrayInputStream in = new ByteArrayInputStream(source, offset, size);
byte eqBuf[] = new byte[_equalBytes.length];
byte semiBuf[] = new byte[_semicolonBytes.length];
while (in.available() > 0) {
String key = readString(in);
int read = read(in, eqBuf);
if ((read != eqBuf.length) || (!eq(eqBuf, _equalBytes))) {
break;
}
String val = readString(in);
read = read(in, semiBuf);
if ((read != semiBuf.length) || (!eq(semiBuf, _semicolonBytes))) {
break;
}
target.put(key, val);
}
return offset + size;
}
public static byte[] toProperties(Properties opts) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(2);
writeProperties(baos, opts);
return baos.toByteArray();
} catch (DataFormatException dfe) {
throw new RuntimeException("Format error writing to memory?! " + dfe.getMessage());
} catch (IOException ioe) {
throw new RuntimeException("IO error writing to memory?! " + ioe.getMessage());
}
}
/**
* Pretty print the mapping
*
@@ -147,9 +211,12 @@ public class DataHelper {
*
*/
public static void loadProps(Properties props, File file) throws IOException {
loadProps(props, new FileInputStream(file));
}
public static void loadProps(Properties props, InputStream inStr) throws IOException {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(new FileInputStream(file)), 16*1024);
in = new BufferedReader(new InputStreamReader(inStr), 16*1024);
String line = null;
while ( (line = in.readLine()) != null) {
if (line.trim().length() <= 0) continue;
@@ -258,15 +325,32 @@ public class DataHelper {
throws DataFormatException, IOException {
if (numBytes > 8)
throw new DataFormatException("readLong doesn't currently support reading numbers > 8 bytes [as thats bigger than java's long]");
byte data[] = new byte[numBytes];
int num = read(rawStream, data);
if (num != numBytes)
throw new DataFormatException("Not enough bytes [" + num + "] as required for the field [" + numBytes + "]");
UnsignedInteger val = new UnsignedInteger(data);
return val.getLong();
long rv = 0;
for (int i = 0; i < numBytes; i++) {
long cur = rawStream.read() & 0xFF;
if (cur == -1) throw new DataFormatException("Not enough bytes for the field");
// we loop until we find a nonzero byte (or we reach the end)
if (cur != 0) {
// ok, data found, now iterate through it to fill the rv
long remaining = numBytes - i;
for (int j = 0; j < remaining; j++) {
long shiftAmount = 8 * (remaining-j-1);
cur = cur << shiftAmount;
rv += cur;
if (j + 1 < remaining) {
cur = rawStream.read() & 0xFF;
if (cur == -1)
throw new DataFormatException("Not enough bytes for the field");
}
}
break;
}
}
return rv;
}
/** Write an integer as defined by the I2P data structure specification to the stream.
* Integers are a fixed number of bytes (numBytes), stored as unsigned integers in network byte order.
* @param value value to write out
@@ -277,12 +361,10 @@ public class DataHelper {
*/
public static void writeLong(OutputStream rawStream, int numBytes, long value)
throws DataFormatException, IOException {
try {
UnsignedInteger.writeBytes(rawStream, numBytes, value);
//UnsignedInteger i = new UnsignedInteger(value);
//rawStream.write(i.getBytes(numBytes));
} catch (IllegalArgumentException iae) {
throw new DataFormatException("Invalid value (must be positive)", iae);
for (int i = numBytes - 1; i >= 0; i--) {
byte cur = (byte)( (value >>> (i*8) ) & 0xFF);
rawStream.write(cur);
}
}
@@ -322,7 +404,7 @@ public class DataHelper {
for (long i = 0; i <= 0xFFFF; i++)
testLong(2, i);
System.out.println("Test 2byte passed");
for (long i = 0; i <= 0xFFFFFF; i++)
for (long i = 0; i <= 0xFFFFFF; i ++)
testLong(3, i);
System.out.println("Test 3byte passed");
for (long i = 0; i <= 0xFFFFFFFF; i++)
@@ -344,6 +426,9 @@ public class DataHelper {
long read = fromLong(extract, 0, extract.length);
if (read != value)
throw new RuntimeException("testLong("+numBytes+","+value+") FAILED on read (" + read + ")");
read = readLong(new ByteArrayInputStream(written), numBytes);
if (read != value)
throw new RuntimeException("testLong("+numBytes+","+value+") FAILED on readLong (" + read + ")");
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
@@ -384,6 +469,9 @@ public class DataHelper {
else
return toLong(DATE_LENGTH, date.getTime());
}
public static void toDate(byte target[], int offset, long when) throws IllegalArgumentException {
toLong(target, offset, DATE_LENGTH, when);
}
public static Date fromDate(byte src[], int offset) throws DataFormatException {
if ( (src == null) || (offset + DATE_LENGTH > src.length) )
throw new DataFormatException("Not enough data to read a date");
@@ -479,9 +567,29 @@ public class DataHelper {
writeLong(out, 1, BOOLEAN_FALSE);
}
public static Boolean fromBoolean(byte data[], int offset) {
if (data[offset] == BOOLEAN_TRUE)
return Boolean.TRUE;
else if (data[offset] == BOOLEAN_FALSE)
return Boolean.FALSE;
else
return null;
}
public static void toBoolean(byte data[], int offset, boolean value) {
data[offset] = (value ? BOOLEAN_TRUE : BOOLEAN_FALSE);
}
public static void toBoolean(byte data[], int offset, Boolean value) {
if (value == null)
data[offset] = BOOLEAN_UNKNOWN;
else
data[offset] = (value.booleanValue() ? BOOLEAN_TRUE : BOOLEAN_FALSE);
}
public static final byte BOOLEAN_TRUE = 0x1;
public static final byte BOOLEAN_FALSE = 0x0;
public static final byte BOOLEAN_UNKNOWN = 0x2;
public static final int BOOLEAN_LENGTH = 1;
//
// The following comparator helpers make it simpler to write consistently comparing
@@ -762,12 +870,13 @@ public class DataHelper {
public static byte[] compress(byte orig[], int offset, int size) {
if ((orig == null) || (orig.length <= 0)) return orig;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
CachingByteArrayOutputStream baos = new CachingByteArrayOutputStream(16, 40*1024);
GZIPOutputStream out = new GZIPOutputStream(baos, size);
out.write(orig, offset, size);
out.finish();
out.flush();
byte rv[] = baos.toByteArray();
baos.releaseBuffer();
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Compression of " + orig.length + " into " + rv.length + " (or " + 100.0d
// * (((double) orig.length) / ((double) rv.length)) + "% savings)");
@@ -785,7 +894,7 @@ public class DataHelper {
public static byte[] decompress(byte orig[], int offset, int length) throws IOException {
if ((orig == null) || (orig.length <= 0)) return orig;
GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(orig, offset, length), length);
ByteArrayOutputStream baos = new ByteArrayOutputStream(length * 2);
CachingByteArrayOutputStream baos = new CachingByteArrayOutputStream(16, 40*1024);
ByteCache cache = ByteCache.getInstance(10, 4*1024);
ByteArray ba = cache.acquire();
byte buf[] = ba.getData(); // new byte[4 * 1024];
@@ -796,6 +905,7 @@ public class DataHelper {
}
byte rv[] = baos.toByteArray();
cache.release(ba);
baos.releaseBuffer();
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Decompression of " + orig.length + " into " + rv.length + " (or " + 100.0d
// * (((double) rv.length) / ((double) orig.length)) + "% savings)");

View File

@@ -25,14 +25,14 @@ import net.i2p.util.Log;
*/
public class Lease extends DataStructureImpl {
private final static Log _log = new Log(Lease.class);
private RouterIdentity _routerIdentity;
private Hash _gateway;
private TunnelId _tunnelId;
private Date _end;
private int _numSuccess;
private int _numFailure;
public Lease() {
setRouterIdentity(null);
setGateway(null);
setTunnelId(null);
setEndDate(null);
setNumSuccess(0);
@@ -42,15 +42,15 @@ public class Lease extends DataStructureImpl {
/** Retrieve the router at which the destination can be contacted
* @return identity of the router acting as a gateway
*/
public RouterIdentity getRouterIdentity() {
return _routerIdentity;
public Hash getGateway() {
return _gateway;
}
/** Configure the router at which the destination can be contacted
* @param ident router acting as the gateway
*/
public void setRouterIdentity(RouterIdentity ident) {
_routerIdentity = ident;
public void setGateway(Hash ident) {
_gateway = ident;
}
/** Tunnel on the gateway to communicate with
@@ -113,18 +113,18 @@ public class Lease extends DataStructureImpl {
}
public void readBytes(InputStream in) throws DataFormatException, IOException {
_routerIdentity = new RouterIdentity();
_routerIdentity.readBytes(in);
_gateway = new Hash();
_gateway.readBytes(in);
_tunnelId = new TunnelId();
_tunnelId.readBytes(in);
_end = DataHelper.readDate(in);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if ((_routerIdentity == null) || (_tunnelId == null))
if ((_gateway == null) || (_tunnelId == null))
throw new DataFormatException("Not enough data to write out a Lease");
_routerIdentity.writeBytes(out);
_gateway.writeBytes(out);
_tunnelId.writeBytes(out);
DataHelper.writeDate(out, _end);
}
@@ -133,12 +133,13 @@ public class Lease extends DataStructureImpl {
if ((object == null) || !(object instanceof Lease)) return false;
Lease lse = (Lease) object;
return DataHelper.eq(getEndDate(), lse.getEndDate())
&& DataHelper.eq(getRouterIdentity(), lse.getRouterIdentity());
&& DataHelper.eq(getTunnelId(), lse.getTunnelId())
&& DataHelper.eq(getGateway(), lse.getGateway());
}
public int hashCode() {
return DataHelper.hashCode(getEndDate()) + DataHelper.hashCode(getRouterIdentity())
return DataHelper.hashCode(getEndDate()) + DataHelper.hashCode(getGateway())
+ DataHelper.hashCode(getTunnelId());
}
@@ -146,7 +147,7 @@ public class Lease extends DataStructureImpl {
StringBuffer buf = new StringBuffer(128);
buf.append("[Lease: ");
buf.append("\n\tEnd Date: ").append(getEndDate());
buf.append("\n\tRouter Identity: ").append(getRouterIdentity());
buf.append("\n\tGateway: ").append(getGateway());
buf.append("\n\tTunnelId: ").append(getTunnelId());
buf.append("]");
return buf.toString();

View File

@@ -74,12 +74,18 @@ public class LeaseSet extends DataStructureImpl {
}
public void addLease(Lease lease) {
if (lease == null) throw new IllegalArgumentException("erm, null lease");
if (lease.getGateway() == null) throw new IllegalArgumentException("erm, lease has no gateway");
if (lease.getTunnelId() == null) throw new IllegalArgumentException("erm, lease has no tunnel");
_leases.add(lease);
}
public void removeLease(Lease lease) {
_leases.remove(lease);
}
public void removeLease(int index) {
_leases.remove(index);
}
public int getLeaseCount() {
return _leases.size();
@@ -208,16 +214,19 @@ public class LeaseSet extends DataStructureImpl {
for (int i = 0; i < cnt; i++) {
Lease l = getLease(i);
if (l.getEndDate().getTime() > insane) {
_log.warn("LeaseSet" + calculateHash() + " expires an insane amount in the future - skip it: " + l);
if (_log.shouldLog(Log.WARN))
_log.warn("LeaseSet" + calculateHash() + " expires an insane amount in the future - skip it: " + l);
return false;
}
// if it hasn't finished, we're current
if (l.getEndDate().getTime() > now) {
_log.debug("LeaseSet " + calculateHash() + " isn't exired: " + l);
if (_log.shouldLog(Log.DEBUG))
_log.debug("LeaseSet " + calculateHash() + " isn't exired: " + l);
return true;
} else if (l.getEndDate().getTime() > now - fudge) {
_log.debug("LeaseSet " + calculateHash()
+ " isn't quite expired, but its within the fudge factor so we'll let it slide: " + l);
if (_log.shouldLog(Log.DEBUG))
_log.debug("LeaseSet " + calculateHash()
+ " isn't quite expired, but its within the fudge factor so we'll let it slide: " + l);
return true;
}
}
@@ -225,7 +234,14 @@ public class LeaseSet extends DataStructureImpl {
}
private byte[] getBytes() {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int len = PublicKey.KEYSIZE_BYTES // dest
+ SigningPublicKey.KEYSIZE_BYTES // dest
+ 4 // cert
+ PublicKey.KEYSIZE_BYTES // encryptionKey
+ SigningPublicKey.KEYSIZE_BYTES // signingKey
+ 1
+ _leases.size() * 44; // leases
ByteArrayOutputStream out = new ByteArrayOutputStream(len);
try {
if ((_destination == null) || (_encryptionKey == null) || (_signingKey == null) || (_leases == null))
return null;
@@ -244,7 +260,8 @@ public class LeaseSet extends DataStructureImpl {
} catch (DataFormatException dfe) {
return null;
}
return out.toByteArray();
byte rv[] = out.toByteArray();
return rv;
}
public void readBytes(InputStream in) throws DataFormatException, IOException {

View File

@@ -49,6 +49,8 @@ public class RouterInfo extends DataStructureImpl {
private volatile int _hashCode;
private volatile boolean _hashCodeInitialized;
public static final String PROP_NETWORK_ID = "netId";
public RouterInfo() {
setIdentity(null);
setPublished(0);
@@ -243,7 +245,7 @@ public class RouterInfo extends DataStructureImpl {
if (_options == null) throw new DataFormatException("Router options isn't set? wtf!");
long before = Clock.getInstance().now();
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream(6*1024);
try {
_identity.writeBytes(out);
DataHelper.writeDate(out, new Date(_published));
@@ -279,6 +281,24 @@ public class RouterInfo extends DataStructureImpl {
return _isValid;
}
/**
* which network is this routerInfo a part of. configured through the property
* PROP_NETWORK_ID
*/
public int getNetworkId() {
if (_options == null) return -1;
String id = null;
synchronized (_options) {
id = _options.getProperty(PROP_NETWORK_ID);
}
if (id != null) {
try {
return Integer.parseInt(id);
} catch (NumberFormatException nfe) {}
}
return -1;
}
/**
* Get the routing key for the structure using the current modifier in the RoutingKeyGenerator.
* This only calculates a new one when necessary though (if the generator's key modifier changes)
@@ -422,19 +442,17 @@ public class RouterInfo extends DataStructureImpl {
public boolean equals(Object object) {
if ((object == null) || !(object instanceof RouterInfo)) return false;
RouterInfo info = (RouterInfo) object;
return DataHelper.eq(_addresses, info.getAddresses())
&& DataHelper.eq(_identity, info.getIdentity())
&& DataHelper.eq(_options, info.getOptions())
&& DataHelper.eq(_peers, info.getPeers())
return DataHelper.eq(_identity, info.getIdentity())
&& DataHelper.eq(_signature, info.getSignature())
&& DataHelper.eq(getPublished(), info.getPublished());
&& DataHelper.eq(getPublished(), info.getPublished())
&& DataHelper.eq(_addresses, info.getAddresses())
&& DataHelper.eq(_options, info.getOptions())
&& DataHelper.eq(_peers, info.getPeers());
}
public int hashCode() {
if (!_hashCodeInitialized) {
_hashCode = DataHelper.hashCode(_addresses) + DataHelper.hashCode(_identity)
+ DataHelper.hashCode(_options) + DataHelper.hashCode(_peers)
+ DataHelper.hashCode(_signature) + (int) getPublished();
_hashCode = DataHelper.hashCode(_identity) + (int) getPublished();
_hashCodeInitialized = true;
}
return _hashCode;

View File

@@ -34,6 +34,8 @@ public class TunnelId extends DataStructureImpl {
public final static int TYPE_OUTBOUND = 2;
public final static int TYPE_PARTICIPANT = 3;
public static final TunnelId INVALID = new TunnelId(0, true);
public TunnelId() {
_tunnelId = -1;
_type = TYPE_UNSPECIFIED;
@@ -48,6 +50,9 @@ public class TunnelId extends DataStructureImpl {
_tunnelId = id;
_type = type;
}
private TunnelId(long id, boolean forceInvalid) {
_tunnelId = id;
}
public long getTunnelId() { return _tunnelId; }
public void setTunnelId(long id) {
@@ -87,7 +92,5 @@ public class TunnelId extends DataStructureImpl {
return (int)getTunnelId();
}
public String toString() {
return "[TunnelID: " + getTunnelId() + "]";
}
public String toString() { return String.valueOf(getTunnelId()); }
}

View File

@@ -18,7 +18,7 @@ import java.util.List;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.RouterIdentity;
import net.i2p.data.Hash;
import net.i2p.data.TunnelId;
import net.i2p.util.Log;
@@ -53,7 +53,7 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
return _endpoints.size();
}
public RouterIdentity getRouter(int endpoint) {
public Hash getRouter(int endpoint) {
if ((endpoint < 0) || (_endpoints.size() < endpoint)) return null;
return ((TunnelEndpoint) _endpoints.get(endpoint)).getRouter();
}
@@ -67,7 +67,9 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
if ((endpoint >= 0) && (endpoint < _endpoints.size())) _endpoints.remove(endpoint);
}
public void addEndpoint(RouterIdentity router, TunnelId tunnel) {
public void addEndpoint(Hash router, TunnelId tunnel) {
if (router == null) throw new IllegalArgumentException("Null router (tunnel=" + tunnel +")");
if (tunnel == null) throw new IllegalArgumentException("Null tunnel (router=" + router +")");
_endpoints.add(new TunnelEndpoint(router, tunnel));
}
@@ -86,7 +88,7 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
int numTunnels = (int) DataHelper.readLong(in, 1);
_endpoints.clear();
for (int i = 0; i < numTunnels; i++) {
RouterIdentity router = new RouterIdentity();
Hash router = new Hash();
router.readBytes(in);
TunnelId tunnel = new TunnelId();
tunnel.readBytes(in);
@@ -106,7 +108,7 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
_sessionId.writeBytes(os);
DataHelper.writeLong(os, 1, _endpoints.size());
for (int i = 0; i < _endpoints.size(); i++) {
RouterIdentity router = getRouter(i);
Hash router = getRouter(i);
router.writeBytes(os);
TunnelId tunnel = getTunnelId(i);
tunnel.writeBytes(os);
@@ -151,7 +153,7 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
}
private class TunnelEndpoint {
private RouterIdentity _router;
private Hash _router;
private TunnelId _tunnelId;
public TunnelEndpoint() {
@@ -159,16 +161,16 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
_tunnelId = null;
}
public TunnelEndpoint(RouterIdentity router, TunnelId id) {
public TunnelEndpoint(Hash router, TunnelId id) {
_router = router;
_tunnelId = id;
}
public RouterIdentity getRouter() {
public Hash getRouter() {
return _router;
}
public void setRouter(RouterIdentity router) {
public void setRouter(Hash router) {
_router = router;
}

View File

@@ -33,6 +33,8 @@ import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
/**
@@ -62,8 +64,12 @@ public class NtpClient {
public static long currentTime(String serverNames[]) {
if (serverNames == null)
throw new IllegalArgumentException("No NTP servers specified");
for (int i = 0; i < serverNames.length; i++) {
long now = currentTime(serverNames[i]);
ArrayList names = new ArrayList(serverNames.length);
for (int i = 0; i < serverNames.length; i++)
names.add(serverNames[i]);
Collections.shuffle(names);
for (int i = 0; i < names.size(); i++) {
long now = currentTime((String)names.get(i));
if (now > 0)
return now;
}
@@ -112,8 +118,9 @@ public class NtpClient {
(msg.transmitTimestamp - destinationTimestamp)) / 2;
socket.close();
//System.out.println("host: " + serverName + " rtt: " + roundTripDelay + " offset: " + localClockOffset + " seconds");
return (long)(System.currentTimeMillis() + localClockOffset*1000);
long rv = (long)(System.currentTimeMillis() + localClockOffset*1000);
//System.out.println("host: " + address.getHostAddress() + " rtt: " + roundTripDelay + " offset: " + localClockOffset + " seconds");
return rv;
} catch (IOException ioe) {
//ioe.printStackTrace();
return -1;

View File

@@ -20,17 +20,25 @@ public class Timestamper implements Runnable {
private List _servers;
private List _listeners;
private int _queryFrequency;
private int _concurringServers;
private volatile boolean _disabled;
private boolean _daemon;
private boolean _initialized;
private static final int DEFAULT_QUERY_FREQUENCY = 5*60*1000;
private static final String DEFAULT_SERVER_LIST = "pool.ntp.org, pool.ntp.org";
private static final boolean DEFAULT_DISABLED = true;
/** how many times do we have to query if we are changing the clock? */
private static final int DEFAULT_CONCURRING_SERVERS = 2;
public static final String PROP_QUERY_FREQUENCY = "time.queryFrequencyMs";
public static final String PROP_SERVER_LIST = "time.sntpServerList";
public static final String PROP_DISABLED = "time.disabled";
public static final String PROP_CONCURRING_SERVERS = "time.concurringServers";
/** if different SNTP servers differ by more than 10s, someone is b0rked */
private static final int MAX_VARIANCE = 10*1000;
public Timestamper(I2PAppContext ctx) {
this(ctx, null, true);
}
@@ -41,6 +49,7 @@ public class Timestamper implements Runnable {
public Timestamper(I2PAppContext ctx, UpdateListener lsnr, boolean daemon) {
_context = ctx;
_daemon = daemon;
_initialized = false;
_servers = new ArrayList(1);
_listeners = new ArrayList(1);
if (lsnr != null)
@@ -114,10 +123,7 @@ public class Timestamper implements Runnable {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Querying servers " + _servers);
try {
long now = NtpClient.currentTime(serverList);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Stamp time");
stampTime(now);
queryTime(serverList);
} catch (IllegalArgumentException iae) {
if (!alreadyBitched)
_log.log(Log.CRIT, "Unable to reach any of the NTP servers - network disconnected?");
@@ -132,6 +138,35 @@ public class Timestamper implements Runnable {
}
}
private void queryTime(String serverList[]) throws IllegalArgumentException {
long localTime = -1;
long now = -1;
long expectedDelta = 0;
for (int i = 0; i < _concurringServers; i++) {
localTime = _context.clock().now();
now = NtpClient.currentTime(serverList);
long delta = now - localTime;
if (i == 0) {
if (Math.abs(delta) < MAX_VARIANCE) {
if (_log.shouldLog(Log.INFO))
_log.info("a single SNTP query was within the tolerance (" + delta + "ms)");
return;
} else {
// outside the tolerance, lets iterate across the concurring queries
expectedDelta = delta;
}
} else {
if (Math.abs(delta - expectedDelta) > MAX_VARIANCE) {
if (_log.shouldLog(Log.ERROR))
_log.error("SNTP client variance exceeded at query " + i + ". expected = " + expectedDelta + ", found = " + delta);
return;
}
}
}
stampTime(now);
}
/**
* Send an HTTP request to a given URL specifying the current time
*/
@@ -142,6 +177,8 @@ public class Timestamper implements Runnable {
lsnr.setNow(now);
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Stamped the time as " + now);
}
/**
@@ -185,6 +222,31 @@ public class Timestamper implements Runnable {
if (disabled == null)
disabled = DEFAULT_DISABLED + "";
_disabled = Boolean.valueOf(disabled).booleanValue();
String concurring = _context.getProperty(PROP_CONCURRING_SERVERS);
if (concurring == null) {
_concurringServers = DEFAULT_CONCURRING_SERVERS;
} else {
try {
int servers = Integer.parseInt(concurring);
if ( (servers > 0) && (servers < 5) )
_concurringServers = servers;
else
_concurringServers = DEFAULT_CONCURRING_SERVERS;
} catch (NumberFormatException nfe) {
_concurringServers = DEFAULT_CONCURRING_SERVERS;
}
}
}
public static void main(String args[]) {
System.setProperty(PROP_DISABLED, "false");
System.setProperty(PROP_QUERY_FREQUENCY, "30000");
I2PAppContext ctx = I2PAppContext.getGlobalContext();
long now = ctx.clock().now();
for (int i = 0; i < 5*60*1000; i += 61*1000) {
try { Thread.sleep(61*1000); } catch (InterruptedException ie) {}
}
}
/**

View File

@@ -18,6 +18,7 @@ public class Clock implements Timestamper.UpdateListener {
private I2PAppContext _context;
private Timestamper _timestamper;
private long _startedOn;
private boolean _statCreated;
public Clock(I2PAppContext context) {
_context = context;
@@ -26,6 +27,7 @@ public class Clock implements Timestamper.UpdateListener {
_listeners = new HashSet(64);
_timestamper = new Timestamper(context, this);
_startedOn = System.currentTimeMillis();
_statCreated = false;
}
public static Clock getInstance() {
return I2PAppContext.getGlobalContext().clock();
@@ -78,10 +80,15 @@ public class Clock implements Timestamper.UpdateListener {
return;
}
}
if (_alreadyChanged)
if (_alreadyChanged) {
getLog().log(Log.CRIT, "Updating clock offset to " + offsetMs + "ms from " + _offset + "ms");
else
if (!_statCreated)
_context.statManager().createRateStat("clock.skew", "How far is the already adjusted clock being skewed?", "Clock", new long[] { 10*60*1000, 3*60*60*1000, 24*60*60*60 });
_statCreated = true;
_context.statManager().addRateData("clock.skew", delta, 0);
} else {
getLog().log(Log.INFO, "Initializing clock offset to " + offsetMs + "ms from " + _offset + "ms");
}
_alreadyChanged = true;
_offset = offsetMs;
fireOffsetChanged(delta);

View File

@@ -97,6 +97,7 @@ public class NativeBigInteger extends BigInteger {
private final static String JBIGI_OPTIMIZATION_K6_2 = "k62";
private final static String JBIGI_OPTIMIZATION_K6_3 = "k63";
private final static String JBIGI_OPTIMIZATION_ATHLON = "athlon";
private final static String JBIGI_OPTIMIZATION_ATHLON64 = "athlon64";
private final static String JBIGI_OPTIMIZATION_PENTIUM = "pentium";
private final static String JBIGI_OPTIMIZATION_PENTIUMMMX = "pentiummmx";
private final static String JBIGI_OPTIMIZATION_PENTIUM2 = "pentium2";
@@ -130,6 +131,8 @@ public class NativeBigInteger extends BigInteger {
CPUInfo c = CPUID.getInfo();
if (c instanceof AMDCPUInfo) {
AMDCPUInfo amdcpu = (AMDCPUInfo) c;
if (amdcpu.IsAthlon64Compatible())
return JBIGI_OPTIMIZATION_ATHLON64;
if (amdcpu.IsAthlonCompatible())
return JBIGI_OPTIMIZATION_ATHLON;
if (amdcpu.IsK6_3_Compatible())

View File

@@ -49,7 +49,9 @@ public class SimpleTimer {
*
*/
public void addEvent(TimedEvent event, long timeoutMs) {
long eventTime = System.currentTimeMillis() + timeoutMs;
int totalEvents = 0;
long now = System.currentTimeMillis();
long eventTime = now + timeoutMs;
Long time = new Long(eventTime);
synchronized (_events) {
// remove the old scheduled position, then reinsert it
@@ -72,8 +74,20 @@ public class SimpleTimer {
}
}
totalEvents = _events.size();
_events.notifyAll();
}
if (time.longValue() > eventTime + 5) {
if (_log.shouldLog(Log.ERROR))
_log.error("Lots of timer congestion, had to push " + event + " back "
+ (time.longValue()-eventTime) + "ms (# events: " + totalEvents + ")");
}
long timeToAdd = System.currentTimeMillis() - now;
if (timeToAdd > 50) {
if (_log.shouldLog(Log.WARN))
_log.warn("timer contention: took " + timeToAdd + "ms to add a job");
}
}
public boolean removeEvent(TimedEvent evt) {