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:
@ -17,7 +17,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@ -27,6 +26,7 @@ import java.util.TreeSet;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.Lease;
|
||||
import net.i2p.data.LeaseSet;
|
||||
import net.i2p.data.RouterAddress;
|
||||
import net.i2p.data.RouterInfo;
|
||||
@ -79,9 +79,8 @@ public class NetDbRenderer {
|
||||
renderRouterInfo(buf, _context.router().getRouterInfo(), true, true);
|
||||
} else {
|
||||
boolean notFound = true;
|
||||
Set routers = _context.netDb().getRouters();
|
||||
for (Iterator iter = routers.iterator(); iter.hasNext(); ) {
|
||||
RouterInfo ri = (RouterInfo)iter.next();
|
||||
Set<RouterInfo> routers = _context.netDb().getRouters();
|
||||
for (RouterInfo ri : routers) {
|
||||
Hash key = ri.getIdentity().getHash();
|
||||
if (key.toBase64().startsWith(routerPrefix)) {
|
||||
renderRouterInfo(buf, ri, false, true);
|
||||
@ -152,11 +151,12 @@ public class NetDbRenderer {
|
||||
buf.append(dest.toBase64().substring(0, 6));
|
||||
}
|
||||
buf.append(")</b><br>\n");
|
||||
long exp = ls.getEarliestLeaseDate()-now;
|
||||
long exp = ls.getLatestLeaseDate()-now;
|
||||
if (exp > 0)
|
||||
buf.append(_("Expires in {0}", DataHelper.formatDuration2(exp))).append("<br>\n");
|
||||
buf.append(_("Expires in {0}", DataHelper.formatDuration2(exp)));
|
||||
else
|
||||
buf.append(_("Expired {0} ago", DataHelper.formatDuration2(0-exp))).append("<br>\n");
|
||||
buf.append(_("Expired {0} ago", DataHelper.formatDuration2(0-exp)));
|
||||
buf.append("<br>\n");
|
||||
if (debug) {
|
||||
buf.append("RAP? " + ls.getReceivedAsPublished());
|
||||
buf.append(" RAR? " + ls.getReceivedAsReply());
|
||||
@ -171,9 +171,18 @@ public class NetDbRenderer {
|
||||
buf.append("Encryption Key: ").append(ls.getEncryptionKey().toBase64().substring(0, 20)).append("...<br>");
|
||||
}
|
||||
for (int i = 0; i < ls.getLeaseCount(); i++) {
|
||||
buf.append(_("Lease")).append(' ').append(i + 1).append(": " + _("Gateway") + ' ');
|
||||
buf.append(_context.commSystem().renderPeerHTML(ls.getLease(i).getGateway()));
|
||||
buf.append(' ' + _("Tunnel") + ' ').append(ls.getLease(i).getTunnelId().getTunnelId()).append("<br>\n");
|
||||
Lease lease = ls.getLease(i);
|
||||
buf.append(_("Lease")).append(' ').append(i + 1).append(": ").append(_("Gateway")).append(' ');
|
||||
buf.append(_context.commSystem().renderPeerHTML(lease.getGateway()));
|
||||
buf.append(' ').append(_("Tunnel")).append(' ').append(lease.getTunnelId().getTunnelId()).append(' ');
|
||||
if (debug) {
|
||||
long exl = lease.getEndDate().getTime() - now;
|
||||
if (exl > 0)
|
||||
buf.append(_("Expires in {0}", DataHelper.formatDuration2(exl)));
|
||||
else
|
||||
buf.append(_("Expired {0} ago", DataHelper.formatDuration2(0-exl)));
|
||||
}
|
||||
buf.append("<br>\n");
|
||||
}
|
||||
buf.append("<hr>\n");
|
||||
out.write(buf.toString());
|
||||
@ -253,8 +262,7 @@ public class NetDbRenderer {
|
||||
|
||||
Set<RouterInfo> routers = new TreeSet(new RouterInfoComparator());
|
||||
routers.addAll(_context.netDb().getRouters());
|
||||
for (Iterator iter = routers.iterator(); iter.hasNext(); ) {
|
||||
RouterInfo ri = (RouterInfo)iter.next();
|
||||
for (RouterInfo ri : routers) {
|
||||
Hash key = ri.getIdentity().getHash();
|
||||
boolean isUs = key.equals(us);
|
||||
if (!isUs) {
|
||||
@ -391,8 +399,7 @@ public class NetDbRenderer {
|
||||
buf.append(" title=\"").append(_(_context.commSystem().getCountryName(country))).append('\"');
|
||||
buf.append(" src=\"/flags.jsp?c=").append(country).append("\"> ");
|
||||
}
|
||||
for (Iterator iter = info.getAddresses().iterator(); iter.hasNext(); ) {
|
||||
RouterAddress addr = (RouterAddress)iter.next();
|
||||
for (RouterAddress addr : info.getAddresses()) {
|
||||
String style = addr.getTransportStyle();
|
||||
buf.append("<b>").append(DataHelper.stripHTML(style)).append(":</b> ");
|
||||
int cost = addr.getCost();
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
17
history.txt
17
history.txt
@ -1,3 +1,20 @@
|
||||
2013-06-09 zzz
|
||||
* 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
|
||||
|
||||
2013-06-07 zzz
|
||||
* BlockfileNamingService:
|
||||
- Fix bug that kept reverse index from being updated
|
||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 6;
|
||||
public final static long BUILD = 7;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
@ -10,9 +10,12 @@ package net.i2p.router.client;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import net.i2p.data.Lease;
|
||||
import net.i2p.data.LeaseSet;
|
||||
import net.i2p.data.i2cp.I2CPMessage;
|
||||
import net.i2p.data.i2cp.I2CPMessageException;
|
||||
import net.i2p.data.i2cp.RequestLeaseSetMessage;
|
||||
import net.i2p.data.i2cp.RequestVariableLeaseSetMessage;
|
||||
import net.i2p.router.Job;
|
||||
import net.i2p.router.JobImpl;
|
||||
import net.i2p.router.RouterContext;
|
||||
@ -31,6 +34,12 @@ class RequestLeaseSetJob extends JobImpl {
|
||||
private final ClientConnectionRunner _runner;
|
||||
private final LeaseRequestState _requestState;
|
||||
|
||||
private static final long MAX_FUDGE = 2*1000;
|
||||
|
||||
/** temp for testing */
|
||||
private static final String PROP_VARIABLE = "router.variableLeaseExpiration";
|
||||
private static final boolean DFLT_VARIABLE = false;
|
||||
|
||||
public RequestLeaseSetJob(RouterContext ctx, ClientConnectionRunner runner, LeaseRequestState state) {
|
||||
super(ctx);
|
||||
_log = ctx.logManager().getLog(RequestLeaseSetJob.class);
|
||||
@ -44,22 +53,51 @@ class RequestLeaseSetJob extends JobImpl {
|
||||
public void runJob() {
|
||||
if (_runner.isDead()) return;
|
||||
|
||||
RequestLeaseSetMessage msg = new RequestLeaseSetMessage();
|
||||
long endTime = _requestState.getRequested().getEarliestLeaseDate();
|
||||
// Add a small number of ms (0-300) that increases as we approach the expire time.
|
||||
LeaseSet requested = _requestState.getRequested();
|
||||
long endTime = requested.getEarliestLeaseDate();
|
||||
// Add a small number of ms (0 to MAX_FUDGE) that increases as we approach the expire time.
|
||||
// Since the earliest date functions as a version number,
|
||||
// this will force the floodfill to flood each new version;
|
||||
// otherwise it won't if the earliest time hasn't changed.
|
||||
long fudge = 300 - ((endTime - getContext().clock().now()) / 2000);
|
||||
long fudge = MAX_FUDGE - ((endTime - getContext().clock().now()) / (10*60*1000 / MAX_FUDGE));
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Adding fudge " + fudge);
|
||||
endTime += fudge;
|
||||
Date end = new Date(endTime);
|
||||
|
||||
msg.setEndDate(end);
|
||||
msg.setSessionId(_runner.getSessionId());
|
||||
|
||||
for (int i = 0; i < _requestState.getRequested().getLeaseCount(); i++) {
|
||||
msg.addEndpoint(_requestState.getRequested().getLease(i).getGateway(),
|
||||
_requestState.getRequested().getLease(i).getTunnelId());
|
||||
I2CPMessage msg;
|
||||
if (getContext().getProperty(PROP_VARIABLE, DFLT_VARIABLE) &&
|
||||
(_runner instanceof QueuedClientConnectionRunner ||
|
||||
RequestVariableLeaseSetMessage.isSupported(_runner.getClientVersion()))) {
|
||||
// new style - leases will have individual expirations
|
||||
RequestVariableLeaseSetMessage rmsg = new RequestVariableLeaseSetMessage();
|
||||
rmsg.setSessionId(_runner.getSessionId());
|
||||
for (int i = 0; i < requested.getLeaseCount(); i++) {
|
||||
Lease lease = requested.getLease(i);
|
||||
if (lease.getEndDate().getTime() < endTime) {
|
||||
// don't modify old object, we don't know where it came from
|
||||
Lease nl = new Lease();
|
||||
nl.setGateway(lease.getGateway());
|
||||
nl.setTunnelId(lease.getTunnelId());
|
||||
nl.setEndDate(new Date(endTime));
|
||||
lease = nl;
|
||||
//if (_log.shouldLog(Log.INFO))
|
||||
// _log.info("Adjusted end date to " + endTime + " for " + lease);
|
||||
}
|
||||
rmsg.addEndpoint(lease);
|
||||
}
|
||||
msg = rmsg;
|
||||
} else {
|
||||
// old style - all leases will have same expiration
|
||||
RequestLeaseSetMessage rmsg = new RequestLeaseSetMessage();
|
||||
Date end = new Date(endTime);
|
||||
rmsg.setEndDate(end);
|
||||
rmsg.setSessionId(_runner.getSessionId());
|
||||
for (int i = 0; i < requested.getLeaseCount(); i++) {
|
||||
Lease lease = requested.getLease(i);
|
||||
rmsg.addEndpoint(lease.getGateway(),
|
||||
lease.getTunnelId());
|
||||
}
|
||||
msg = rmsg;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -304,7 +304,11 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
// it (due to failure for example) we won't continue to use it.
|
||||
for (int i = 0; i < _leaseSet.getLeaseCount(); i++) {
|
||||
Lease lease = _leaseSet.getLease(i);
|
||||
if (_lease.equals(lease)) {
|
||||
// Don't use Lease.equals(), as that compares expiration time too,
|
||||
// and that time may change in subsequent publication
|
||||
//if (_lease.equals(lease)) {
|
||||
if (_lease.getTunnelId().equals(lease.getTunnelId()) &&
|
||||
_lease.getGateway().equals(lease.getGateway())) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getJobId() + ": Found in cache - lease for " + _toString);
|
||||
return true;
|
||||
|
@ -96,10 +96,6 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
/** don't probe or broadcast data, just respond and search when explicitly needed */
|
||||
private static final boolean QUIET = false;
|
||||
|
||||
public static final String PROP_ENFORCE_NETID = "router.networkDatabase.enforceNetId";
|
||||
private static final boolean DEFAULT_ENFORCE_NETID = false;
|
||||
private boolean _enforceNetId = DEFAULT_ENFORCE_NETID;
|
||||
|
||||
public final static String PROP_DB_DIR = "router.networkDatabase.dbDir";
|
||||
public final static String DEFAULT_DB_DIR = "netDb";
|
||||
|
||||
@ -143,7 +139,6 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
_peerSelector = createPeerSelector();
|
||||
_publishingLeaseSets = new HashMap(8);
|
||||
_activeRequests = new HashMap(8);
|
||||
_enforceNetId = DEFAULT_ENFORCE_NETID;
|
||||
_reseedChecker = new ReseedChecker(context);
|
||||
context.statManager().createRateStat("netDb.lookupDeferred", "how many lookups are deferred?", "NetworkDatabase", new long[] { 60*60*1000 });
|
||||
context.statManager().createRateStat("netDb.exploreKeySet", "how many keys are queued for exploration?", "NetworkDatabase", new long[] { 60*60*1000 });
|
||||
@ -223,11 +218,6 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
_log.info("No DB dir specified [" + PROP_DB_DIR + "], using [" + DEFAULT_DB_DIR + "]");
|
||||
_dbDir = DEFAULT_DB_DIR;
|
||||
}
|
||||
String enforce = _context.getProperty(PROP_ENFORCE_NETID);
|
||||
if (enforce != null)
|
||||
_enforceNetId = Boolean.parseBoolean(enforce);
|
||||
else
|
||||
_enforceNetId = DEFAULT_ENFORCE_NETID;
|
||||
_ds.restart();
|
||||
_exploreKeys.clear();
|
||||
|
||||
@ -249,12 +239,6 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
_log.info("Starting up the kademlia network database");
|
||||
RouterInfo ri = _context.router().getRouterInfo();
|
||||
String dbDir = _context.getProperty(PROP_DB_DIR, DEFAULT_DB_DIR);
|
||||
String enforce = _context.getProperty(PROP_ENFORCE_NETID);
|
||||
if (enforce != null)
|
||||
_enforceNetId = Boolean.parseBoolean(enforce);
|
||||
else
|
||||
_enforceNetId = DEFAULT_ENFORCE_NETID;
|
||||
|
||||
_kb = new KBucketSet(_context, ri.getIdentity().getHash());
|
||||
try {
|
||||
_ds = new PersistentDataStore(_context, dbDir, this);
|
||||
@ -443,7 +427,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
fail(key);
|
||||
} else if (rv.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
|
||||
try {
|
||||
if (validate(key, (RouterInfo)rv) == null)
|
||||
if (validate((RouterInfo)rv) == null)
|
||||
return rv;
|
||||
} catch (IllegalArgumentException iae) {}
|
||||
fail(key);
|
||||
@ -512,7 +496,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
// startup allows some lax rules).
|
||||
boolean valid = true;
|
||||
try {
|
||||
valid = (null == validate(key, (RouterInfo)ds));
|
||||
valid = (null == validate((RouterInfo)ds));
|
||||
} catch (IllegalArgumentException iae) {
|
||||
valid = false;
|
||||
}
|
||||
@ -531,6 +515,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
}
|
||||
|
||||
private static final long PUBLISH_DELAY = 3*1000;
|
||||
|
||||
public void publish(LeaseSet localLeaseSet) {
|
||||
if (!_initialized) return;
|
||||
Hash h = localLeaseSet.getDestination().calculateHash();
|
||||
@ -564,6 +549,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
// remove first since queue is a TreeSet now...
|
||||
_context.jobQueue().removeJob(j);
|
||||
j.getTiming().setStartAfter(nextTime);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Queueing to publish at " + (new Date(nextTime)) + ' ' + localLeaseSet);
|
||||
_context.jobQueue().addJob(j);
|
||||
}
|
||||
|
||||
@ -627,34 +614,46 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
* Determine whether this leaseSet will be accepted as valid and current
|
||||
* given what we know now.
|
||||
*
|
||||
* TODO this is called several times, only check the key and signature once
|
||||
* Unlike for RouterInfos, this is only called once, when stored.
|
||||
* After that, LeaseSet.isCurrent() is used.
|
||||
*
|
||||
* @return reason why the entry is not valid, or null if it is valid
|
||||
*/
|
||||
String validate(Hash key, LeaseSet leaseSet) {
|
||||
private String validate(Hash key, LeaseSet leaseSet) {
|
||||
if (!key.equals(leaseSet.getDestination().calculateHash())) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Invalid store attempt! key does not match leaseSet.destination! key = "
|
||||
+ key + ", leaseSet = " + leaseSet);
|
||||
return "Key does not match leaseSet.destination - " + key.toBase64();
|
||||
} else if (!leaseSet.verifySignature()) {
|
||||
}
|
||||
if (!leaseSet.verifySignature()) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Invalid leaseSet signature! leaseSet = " + leaseSet);
|
||||
return "Invalid leaseSet signature on " + leaseSet.getDestination().calculateHash().toBase64();
|
||||
} else if (leaseSet.getEarliestLeaseDate() <= _context.clock().now() - 2*Router.CLOCK_FUDGE_FACTOR) {
|
||||
long age = _context.clock().now() - leaseSet.getEarliestLeaseDate();
|
||||
}
|
||||
long earliest = leaseSet.getEarliestLeaseDate();
|
||||
long latest = leaseSet.getLatestLeaseDate();
|
||||
long now = _context.clock().now();
|
||||
if (earliest <= now - 2*Router.CLOCK_FUDGE_FACTOR ||
|
||||
// same as the isCurrent(Router.CLOCK_FUDGE_FACTOR) test in
|
||||
// lookupLeaseSetLocally()
|
||||
latest <= now - Router.CLOCK_FUDGE_FACTOR) {
|
||||
long age = now - earliest;
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Old leaseSet! not storing it: "
|
||||
+ leaseSet.getDestination().calculateHash().toBase64()
|
||||
+ " expires on " + new Date(leaseSet.getEarliestLeaseDate()), new Exception("Rejecting store"));
|
||||
+ leaseSet.getDestination().calculateHash()
|
||||
+ " first exp. " + new Date(earliest)
|
||||
+ " last exp. " + new Date(latest),
|
||||
new Exception("Rejecting store"));
|
||||
return "Expired leaseSet for " + leaseSet.getDestination().calculateHash().toBase64()
|
||||
+ " expired " + DataHelper.formatDuration(age) + " ago";
|
||||
} else if (leaseSet.getEarliestLeaseDate() > _context.clock().now() + (Router.CLOCK_FUDGE_FACTOR + MAX_LEASE_FUTURE)) {
|
||||
long age = leaseSet.getEarliestLeaseDate() - _context.clock().now();
|
||||
}
|
||||
if (latest > now + (Router.CLOCK_FUDGE_FACTOR + MAX_LEASE_FUTURE)) {
|
||||
long age = latest - now;
|
||||
// let's not make this an error, it happens when peers have bad clocks
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("LeaseSet expires too far in the future: "
|
||||
+ leaseSet.getDestination().calculateHash().toBase64()
|
||||
+ leaseSet.getDestination().calculateHash()
|
||||
+ " expires " + DataHelper.formatDuration(age) + " from now");
|
||||
return "Future expiring leaseSet for " + leaseSet.getDestination().calculateHash()
|
||||
+ " expiring in " + DataHelper.formatDuration(age);
|
||||
@ -720,11 +719,40 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
* Determine whether this routerInfo will be accepted as valid and current
|
||||
* given what we know now.
|
||||
*
|
||||
* TODO this is called several times, only check the key and signature once
|
||||
* Call this only on first store, to check the key and signature once
|
||||
*
|
||||
* @return reason why the entry is not valid, or null if it is valid
|
||||
*/
|
||||
String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException {
|
||||
private String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException {
|
||||
if (!key.equals(routerInfo.getIdentity().getHash())) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Invalid store attempt! key does not match routerInfo.identity! key = " + key + ", router = " + routerInfo);
|
||||
return "Key does not match routerInfo.identity";
|
||||
}
|
||||
if (!routerInfo.isValid()) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Invalid routerInfo signature! forged router structure! router = " + routerInfo);
|
||||
return "Invalid routerInfo signature";
|
||||
}
|
||||
if (routerInfo.getNetworkId() != Router.NETWORK_ID){
|
||||
_context.banlist().banlistRouter(key, "Not in our network");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Bad network: " + routerInfo);
|
||||
return "Not in our network";
|
||||
}
|
||||
return validate(routerInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this routerInfo will be accepted as valid and current
|
||||
* given what we know now.
|
||||
*
|
||||
* Call this before each use, to check expiration
|
||||
*
|
||||
* @return reason why the entry is not valid, or null if it is valid
|
||||
* @since 0.9.7
|
||||
*/
|
||||
private String validate(RouterInfo routerInfo) throws IllegalArgumentException {
|
||||
long now = _context.clock().now();
|
||||
boolean upLongEnough = _context.router().getUptime() > 60*60*1000;
|
||||
// Once we're over MIN_ROUTERS routers, reduce the expiration time down from the default,
|
||||
@ -743,59 +771,44 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
ROUTER_INFO_EXPIRATION_MIN +
|
||||
((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * MIN_ROUTERS / (_kb.size() + 1)));
|
||||
|
||||
if (!key.equals(routerInfo.getIdentity().getHash())) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Invalid store attempt! key does not match routerInfo.identity! key = " + key + ", router = " + routerInfo);
|
||||
return "Key does not match routerInfo.identity - " + key.toBase64();
|
||||
} else if (!routerInfo.isValid()) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Invalid routerInfo signature! forged router structure! router = " + routerInfo);
|
||||
return "Invalid routerInfo signature on " + key.toBase64();
|
||||
} else if (upLongEnough && !routerInfo.isCurrent(adjustedExpiration)) {
|
||||
if (routerInfo.getNetworkId() != Router.NETWORK_ID) {
|
||||
_context.banlist().banlistRouter(key, "Peer is not in our network");
|
||||
return "Peer is not in our network (" + routerInfo.getNetworkId() + ", wants "
|
||||
+ Router.NETWORK_ID + "): " + routerInfo.calculateHash().toBase64();
|
||||
}
|
||||
if (upLongEnough && !routerInfo.isCurrent(adjustedExpiration)) {
|
||||
long age = _context.clock().now() - routerInfo.getPublished();
|
||||
int existing = _kb.size();
|
||||
if (existing >= MIN_REMAINING_ROUTERS) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Not storing expired router for " + key.toBase64(), new Exception("Rejecting store"));
|
||||
return "Peer " + key.toBase64() + " expired " + DataHelper.formatDuration(age) + " ago";
|
||||
_log.info("Not storing expired RI " + routerInfo.getIdentity().getHash(), new Exception("Rejecting store"));
|
||||
return "Peer expired " + DataHelper.formatDuration(age) + " ago";
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Even though the peer is old, we have only " + existing
|
||||
+ " peers left (curPeer: " + key.toBase64() + " published on "
|
||||
+ new Date(routerInfo.getPublished()));
|
||||
+ " peers left " + routerInfo);
|
||||
}
|
||||
} else if (routerInfo.getPublished() > now + 2*Router.CLOCK_FUDGE_FACTOR) {
|
||||
}
|
||||
if (routerInfo.getPublished() > now + 2*Router.CLOCK_FUDGE_FACTOR) {
|
||||
long age = routerInfo.getPublished() - _context.clock().now();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Peer " + key.toBase64() + " published their routerInfo in the future?! ["
|
||||
_log.info("Peer " + routerInfo.getIdentity().getHash() + " published their routerInfo in the future?! ["
|
||||
+ new Date(routerInfo.getPublished()) + "]", new Exception("Rejecting store"));
|
||||
return "Peer " + key.toBase64() + " published " + DataHelper.formatDuration(age) + " in the future?!";
|
||||
} else if (_enforceNetId && (routerInfo.getNetworkId() != Router.NETWORK_ID) ){
|
||||
String rv = "Peer " + key.toBase64() + " is from another network, not accepting it (id="
|
||||
+ routerInfo.getNetworkId() + ", want " + Router.NETWORK_ID + ")";
|
||||
return rv;
|
||||
} else if (upLongEnough && (routerInfo.getPublished() < now - 2*24*60*60*1000l) ) {
|
||||
return "Peer published " + DataHelper.formatDuration(age) + " in the future?!";
|
||||
}
|
||||
if (upLongEnough && (routerInfo.getPublished() < now - 2*24*60*60*1000l) ) {
|
||||
long age = _context.clock().now() - routerInfo.getPublished();
|
||||
return "Peer " + key.toBase64() + " published " + DataHelper.formatDuration(age) + " ago";
|
||||
} else if (upLongEnough && !routerInfo.isCurrent(ROUTER_INFO_EXPIRATION_SHORT)) {
|
||||
return "Peer published " + DataHelper.formatDuration(age) + " ago";
|
||||
}
|
||||
if (upLongEnough && !routerInfo.isCurrent(ROUTER_INFO_EXPIRATION_SHORT)) {
|
||||
if (routerInfo.getAddresses().isEmpty())
|
||||
return "Peer " + key.toBase64() + " published > 75m ago with no addresses";
|
||||
return "Peer published > 75m ago with no addresses";
|
||||
// This should cover the introducers case below too
|
||||
// And even better, catches the case where the router is unreachable but knows no introducers
|
||||
if (routerInfo.getCapabilities().indexOf(Router.CAPABILITY_UNREACHABLE) >= 0)
|
||||
return "Peer " + key.toBase64() + " published > 75m ago and thinks it is unreachable";
|
||||
return "Peer published > 75m ago and thinks it is unreachable";
|
||||
RouterAddress ra = routerInfo.getTargetAddress("SSU");
|
||||
if (ra != null) {
|
||||
// Introducers change often, introducee will ping introducer for 2 hours
|
||||
if (ra.getOption("ihost0") != null)
|
||||
return "Peer " + key.toBase64() + " published > 75m ago with SSU Introducers";
|
||||
return "Peer published > 75m ago with SSU Introducers";
|
||||
if (routerInfo.getTargetAddress("NTCP") == null)
|
||||
return "Peer " + key.toBase64() + " published > 75m ago, SSU only without introducers";
|
||||
return "Peer published > 75m ago, SSU only without introducers";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -47,12 +47,12 @@ public class RepublishLeaseSetJob extends JobImpl {
|
||||
if (getContext().clientManager().isLocal(_dest)) {
|
||||
LeaseSet ls = _facade.lookupLeaseSetLocally(_dest);
|
||||
if (ls != null) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Client " + _dest + " is local, so we're republishing it");
|
||||
if (!ls.isCurrent(Router.CLOCK_FUDGE_FACTOR)) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Not publishing a LOCAL lease that isn't current - " + _dest, new Exception("Publish expired LOCAL lease?"));
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Publishing " + ls);
|
||||
getContext().statManager().addRateData("netDb.republishLeaseSetCount", 1, 0);
|
||||
_facade.sendStore(_dest, ls, new OnRepublishSuccess(getContext()), new OnRepublishFailure(getContext(), this), REPUBLISH_LEASESET_TIMEOUT, null);
|
||||
_lastPublished = getContext().clock().now();
|
||||
|
@ -81,9 +81,11 @@ class TransientDataStore implements DataStore {
|
||||
return Collections.unmodifiableSet(_data.entrySet());
|
||||
}
|
||||
|
||||
/** for PersistentDataStore only - don't use here @throws IAE always */
|
||||
/** for PersistentDataStore only - don't use here
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public DatabaseEntry get(Hash key, boolean persist) {
|
||||
throw new IllegalArgumentException("no");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public DatabaseEntry get(Hash key) {
|
||||
@ -103,9 +105,11 @@ class TransientDataStore implements DataStore {
|
||||
return count;
|
||||
}
|
||||
|
||||
/** for PersistentDataStore only - don't use here @throws IAE always */
|
||||
/** for PersistentDataStore only - don't use here
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public boolean put(Hash key, DatabaseEntry data, boolean persist) {
|
||||
throw new IllegalArgumentException("no");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,8 +120,7 @@ class TransientDataStore implements DataStore {
|
||||
if (data == null) return false;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Storing key " + key);
|
||||
DatabaseEntry old = null;
|
||||
old = _data.putIfAbsent(key, data);
|
||||
DatabaseEntry old = _data.putIfAbsent(key, data);
|
||||
boolean rv = false;
|
||||
if (data.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
|
||||
// Don't do this here so we don't reset it at router startup;
|
||||
@ -128,13 +131,15 @@ class TransientDataStore implements DataStore {
|
||||
RouterInfo ori = (RouterInfo)old;
|
||||
if (ri.getPublished() < ori.getPublished()) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Almost clobbered an old router! " + key + ": [old published on " + new Date(ori.getPublished()) + " new on " + new Date(ri.getPublished()) + "]");
|
||||
_log.info("Almost clobbered an old router! " + key + ": [old published on " + new Date(ori.getPublished()) +
|
||||
" new on " + new Date(ri.getPublished()) + ']');
|
||||
} else if (ri.getPublished() == ori.getPublished()) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Duplicate " + key);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Updated the old router for " + key + ": [old published on " + new Date(ori.getPublished()) + " new on " + new Date(ri.getPublished()) + "]");
|
||||
_log.info("Updated the old router for " + key + ": [old published on " + new Date(ori.getPublished()) +
|
||||
" new on " + new Date(ri.getPublished()) + ']');
|
||||
_data.put(key, data);
|
||||
rv = true;
|
||||
}
|
||||
@ -149,13 +154,15 @@ class TransientDataStore implements DataStore {
|
||||
LeaseSet ols = (LeaseSet)old;
|
||||
if (ls.getEarliestLeaseDate() < ols.getEarliestLeaseDate()) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Almost clobbered an old leaseSet! " + key + ": [old published on " + new Date(ols.getEarliestLeaseDate()) + " new on " + new Date(ls.getEarliestLeaseDate()) + "]");
|
||||
_log.info("Almost clobbered an old leaseSet! " + key + ": [old expires " + new Date(ols.getEarliestLeaseDate()) +
|
||||
" new on " + new Date(ls.getEarliestLeaseDate()) + ']');
|
||||
} else if (ls.getEarliestLeaseDate() == ols.getEarliestLeaseDate()) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Duplicate " + key);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Updated old leaseSet " + key + ": [old published on " + new Date(ols.getEarliestLeaseDate()) + " new on " + new Date(ls.getEarliestLeaseDate()) + "]");
|
||||
_log.info("Updated old leaseSet " + key + ": [old expires " + new Date(ols.getEarliestLeaseDate()) +
|
||||
" new on " + new Date(ls.getEarliestLeaseDate()) + ']');
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply());
|
||||
}
|
||||
@ -164,7 +171,7 @@ class TransientDataStore implements DataStore {
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("New leaseset for " + key + ": published on " + new Date(ls.getEarliestLeaseDate()));
|
||||
_log.info("New leaseset for " + key + ": expires " + new Date(ls.getEarliestLeaseDate()));
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply());
|
||||
}
|
||||
@ -187,9 +194,11 @@ class TransientDataStore implements DataStore {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/** for PersistentDataStore only - don't use here */
|
||||
/** for PersistentDataStore only - don't use here
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public DatabaseEntry remove(Hash key, boolean persist) {
|
||||
throw new IllegalArgumentException("no");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public DatabaseEntry remove(Hash key) {
|
||||
|
@ -16,6 +16,9 @@ class ExpireJob extends JobImpl {
|
||||
private boolean _leaseUpdated;
|
||||
private final long _dropAfter;
|
||||
|
||||
private static final long OB_EARLY_EXPIRE = 30*1000;
|
||||
private static final long IB_EARLY_EXPIRE = OB_EARLY_EXPIRE + 7500;
|
||||
|
||||
public ExpireJob(RouterContext ctx, TunnelCreatorConfig cfg, TunnelPool pool) {
|
||||
super(ctx);
|
||||
_pool = pool;
|
||||
@ -27,9 +30,11 @@ class ExpireJob extends JobImpl {
|
||||
// Also skew the inbound away from the outbound
|
||||
long expire = cfg.getExpiration();
|
||||
_dropAfter = expire + Router.CLOCK_FUDGE_FACTOR;
|
||||
expire -= ctx.random().nextLong(60*1000);
|
||||
if (_pool.getSettings().isInbound())
|
||||
expire -= ctx.random().nextLong(15*1000);
|
||||
expire -= IB_EARLY_EXPIRE + ctx.random().nextLong(IB_EARLY_EXPIRE);
|
||||
else
|
||||
expire -= OB_EARLY_EXPIRE + ctx.random().nextLong(OB_EARLY_EXPIRE);
|
||||
// See comments in TunnelPool.locked_buildNewLeaseSet
|
||||
cfg.setExpiration(expire);
|
||||
getTiming().setStartAfter(expire);
|
||||
}
|
||||
@ -42,6 +47,7 @@ class ExpireJob extends JobImpl {
|
||||
if (!_leaseUpdated) {
|
||||
_pool.removeTunnel(_cfg);
|
||||
_leaseUpdated = true;
|
||||
// noop for outbound
|
||||
_pool.refreshLeaseSet();
|
||||
long timeToDrop = _dropAfter - getContext().clock().now();
|
||||
requeue(timeToDrop);
|
||||
|
@ -18,6 +18,7 @@ import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.TunnelInfo;
|
||||
import net.i2p.router.TunnelPoolSettings;
|
||||
import net.i2p.router.tunnel.HopConfig;
|
||||
import net.i2p.router.tunnel.TunnelCreatorConfig;
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateAverages;
|
||||
import net.i2p.stat.RateStat;
|
||||
@ -725,7 +726,13 @@ public class TunnelPool {
|
||||
continue;
|
||||
}
|
||||
Lease lease = new Lease();
|
||||
lease.setEndDate(new Date(tunnel.getExpiration()));
|
||||
// bugfix
|
||||
// ExpireJob reduces the expiration, which causes a 2nd leaseset with the same lease
|
||||
// to have an earlier expiration, so it isn't stored.
|
||||
// Get the "real" expiration from the gateway hop config,
|
||||
// HopConfig expirations are the same as the "real" expiration and don't change
|
||||
// see configureNewTunnel()
|
||||
lease.setEndDate(new Date(((TunnelCreatorConfig)tunnel).getConfig(0).getExpiration()));
|
||||
lease.setTunnelId(inId);
|
||||
lease.setGateway(gw);
|
||||
leases.add(lease);
|
||||
@ -1131,6 +1138,7 @@ public class TunnelPool {
|
||||
// tunnelIds will be updated during building, and as the creator, we
|
||||
// don't need to worry about prev/next hop
|
||||
}
|
||||
// note that this will be adjusted by expire job
|
||||
cfg.setExpiration(expiration);
|
||||
if (!settings.isInbound())
|
||||
cfg.setPriority(settings.getPriority());
|
||||
|
Reference in New Issue
Block a user