forked from I2P_Developers/i2p.i2p
* Data Structures:
- Make Destination and RouterIdentity keys and cert immutable - Add Destination cache
This commit is contained in:
@ -65,12 +65,9 @@ public final class I2PDatagramDissector {
|
||||
this.valid = false;
|
||||
|
||||
try {
|
||||
rxDest = new Destination();
|
||||
rxSign = new Signature();
|
||||
|
||||
// read destination
|
||||
rxDest.readBytes(dgStream);
|
||||
|
||||
rxDest = Destination.create(dgStream);
|
||||
rxSign = new Signature();
|
||||
// read signature
|
||||
rxSign.readBytes(dgStream);
|
||||
|
||||
@ -155,6 +152,7 @@ public final class I2PDatagramDissector {
|
||||
* @return The Destination of the I2P repliable datagram sender
|
||||
*/
|
||||
public Destination extractSender() {
|
||||
/****
|
||||
if (this.rxDest == null)
|
||||
return null;
|
||||
Destination retDest = new Destination();
|
||||
@ -167,6 +165,9 @@ public final class I2PDatagramDissector {
|
||||
}
|
||||
|
||||
return retDest;
|
||||
****/
|
||||
// dests are no longer modifiable
|
||||
return rxDest;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1162,12 +1162,12 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
/** returns null on error */
|
||||
public Object construct(byte[] b) {
|
||||
DestEntry rv = new DestEntry();
|
||||
Destination dest = new Destination();
|
||||
rv.dest = dest;
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(b);
|
||||
try {
|
||||
rv.props = DataHelper.readProperties(bais);
|
||||
dest.readBytes(bais);
|
||||
//dest.readBytes(bais);
|
||||
// Will this flush the dest cache too much?
|
||||
rv.dest = Destination.create(bais);
|
||||
} catch (IOException ioe) {
|
||||
logError("DB Read Fail", ioe);
|
||||
return null;
|
||||
|
@ -45,7 +45,7 @@ public class Certificate extends DataStructureImpl {
|
||||
|
||||
/**
|
||||
* If null cert, return immutable static instance, else create new
|
||||
* @throws AIOOBE if not enough bytes
|
||||
* @throws AIOOBE if not enough bytes, FIXME should throw DataFormatException
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public static Certificate create(byte[] data, int off) {
|
||||
|
@ -32,10 +32,13 @@ import java.io.OutputStream;
|
||||
* @author jrandom
|
||||
*/
|
||||
public interface DataStructure /* extends Serializable */ {
|
||||
|
||||
/**
|
||||
* Load up the current object with data from the given stream. Data loaded
|
||||
* this way must match the I2P data structure specification.
|
||||
*
|
||||
* Warning - many classes will throw IllegalStateException if data is already set.
|
||||
*
|
||||
* @param in stream to read from
|
||||
* @throws DataFormatException if the data is improperly formatted
|
||||
* @throws IOException if there was a problem reading the stream
|
||||
@ -61,11 +64,24 @@ public interface DataStructure /* extends Serializable */ {
|
||||
/**
|
||||
* Load the structure from the base 64 encoded data provided
|
||||
*
|
||||
* Warning - many classes will throw IllegalStateException if data is already set.
|
||||
* Warning - many classes will throw IllegalArgumentException if data is the wrong size.
|
||||
*
|
||||
*/
|
||||
public void fromBase64(String data) throws DataFormatException;
|
||||
|
||||
/**
|
||||
* @return may be null if data is not set
|
||||
*/
|
||||
public byte[] toByteArray();
|
||||
|
||||
/**
|
||||
* Load the structure from the data provided
|
||||
*
|
||||
* Warning - many classes will throw IllegalStateException if data is already set.
|
||||
* Warning - many classes will throw IllegalArgumentException if data is the wrong size.
|
||||
*
|
||||
*/
|
||||
public void fromByteArray(byte data[]) throws DataFormatException;
|
||||
|
||||
/**
|
||||
|
@ -32,16 +32,19 @@ public abstract class DataStructureImpl implements DataStructure {
|
||||
|
||||
return Base64.encode(data);
|
||||
}
|
||||
|
||||
public void fromBase64(String data) throws DataFormatException {
|
||||
if (data == null) throw new DataFormatException("Null data passed in");
|
||||
byte bytes[] = Base64.decode(data);
|
||||
fromByteArray(bytes);
|
||||
}
|
||||
|
||||
public Hash calculateHash() {
|
||||
byte data[] = toByteArray();
|
||||
if (data != null) return SHA256Generator.getInstance().calculateHash(data);
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] toByteArray() {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
|
||||
@ -57,6 +60,7 @@ public abstract class DataStructureImpl implements DataStructure {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void fromByteArray(byte data[]) throws DataFormatException {
|
||||
if (data == null) throw new DataFormatException("Null data passed in");
|
||||
try {
|
||||
|
@ -9,6 +9,14 @@ package net.i2p.data;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.LHMCache;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
/**
|
||||
* Defines an end point in the I2P network. The Destination may move around
|
||||
* in the network, but messages sent to the Destination will find it
|
||||
@ -20,13 +28,56 @@ package net.i2p.data;
|
||||
* The first bytes of the public key are used for the IV for leaseset encryption,
|
||||
* but that encryption is poorly designed and should be deprecated.
|
||||
*
|
||||
* As of 0.9.9 this data structure is immutable after the two keys and the certificate
|
||||
* are set; attempts to change them will throw an IllegalStateException.
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
public class Destination extends KeysAndCert {
|
||||
|
||||
public Destination() {
|
||||
private String _cachedB64;
|
||||
|
||||
//private static final boolean STATS = true;
|
||||
private static final int CACHE_SIZE;
|
||||
private static final int MIN_CACHE_SIZE = 32;
|
||||
private static final int MAX_CACHE_SIZE = 512;
|
||||
static {
|
||||
long maxMemory = SystemVersion.getMaxMemory();
|
||||
CACHE_SIZE = (int) Math.min(MAX_CACHE_SIZE, Math.max(MIN_CACHE_SIZE, maxMemory / 512*1024));
|
||||
//if (STATS)
|
||||
// I2PAppContext.getGlobalContext().statManager().createRateStat("DestCache", "Hit rate", "Router", new long[] { 10*60*1000 });
|
||||
}
|
||||
|
||||
private static final Map<SigningPublicKey, Destination> _cache = new LHMCache(CACHE_SIZE);
|
||||
|
||||
/**
|
||||
* Pull from cache or return new
|
||||
* @since 0.9.9
|
||||
*/
|
||||
public static Destination create(InputStream in) throws DataFormatException, IOException {
|
||||
PublicKey pk = PublicKey.create(in);
|
||||
SigningPublicKey sk = SigningPublicKey.create(in);
|
||||
Certificate c = Certificate.create(in);
|
||||
Destination rv;
|
||||
synchronized(_cache) {
|
||||
rv = _cache.get(sk);
|
||||
}
|
||||
if (rv != null && rv.getPublicKey().equals(pk) && rv.getCertificate().equals(c)) {
|
||||
//if (STATS)
|
||||
// I2PAppContext.getGlobalContext().statManager().addRateData("DestCache", 1);
|
||||
return rv;
|
||||
}
|
||||
//if (STATS)
|
||||
// I2PAppContext.getGlobalContext().statManager().addRateData("DestCache", 0);
|
||||
rv = new Destination(pk, sk, c);
|
||||
synchronized(_cache) {
|
||||
_cache.put(sk, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public Destination() {}
|
||||
|
||||
/**
|
||||
* alternative constructor which takes a base64 string representation
|
||||
* @param s a Base64 representation of the destination, as (eg) is used in hosts.txt
|
||||
@ -35,6 +86,15 @@ public class Destination extends KeysAndCert {
|
||||
fromBase64(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.9
|
||||
*/
|
||||
private Destination(PublicKey pk, SigningPublicKey sk, Certificate c) {
|
||||
_publicKey = pk;
|
||||
_signingKey = sk;
|
||||
_certificate = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* deprecated, used only by Packet.java in streaming
|
||||
* @return the written length (NOT the new offset)
|
||||
@ -49,11 +109,17 @@ public class Destination extends KeysAndCert {
|
||||
return cur - offset;
|
||||
}
|
||||
|
||||
/** deprecated, used only by Packet.java in streaming */
|
||||
/**
|
||||
* @deprecated, was used only by Packet.java in streaming, now unused
|
||||
*
|
||||
* @throws IllegalStateException if data already set
|
||||
*/
|
||||
public int readBytes(byte source[], int offset) throws DataFormatException {
|
||||
if (source == null) throw new DataFormatException("Null source");
|
||||
if (source.length <= offset + PublicKey.KEYSIZE_BYTES + SigningPublicKey.KEYSIZE_BYTES)
|
||||
throw new DataFormatException("Not enough data (len=" + source.length + " off=" + offset + ")");
|
||||
if (_publicKey != null || _signingKey != null || _certificate != null)
|
||||
throw new IllegalStateException();
|
||||
int cur = offset;
|
||||
|
||||
_publicKey = PublicKey.create(source, cur);
|
||||
@ -71,4 +137,26 @@ public class Destination extends KeysAndCert {
|
||||
public int size() {
|
||||
return PublicKey.KEYSIZE_BYTES + SigningPublicKey.KEYSIZE_BYTES + _certificate.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache it.
|
||||
* Useful in I2PTunnelHTTPServer where it is added to the headers
|
||||
* @since 0.9.9
|
||||
*/
|
||||
@Override
|
||||
public String toBase64() {
|
||||
if (_cachedB64 == null)
|
||||
_cachedB64 = super.toBase64();
|
||||
return _cachedB64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache.
|
||||
* @since 0.9.9
|
||||
*/
|
||||
public static void clearCache() {
|
||||
synchronized(_cache) {
|
||||
_cache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,9 @@ import net.i2p.crypto.SHA256Generator;
|
||||
* Implemented in 0.8.2 and retrofitted over Destination and RouterIdentity.
|
||||
* There's actually no difference between the two of them.
|
||||
*
|
||||
* As of 0.9.9 this data structure is immutable after the two keys and the certificate
|
||||
* are set; attempts to change them will throw an IllegalStateException.
|
||||
*
|
||||
* @since 0.8.2
|
||||
* @author zzz
|
||||
*/
|
||||
@ -37,7 +40,12 @@ public class KeysAndCert extends DataStructureImpl {
|
||||
return _certificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalStateException if was already set
|
||||
*/
|
||||
public void setCertificate(Certificate cert) {
|
||||
if (_certificate != null)
|
||||
throw new IllegalStateException();
|
||||
_certificate = cert;
|
||||
__calculatedHash = null;
|
||||
}
|
||||
@ -46,7 +54,12 @@ public class KeysAndCert extends DataStructureImpl {
|
||||
return _publicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalStateException if was already set
|
||||
*/
|
||||
public void setPublicKey(PublicKey key) {
|
||||
if (_publicKey != null)
|
||||
throw new IllegalStateException();
|
||||
_publicKey = key;
|
||||
__calculatedHash = null;
|
||||
}
|
||||
@ -55,20 +68,24 @@ public class KeysAndCert extends DataStructureImpl {
|
||||
return _signingKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalStateException if was already set
|
||||
*/
|
||||
public void setSigningPublicKey(SigningPublicKey key) {
|
||||
if (_signingKey != null)
|
||||
throw new IllegalStateException();
|
||||
_signingKey = key;
|
||||
__calculatedHash = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalStateException if data already set
|
||||
*/
|
||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||
//_publicKey = new PublicKey();
|
||||
//_publicKey.readBytes(in);
|
||||
if (_publicKey != null || _signingKey != null || _certificate != null)
|
||||
throw new IllegalStateException();
|
||||
_publicKey = PublicKey.create(in);
|
||||
//_signingKey = new SigningPublicKey();
|
||||
//_signingKey.readBytes(in);
|
||||
_signingKey = SigningPublicKey.create(in);
|
||||
//_certificate = new Certificate();
|
||||
//_certificate.readBytes(in);
|
||||
_certificate = Certificate.create(in);
|
||||
__calculatedHash = null;
|
||||
}
|
||||
@ -86,9 +103,10 @@ public class KeysAndCert extends DataStructureImpl {
|
||||
if (object == this) return true;
|
||||
if ((object == null) || !(object instanceof KeysAndCert)) return false;
|
||||
KeysAndCert ident = (KeysAndCert) object;
|
||||
return DataHelper.eq(_certificate, ident._certificate)
|
||||
&& DataHelper.eq(_signingKey, ident._signingKey)
|
||||
&& DataHelper.eq(_publicKey, ident._publicKey);
|
||||
return
|
||||
DataHelper.eq(_signingKey, ident._signingKey)
|
||||
&& DataHelper.eq(_publicKey, ident._publicKey)
|
||||
&& DataHelper.eq(_certificate, ident._certificate);
|
||||
}
|
||||
|
||||
/** the public key has enough randomness in it to use it by itself for speed */
|
||||
|
@ -311,8 +311,7 @@ public class LeaseSet extends DatabaseEntry {
|
||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||
if (_destination != null)
|
||||
throw new IllegalStateException();
|
||||
_destination = new Destination();
|
||||
_destination.readBytes(in);
|
||||
_destination = Destination.create(in);
|
||||
_encryptionKey = PublicKey.create(in);
|
||||
_signingKey = SigningPublicKey.create(in);
|
||||
int numLeases = (int) DataHelper.readLong(in, 1);
|
||||
|
@ -26,8 +26,10 @@ public class PublicKey extends SimpleDataStructure {
|
||||
private static final SDSCache<PublicKey> _cache = new SDSCache(PublicKey.class, KEYSIZE_BYTES, CACHE_SIZE);
|
||||
|
||||
/**
|
||||
* Pull from cache or return new
|
||||
* @throws AIOOBE if not enough bytes
|
||||
* Pull from cache or return new.
|
||||
* Deprecated - used only by deprecated Destination.readBytes(data, off)
|
||||
*
|
||||
* @throws AIOOBE if not enough bytes, FIXME should throw DataFormatException
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public static PublicKey create(byte[] data, int off) {
|
||||
|
@ -13,6 +13,9 @@ package net.i2p.data;
|
||||
* Defines the unique identifier of a router, including any certificate or
|
||||
* public key.
|
||||
*
|
||||
* As of 0.9.9 this data structure is immutable after the two keys and the certificate
|
||||
* are set; attempts to change them will throw an IllegalStateException.
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
public class RouterIdentity extends KeysAndCert {
|
||||
|
@ -139,7 +139,7 @@ public class SDSCache<V extends SimpleDataStructure> {
|
||||
found = 0;
|
||||
}
|
||||
}
|
||||
I2PAppContext.getGlobalContext().statManager().addRateData(_statName, found, 0);
|
||||
I2PAppContext.getGlobalContext().statManager().addRateData(_statName, found);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,10 @@ public class SigningPublicKey extends SimpleDataStructure {
|
||||
private final SigType _type;
|
||||
|
||||
/**
|
||||
* Pull from cache or return new
|
||||
* @throws AIOOBE if not enough bytes
|
||||
* Pull from cache or return new.
|
||||
* Deprecated - used only by deprecated Destination.readBytes(data, off)
|
||||
*
|
||||
* @throws AIOOBE if not enough bytes, FIXME should throw DataFormatException
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public static SigningPublicKey create(byte[] data, int off) {
|
||||
|
@ -62,9 +62,7 @@ public class DestReplyMessage extends I2CPMessageImpl {
|
||||
if (size == Hash.HASH_LENGTH) {
|
||||
_hash = Hash.create(in);
|
||||
} else {
|
||||
Destination d = new Destination();
|
||||
d.readBytes(in);
|
||||
_dest = d;
|
||||
_dest = Destination.create(in);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
_dest = null;
|
||||
|
@ -92,8 +92,7 @@ public class SendMessageMessage extends I2CPMessageImpl {
|
||||
try {
|
||||
_sessionId = new SessionId();
|
||||
_sessionId.readBytes(in);
|
||||
_destination = new Destination();
|
||||
_destination.readBytes(in);
|
||||
_destination = Destination.create(in);
|
||||
_payload = new Payload();
|
||||
_payload.readBytes(in);
|
||||
_nonce = DataHelper.readLong(in, 4);
|
||||
|
@ -186,7 +186,7 @@ public class SessionConfig extends DataStructureImpl {
|
||||
}
|
||||
|
||||
public void readBytes(InputStream rawConfig) throws DataFormatException, IOException {
|
||||
_destination = new Destination();
|
||||
_destination = Destination.create(rawConfig);
|
||||
_destination.readBytes(rawConfig);
|
||||
_options = DataHelper.readProperties(rawConfig);
|
||||
_creationDate = DataHelper.readDate(rawConfig);
|
||||
|
Reference in New Issue
Block a user