forked from I2P_Developers/i2p.i2p
* NetDB: Prep for leasesets with different expire times
- Add new I2CP RequestVariableLeaseSetMessage - Send RVLSM if client supports it; handle on client side; disabled by default for the moment. - Add LeaseSet.getLatestLeaseDate() - Check latest, not earliest, date too far in future in KNDF.validate() - Check latest date too far in past in KNDF.validate() - Only check gateway and tunnel ID for equality in OCMOSJ lease caching to reduce churn - Split up KNDF.validate(RI) for efficiency, don't need to check signature, netid, etc. before lookups, only on store - Remove enforeNetID config - Fix major bug causing newer leasesets to be treated as older, and not stored or published - Increase max adjustment time of earliest lease - TransientDataStore cleanups - RouterInfo and LeaseSet equals() speedups
This commit is contained in:
@ -16,6 +16,7 @@ import net.i2p.data.i2cp.DisconnectMessage;
|
||||
import net.i2p.data.i2cp.MessagePayloadMessage;
|
||||
import net.i2p.data.i2cp.MessageStatusMessage;
|
||||
import net.i2p.data.i2cp.RequestLeaseSetMessage;
|
||||
import net.i2p.data.i2cp.RequestVariableLeaseSetMessage;
|
||||
import net.i2p.data.i2cp.SessionStatusMessage;
|
||||
import net.i2p.data.i2cp.SetDateMessage;
|
||||
|
||||
@ -40,6 +41,7 @@ class I2PClientMessageHandlerMap {
|
||||
highest = Math.max(highest, SetDateMessage.MESSAGE_TYPE);
|
||||
highest = Math.max(highest, DestReplyMessage.MESSAGE_TYPE);
|
||||
highest = Math.max(highest, BandwidthLimitsMessage.MESSAGE_TYPE);
|
||||
highest = Math.max(highest, RequestVariableLeaseSetMessage.MESSAGE_TYPE);
|
||||
|
||||
_handlers = new I2CPMessageHandler[highest+1];
|
||||
_handlers[DisconnectMessage.MESSAGE_TYPE] = new DisconnectMessageHandler(context);
|
||||
@ -50,6 +52,7 @@ class I2PClientMessageHandlerMap {
|
||||
_handlers[SetDateMessage.MESSAGE_TYPE] = new SetDateMessageHandler(context);
|
||||
_handlers[DestReplyMessage.MESSAGE_TYPE] = new DestReplyMessageHandler(context);
|
||||
_handlers[BandwidthLimitsMessage.MESSAGE_TYPE] = new BWLimitsMessageHandler(context);
|
||||
_handlers[RequestVariableLeaseSetMessage.MESSAGE_TYPE] = new RequestVariableLeaseSetMessageHandler(context);
|
||||
}
|
||||
|
||||
public I2CPMessageHandler getHandler(int messageTypeId) {
|
||||
|
@ -29,7 +29,8 @@ import net.i2p.data.i2cp.RequestLeaseSetMessage;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handle I2CP RequestLeaseSetMessage from the router by granting all leases
|
||||
* Handle I2CP RequestLeaseSetMessage from the router by granting all leases,
|
||||
* using the specified expiration time for each lease.
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
@ -37,7 +38,15 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
private final Map<Destination, LeaseInfo> _existingLeaseSets;
|
||||
|
||||
public RequestLeaseSetMessageHandler(I2PAppContext context) {
|
||||
super(context, RequestLeaseSetMessage.MESSAGE_TYPE);
|
||||
this(context, RequestLeaseSetMessage.MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* For extension
|
||||
* @since 0.9.7
|
||||
*/
|
||||
protected RequestLeaseSetMessageHandler(I2PAppContext context, int messageType) {
|
||||
super(context, messageType);
|
||||
// not clear why there would ever be more than one
|
||||
_existingLeaseSets = new ConcurrentHashMap(4);
|
||||
}
|
||||
@ -55,6 +64,14 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
//lease.setStartDate(msg.getStartDate());
|
||||
leaseSet.addLease(lease);
|
||||
}
|
||||
signLeaseSet(leaseSet, session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish creating and signing the new LeaseSet
|
||||
* @since 0.9.7
|
||||
*/
|
||||
protected void signLeaseSet(LeaseSet leaseSet, I2PSessionImpl session) {
|
||||
// also, if this session is connected to multiple routers, include other leases here
|
||||
leaseSet.setDestination(session.getMyDestination());
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
package net.i2p.client;
|
||||
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* 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 net.i2p.I2PAppContext;
|
||||
import net.i2p.data.LeaseSet;
|
||||
import net.i2p.data.i2cp.I2CPMessage;
|
||||
import net.i2p.data.i2cp.RequestVariableLeaseSetMessage;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handle I2CP RequestVariableLeaseSetMessage from the router by granting all leases,
|
||||
* retaining the individual expiration time for each lease.
|
||||
*
|
||||
* @since 0.9.7
|
||||
*/
|
||||
class RequestVariableLeaseSetMessageHandler extends RequestLeaseSetMessageHandler {
|
||||
|
||||
public RequestVariableLeaseSetMessageHandler(I2PAppContext context) {
|
||||
super(context, RequestVariableLeaseSetMessage.MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(I2CPMessage message, I2PSessionImpl session) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handle message " + message);
|
||||
RequestVariableLeaseSetMessage msg = (RequestVariableLeaseSetMessage) message;
|
||||
LeaseSet leaseSet = new LeaseSet();
|
||||
for (int i = 0; i < msg.getEndpoints(); i++) {
|
||||
leaseSet.addLease(msg.getEndpoint(i));
|
||||
}
|
||||
signLeaseSet(leaseSet, session);
|
||||
}
|
||||
}
|
@ -93,6 +93,9 @@ public class LeaseSet extends DatabaseEntry {
|
||||
_firstExpiration = Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as getEarliestLeaseDate()
|
||||
*/
|
||||
public long getDate() {
|
||||
return getEarliestLeaseDate();
|
||||
}
|
||||
@ -198,7 +201,7 @@ public class LeaseSet extends DatabaseEntry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the end date of the earliest lease include in this leaseSet.
|
||||
* Retrieve the end date of the earliest lease included in this leaseSet.
|
||||
* This is the date that should be used in comparisons for leaseSet age - to
|
||||
* determine which LeaseSet was published more recently (later earliestLeaseSetDate
|
||||
* means it was published later)
|
||||
@ -211,6 +214,17 @@ public class LeaseSet extends DatabaseEntry {
|
||||
return _firstExpiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the end date of the latest lease included in this leaseSet.
|
||||
* This is the date used in isCurrent().
|
||||
*
|
||||
* @return latest end date of any lease in the set, or 0 if there are no leases
|
||||
* @since 0.9.7
|
||||
*/
|
||||
public long getLatestLeaseDate() {
|
||||
return _lastExpiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the signature matches the lease set's destination's signing public key.
|
||||
* OR the included revocation key.
|
||||
@ -287,8 +301,12 @@ public class LeaseSet extends DatabaseEntry {
|
||||
|
||||
/**
|
||||
* This does NOT validate the signature
|
||||
*
|
||||
* @throws IllegalStateException if called more than once or Destination already set
|
||||
*/
|
||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||
if (_destination != null)
|
||||
throw new IllegalStateException();
|
||||
_destination = new Destination();
|
||||
_destination.readBytes(in);
|
||||
_encryptionKey = PublicKey.create(in);
|
||||
@ -297,7 +315,6 @@ public class LeaseSet extends DatabaseEntry {
|
||||
if (numLeases > MAX_LEASES)
|
||||
throw new DataFormatException("Too many leases - max is " + MAX_LEASES);
|
||||
//_version = DataHelper.readLong(in, 4);
|
||||
_leases.clear();
|
||||
for (int i = 0; i < numLeases; i++) {
|
||||
Lease lease = new Lease();
|
||||
lease.readBytes(in);
|
||||
@ -344,9 +361,10 @@ public class LeaseSet extends DatabaseEntry {
|
||||
if (object == this) return true;
|
||||
if ((object == null) || !(object instanceof LeaseSet)) return false;
|
||||
LeaseSet ls = (LeaseSet) object;
|
||||
return DataHelper.eq(getEncryptionKey(), ls.getEncryptionKey()) &&
|
||||
//DataHelper.eq(getVersion(), ls.getVersion()) &&
|
||||
DataHelper.eq(_leases, ls._leases) && DataHelper.eq(_signature, ls.getSignature())
|
||||
return
|
||||
DataHelper.eq(_signature, ls.getSignature())
|
||||
&& DataHelper.eq(_leases, ls._leases)
|
||||
&& DataHelper.eq(getEncryptionKey(), ls.getEncryptionKey())
|
||||
&& DataHelper.eq(_signingKey, ls.getSigningKey())
|
||||
&& DataHelper.eq(_destination, ls.getDestination());
|
||||
|
||||
@ -371,7 +389,7 @@ public class LeaseSet extends DatabaseEntry {
|
||||
buf.append("\n\tSignature: ").append(_signature);
|
||||
buf.append("\n\tLeases: #").append(getLeaseCount());
|
||||
for (int i = 0; i < getLeaseCount(); i++)
|
||||
buf.append("\n\t\tLease (").append(i).append("): ").append(getLease(i));
|
||||
buf.append("\n\t\t").append(getLease(i));
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
@ -592,9 +592,10 @@ public class RouterInfo extends DatabaseEntry {
|
||||
if (object == this) return true;
|
||||
if ((object == null) || !(object instanceof RouterInfo)) return false;
|
||||
RouterInfo info = (RouterInfo) object;
|
||||
return DataHelper.eq(_identity, info.getIdentity())
|
||||
return
|
||||
_published == info.getPublished()
|
||||
&& DataHelper.eq(_signature, info.getSignature())
|
||||
&& _published == info.getPublished();
|
||||
&& DataHelper.eq(_identity, info.getIdentity());
|
||||
// Let's speed up the NetDB
|
||||
//&& DataHelper.eq(_addresses, info.getAddresses())
|
||||
//&& DataHelper.eq(_options, info.getOptions())
|
||||
|
@ -77,6 +77,8 @@ public class I2CPMessageHandler {
|
||||
return new ReportAbuseMessage();
|
||||
case RequestLeaseSetMessage.MESSAGE_TYPE:
|
||||
return new RequestLeaseSetMessage();
|
||||
case RequestVariableLeaseSetMessage.MESSAGE_TYPE:
|
||||
return new RequestVariableLeaseSetMessage();
|
||||
case SendMessageMessage.MESSAGE_TYPE:
|
||||
return new SendMessageMessage();
|
||||
case SendMessageExpiresMessage.MESSAGE_TYPE:
|
||||
|
@ -50,18 +50,18 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
|
||||
}
|
||||
|
||||
public Hash getRouter(int endpoint) {
|
||||
if ((endpoint < 0) || (_endpoints.size() < endpoint)) return null;
|
||||
if ((endpoint < 0) || (_endpoints.size() <= endpoint)) return null;
|
||||
return _endpoints.get(endpoint).getRouter();
|
||||
}
|
||||
|
||||
public TunnelId getTunnelId(int endpoint) {
|
||||
if ((endpoint < 0) || (_endpoints.size() < endpoint)) return null;
|
||||
if ((endpoint < 0) || (_endpoints.size() <= endpoint)) return null;
|
||||
return _endpoints.get(endpoint).getTunnelId();
|
||||
}
|
||||
|
||||
/** @deprecated unused - presumably he meant remove? */
|
||||
public void remoteEndpoint(int endpoint) {
|
||||
if ((endpoint >= 0) && (endpoint < _endpoints.size())) _endpoints.remove(endpoint);
|
||||
if ((endpoint >= 0) && (endpoint <= _endpoints.size())) _endpoints.remove(endpoint);
|
||||
}
|
||||
|
||||
public void addEndpoint(Hash router, TunnelId tunnel) {
|
||||
|
@ -0,0 +1,128 @@
|
||||
package net.i2p.data.i2cp;
|
||||
|
||||
/*
|
||||
* 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.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Lease;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
/**
|
||||
* Defines the message a router sends to a client to request that
|
||||
* a leaseset be created and signed. The reply is a CreateLeaseSetMessage.
|
||||
*
|
||||
* This message has an expiration time for each lease, unlike RequestLeaseSetMessage,
|
||||
* which has a single expiration time for all leases.
|
||||
*
|
||||
* @since 0.9.7
|
||||
*/
|
||||
public class RequestVariableLeaseSetMessage extends I2CPMessageImpl {
|
||||
public final static int MESSAGE_TYPE = 37;
|
||||
private SessionId _sessionId;
|
||||
private final List<Lease> _endpoints;
|
||||
|
||||
private static final String MIN_VERSION = "0.9.7";
|
||||
|
||||
public RequestVariableLeaseSetMessage() {
|
||||
_endpoints = new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the client support this message?
|
||||
*
|
||||
* @param clientVersion may be null
|
||||
* @return version != null and version >= 0.9.7
|
||||
*/
|
||||
public static boolean isSupported(String clientVersion) {
|
||||
return clientVersion != null &&
|
||||
VersionComparator.comp(clientVersion, MIN_VERSION) >= 0;
|
||||
}
|
||||
|
||||
public SessionId getSessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
||||
public int getEndpoints() {
|
||||
return _endpoints.size();
|
||||
}
|
||||
|
||||
public Lease getEndpoint(int endpoint) {
|
||||
if ((endpoint < 0) || (_endpoints.size() <= endpoint)) return null;
|
||||
return _endpoints.get(endpoint);
|
||||
}
|
||||
|
||||
public void addEndpoint(Lease lease) {
|
||||
if (lease == null)
|
||||
throw new IllegalArgumentException();
|
||||
_endpoints.add(lease);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException {
|
||||
try {
|
||||
if (_sessionId == null)
|
||||
throw new IllegalStateException();
|
||||
_sessionId = new SessionId();
|
||||
_sessionId.readBytes(in);
|
||||
int numTunnels = (int) DataHelper.readLong(in, 1);
|
||||
for (int i = 0; i < numTunnels; i++) {
|
||||
Lease lease = new Lease();
|
||||
lease.readBytes(in);
|
||||
_endpoints.add(lease);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2CPMessageException("Unable to load the message data", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
|
||||
if (_sessionId == null)
|
||||
throw new I2CPMessageException("No data");
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(256);
|
||||
try {
|
||||
_sessionId.writeBytes(os);
|
||||
DataHelper.writeLong(os, 1, _endpoints.size());
|
||||
for (int i = 0; i < _endpoints.size(); i++) {
|
||||
_endpoints.get(i).writeBytes(os);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2CPMessageException("Error writing out the message data", dfe);
|
||||
}
|
||||
return os.toByteArray();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return MESSAGE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("[RequestVariableLeaseSetMessage: ");
|
||||
buf.append("\n\tSessionId: ").append(getSessionId());
|
||||
buf.append("\n\tTunnels:");
|
||||
for (int i = 0; i < getEndpoints(); i++) {
|
||||
buf.append('\n').append(_endpoints.get(i));
|
||||
}
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user