diff --git a/LICENSE.txt b/LICENSE.txt index e93798548..250261d98 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -121,7 +121,6 @@ Applications: Copyright 2000-2004 Mort Bay Consulting Pty. Ltd. See licenses/LICENSE-Apache1.1.txt See licenses/LICENSE-Apache2.0.txt - See licenses/NOTICE-Ant.txt See licenses/NOTICE-Commons-Logging.txt JRobin 1.4.0: diff --git a/apps/i2ptunnel/java/build.xml b/apps/i2ptunnel/java/build.xml index 5ab73d5e2..a74e328cc 100644 --- a/apps/i2ptunnel/java/build.xml +++ b/apps/i2ptunnel/java/build.xml @@ -55,7 +55,7 @@ - + diff --git a/apps/routerconsole/java/build.xml b/apps/routerconsole/java/build.xml index 23e1ac05b..c0a132a41 100644 --- a/apps/routerconsole/java/build.xml +++ b/apps/routerconsole/java/build.xml @@ -86,7 +86,7 @@ - + diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java index 8b8b2fb16..2e53be6b5 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java @@ -63,6 +63,11 @@ public class ConfigTunnelsHelper extends HelperBase { out.getLength() <= 0 || out.getLength() + out.getLengthVariance() <= 0) buf.append("ANONYMITY WARNING - Settings include 0-hop tunnels"); + else if (in.getLength() <= 1 || + in.getLength() + in.getLengthVariance() <= 1 || + out.getLength() <= 1 || + out.getLength() + out.getLengthVariance() <= 1) + buf.append("ANONYMITY WARNING - Settings include 1-hop tunnels"); if (in.getLength() + Math.abs(in.getLengthVariance()) >= WARN_LENGTH || out.getLength() + Math.abs(out.getLengthVariance()) >= WARN_LENGTH) buf.append("PERFORMANCE WARNING - Settings include very long tunnels"); diff --git a/apps/routerconsole/jsp/logs.jsp b/apps/routerconsole/jsp/logs.jsp index 374a2ed8b..845ad3e8d 100644 --- a/apps/routerconsole/jsp/logs.jsp +++ b/apps/routerconsole/jsp/logs.jsp @@ -26,7 +26,7 @@ jbigi <%=net.i2p.util.NativeBigInteger.loadStatus()%> Critical logs: - Router logs: + Router logs (configure): Service (Wrapper) logs: diff --git a/apps/susidns/src/build.xml b/apps/susidns/src/build.xml index 6f82b26b1..35fbeb28c 100644 --- a/apps/susidns/src/build.xml +++ b/apps/susidns/src/build.xml @@ -35,7 +35,7 @@ - + diff --git a/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java b/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java index 214e7e292..de4cff527 100644 --- a/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java +++ b/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java @@ -37,11 +37,13 @@ import java.util.Properties; public class AddressbookBean { private String book, action, serial, lastSerial, filter, search, hostname, destination; + private int beginIndex, endIndex; private Properties properties, addressbook; private int trClass; private LinkedList deletionMarks; private static Comparator sorter; - + private static final int DISPLAY_SIZE=100; + static { sorter = new AddressByNameSorter(); } @@ -74,6 +76,8 @@ public class AddressbookBean { properties = new Properties(); deletionMarks = new LinkedList(); + beginIndex = 0; + endIndex = DISPLAY_SIZE - 1; } private long configLastLoaded = 0; private static final String PRIVATE_BOOK = "private_addressbook"; @@ -106,6 +110,8 @@ public class AddressbookBean { loadConfig(); String filename = properties.getProperty( getBook() + "_addressbook" ); + if (filename.startsWith("../")) + return filename.substring(3); return ConfigBean.addressbookPrefix + filename; } private Object[] entries; @@ -174,17 +180,45 @@ public class AddressbookBean } list.addLast( new AddressBean( name, destination ) ); } - // Format a message about filtered addressbook size, and the number of displayed entries - if( filter != null && filter.length() > 0 ) - message = "Filtered l"; - else - message = "L"; - message += "ist contains " + list.size() + " entries"; - if (list.size() > 300) message += ", displaying the first 300."; else message += "."; - Object array[] = list.toArray(); Arrays.sort( array, sorter ); entries = array; + + // Format a message about filtered addressbook size, and the number of displayed entries + // addressbook.jsp catches the case where the whole book is empty. + String filterArg = ""; + if( search != null && search.length() > 0 ) { + message = "Search "; + } + if( filter != null && filter.length() > 0 ) { + if( search != null && search.length() > 0 ) + message += "within "; + message += "Filtered list "; + filterArg = "&filter=" + filter; + } + if (entries.length == 0) { + message += "- no matches"; + } else if (getBeginInt() == 0 && getEndInt() == entries.length - 1) { + if (message.length() == 0) + message = "Addressbook "; + message += "contains " + entries.length + " entries"; + } else { + if (getBeginInt() > 0) { + int newBegin = Math.max(0, getBeginInt() - DISPLAY_SIZE); + int newEnd = Math.max(0, getBeginInt() - 1); + message += "" + newBegin + + '-' + newEnd + " | "; + } + message += "Showing " + getBegin() + '-' + getEnd() + " of " + entries.length; + if (getEndInt() < entries.length - 1) { + int newBegin = Math.min(entries.length - 1, getEndInt() + 1); + int newEnd = Math.min(entries.length, getEndInt() + DISPLAY_SIZE); + message += " | " + newBegin + + '-' + newEnd + ""; + } + } } catch (Exception e) { Debug.debug( e.getClass().getName() + ": " + e.getMessage() ); @@ -302,4 +336,26 @@ public class AddressbookBean public void setHostname(String hostname) { this.hostname = hostname; } + private int getBeginInt() { + return Math.max(0, Math.min(entries.length - 1, beginIndex)); + } + public String getBegin() { + return "" + getBeginInt(); + } + public void setBegin(String s) { + try { + beginIndex = Integer.parseInt(s); + } catch (NumberFormatException nfe) {} + } + private int getEndInt() { + return Math.max(0, Math.max(getBeginInt(), Math.min(entries.length - 1, endIndex))); + } + public String getEnd() { + return "" + getEndInt(); + } + public void setEnd(String s) { + try { + endIndex = Integer.parseInt(s); + } catch (NumberFormatException nfe) {} + } } diff --git a/apps/susidns/src/jsp/addressbook.jsp b/apps/susidns/src/jsp/addressbook.jsp index d36b91354..d3cf0c3b4 100644 --- a/apps/susidns/src/jsp/addressbook.jsp +++ b/apps/susidns/src/jsp/addressbook.jsp @@ -46,10 +46,10 @@ addressbooks -master | -router | -published | -private * +master | +router | +published | +private * subscriptions * configuration * overview @@ -64,42 +64,46 @@ ${book.loadBookMessages} + -Filter: a -b -c -d -e -f -g -h -i -j -k -l -m -n -o -p -q -r -s -t -u -v -w -x -y -z -0-9 -all +Filter: +a +b +c +d +e +f +g +h +i +j +k +l +m +n +o +p +q +r +s +t +u +v +w +x +y +z +0-9 +all Current filter: ${book.filter} -(clear filter) +(clear filter) + + Search: @@ -109,9 +113,12 @@ + + + @@ -127,8 +134,8 @@ Name Destination - - + + @@ -136,7 +143,7 @@ ${addr.name} - (addrhlpr) -${addr.destination} +${addr.destination} @@ -160,8 +167,9 @@ Add new destination: -Hostname: -Destination: ${book.destination} +Hostname: +Destination: ${book.destination} + diff --git a/build.xml b/build.xml index fc251a40a..f9dc3611b 100644 --- a/build.xml +++ b/build.xml @@ -72,7 +72,6 @@ - @@ -103,7 +102,7 @@ - + @@ -210,7 +209,6 @@ - @@ -396,7 +394,6 @@ - @@ -491,7 +488,7 @@ - + diff --git a/installer/resources/wrapper.config b/installer/resources/wrapper.config index 42958ba77..e35484de1 100644 --- a/installer/resources/wrapper.config +++ b/installer/resources/wrapper.config @@ -46,18 +46,17 @@ wrapper.java.classpath.11=lib/jasper-compiler.jar wrapper.java.classpath.12=lib/jasper-runtime.jar wrapper.java.classpath.13=lib/commons-logging.jar wrapper.java.classpath.14=lib/commons-el.jar -wrapper.java.classpath.15=lib/ant.jar # java service wrapper, BSD -wrapper.java.classpath.16=lib/wrapper.jar +wrapper.java.classpath.15=lib/wrapper.jar # systray, LGPL -wrapper.java.classpath.17=lib/systray.jar -wrapper.java.classpath.18=lib/systray4j.jar +wrapper.java.classpath.16=lib/systray.jar +wrapper.java.classpath.17=lib/systray4j.jar # BOB -wrapper.java.classpath.19=lib/BOB.jar +wrapper.java.classpath.18=lib/BOB.jar # desktopgui -wrapper.java.classpath.20=lib/appframework.jar -wrapper.java.classpath.21=lib/swing-worker.jar -wrapper.java.classpath.22=lib/desktopgui.jar +wrapper.java.classpath.19=lib/appframework.jar +wrapper.java.classpath.20=lib/swing-worker.jar +wrapper.java.classpath.21=lib/desktopgui.jar # Java Library Path (location of Wrapper.DLL or libwrapper.so) wrapper.java.library.path.1=. diff --git a/licenses/NOTICE-Ant.txt b/licenses/NOTICE-Ant.txt deleted file mode 100644 index 1fb6dde47..000000000 --- a/licenses/NOTICE-Ant.txt +++ /dev/null @@ -1,15 +0,0 @@ - ========================================================================= - == NOTICE file corresponding to the section 4 d of == - == the Apache License, Version 2.0, == - == in this case for the Apache Ant distribution. == - ========================================================================= - - This product includes software developed by - The Apache Software Foundation (http://www.apache.org/). - - This product includes also software developed by : - - the W3C consortium (http://www.w3c.org) , - - the SAX project (http://www.saxproject.org) - - Please read the different LICENSE files present in the root directory of - this distribution. diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java index 7c37cfc18..3279f437c 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java @@ -12,6 +12,8 @@ import java.util.Set; import net.i2p.data.DataStructure; import net.i2p.data.Hash; +import net.i2p.data.LeaseSet; +import net.i2p.data.RouterInfo; import net.i2p.router.Job; import net.i2p.router.RouterContext; @@ -45,10 +47,23 @@ class FloodfillStoreJob extends StoreJob { @Override protected void succeed() { super.succeed(); - if (_state != null) - getContext().jobQueue().addJob(new FloodfillVerifyStoreJob(getContext(), _state.getTarget(), _facade)); + if (_state != null) { + // Get the time stamp from the data we sent, so the Verify job can meke sure that + // it finds something stamped with that time or newer. + long published = 0; + boolean isRouterInfo = false; + DataStructure data = _state.getData(); + if (data instanceof RouterInfo) { + published = ((RouterInfo) data).getPublished(); + isRouterInfo = true; + } else if (data instanceof LeaseSet) { + published = ((LeaseSet) data).getEarliestLeaseDate(); + } + getContext().jobQueue().addJob(new FloodfillVerifyStoreJob(getContext(), _state.getTarget(), + published, isRouterInfo, _facade)); + } } @Override public String getName() { return "Floodfill netDb store"; } -} \ No newline at end of file +} diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java index d541f781f..e368b4567 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java @@ -5,6 +5,8 @@ import java.util.List; import net.i2p.data.DataStructure; import net.i2p.data.Hash; +import net.i2p.data.LeaseSet; +import net.i2p.data.RouterInfo; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DatabaseStoreMessage; @@ -29,21 +31,33 @@ public class FloodfillVerifyStoreJob extends JobImpl { private FloodfillNetworkDatabaseFacade _facade; private long _expiration; private long _sendTime; + private long _published; + private boolean _isRouterInfo; private static final int VERIFY_TIMEOUT = 10*1000; - public FloodfillVerifyStoreJob(RouterContext ctx, Hash key, FloodfillNetworkDatabaseFacade facade) { + public FloodfillVerifyStoreJob(RouterContext ctx, Hash key, long published, boolean isRouterInfo, FloodfillNetworkDatabaseFacade facade) { super(ctx); _key = key; + _published = published; + _isRouterInfo = isRouterInfo; _log = ctx.logManager().getLog(getClass()); _facade = facade; // wait 10 seconds before trying to verify the store getTiming().setStartAfter(ctx.clock().now() + VERIFY_TIMEOUT); - getContext().statManager().createRateStat("netDb.floodfillVerifyOK", "How long a floodfill verify takes when it succeeds", "NetworkDatabase", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); - getContext().statManager().createRateStat("netDb.floodfillVerifyFail", "How long a floodfill verify takes when it fails", "NetworkDatabase", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); - getContext().statManager().createRateStat("netDb.floodfillVerifyTimeout", "How long a floodfill verify takes when it times out", "NetworkDatabase", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); + getContext().statManager().createRateStat("netDb.floodfillVerifyOK", "How long a floodfill verify takes when it succeeds", "NetworkDatabase", new long[] { 60*60*1000 }); + getContext().statManager().createRateStat("netDb.floodfillVerifyFail", "How long a floodfill verify takes when it fails", "NetworkDatabase", new long[] { 60*60*1000 }); + getContext().statManager().createRateStat("netDb.floodfillVerifyTimeout", "How long a floodfill verify takes when it times out", "NetworkDatabase", new long[] { 60*60*1000 }); } public String getName() { return "Verify netdb store"; } + + /** + * Wait 10 seconds, then query a random floodfill for the leaseset or routerinfo + * that we just stored to a (hopefully different) floodfill peer. + * + * If it fails (after waiting up to another 10 seconds), resend the data. + * If the queried data is older than what we stored, that counts as a fail. + **/ public void runJob() { _target = pickTarget(); if (_target == null) return; @@ -118,20 +132,29 @@ public class FloodfillVerifyStoreJob extends JobImpl { public void runJob() { long delay = getContext().clock().now() - _sendTime; if (_message instanceof DatabaseStoreMessage) { - // store ok, w00t! - // Hmm should we verify it's as recent as the one we sent??? - getContext().profileManager().dbLookupSuccessful(_target, delay); - getContext().statManager().addRateData("netDb.floodfillVerifyOK", delay, 0); - } else { - // store failed, boo, hiss! - if (_message instanceof DatabaseSearchReplyMessage) { - // assume 0 old, all new, 0 invalid, 0 dup - getContext().profileManager().dbLookupReply(_target, 0, - ((DatabaseSearchReplyMessage)_message).getNumReplies(), 0, 0, delay); + // Verify it's as recent as the one we sent + boolean success = false; + DatabaseStoreMessage dsm = (DatabaseStoreMessage)_message; + if (_isRouterInfo && dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO) + success = dsm.getRouterInfo().getPublished() >= _published; + else if ((!_isRouterInfo) && dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) + success = dsm.getLeaseSet().getEarliestLeaseDate() >= _published; + if (success) { + // store ok, w00t! + getContext().profileManager().dbLookupSuccessful(_target, delay); + getContext().statManager().addRateData("netDb.floodfillVerifyOK", delay, 0); + return; } - getContext().statManager().addRateData("netDb.floodfillVerifyFail", delay, 0); - resend(); + if (_log.shouldLog(Log.WARN)) + _log.warn("Verify failed - older"); + } else if (_message instanceof DatabaseSearchReplyMessage) { + // assume 0 old, all new, 0 invalid, 0 dup + getContext().profileManager().dbLookupReply(_target, 0, + ((DatabaseSearchReplyMessage)_message).getNumReplies(), 0, 0, delay); } + // store failed, boo, hiss! + getContext().statManager().addRateData("netDb.floodfillVerifyFail", delay, 0); + resend(); } public void setMessage(I2NPMessage message) { _message = message; } } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java index 28a35862b..c8a0685af 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java @@ -627,9 +627,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException { long now = _context.clock().now(); boolean upLongEnough = _context.router().getUptime() > 60*60*1000; - // Once we're over 300 routers, reduce the expiration time down from the default, + // Once we're over 150 routers, reduce the expiration time down from the default, // as a crude way of limiting memory usage. - // i.e. at 600 routers the expiration time will be about half the default, etc. + // i.e. at 300 routers the expiration time will be about half the default, etc. // And if we're floodfill, we can keep the expiration really short, since // we are always getting the latest published to us. // As the net grows this won't be sufficient, and we'll have to implement @@ -638,9 +638,10 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context)) adjustedExpiration = ROUTER_INFO_EXPIRATION_FLOODFILL; else + // _kb.size() includes leasesets but that's ok adjustedExpiration = Math.min(ROUTER_INFO_EXPIRATION, ROUTER_INFO_EXPIRATION_MIN + - ((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * 300 / (_kb.size() + 1))); + ((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * 150 / (_kb.size() + 1))); if (!key.equals(routerInfo.getIdentity().getHash())) { if (_log.shouldLog(Log.WARN))
addressbooks -master | -router | -published | -private * +master | +router | +published | +private * subscriptions * configuration * overview @@ -64,42 +64,46 @@ ${book.loadBookMessages} + -Filter: a -b -c -d -e -f -g -h -i -j -k -l -m -n -o -p -q -r -s -t -u -v -w -x -y -z -0-9 -all +Filter: +a +b +c +d +e +f +g +h +i +j +k +l +m +n +o +p +q +r +s +t +u +v +w +x +y +z +0-9 +all Current filter: ${book.filter} -(clear filter) +(clear filter) + + Search: @@ -109,9 +113,12 @@ + + + @@ -127,8 +134,8 @@ Name Destination - - + + @@ -136,7 +143,7 @@ ${addr.name} - (addrhlpr) -${addr.destination} +${addr.destination} @@ -160,8 +167,9 @@ Add new destination: -Hostname: -Destination: ${book.destination} +Hostname: +Destination: ${book.destination} + diff --git a/build.xml b/build.xml index fc251a40a..f9dc3611b 100644 --- a/build.xml +++ b/build.xml @@ -72,7 +72,6 @@ - @@ -103,7 +102,7 @@ - + @@ -210,7 +209,6 @@ - @@ -396,7 +394,6 @@ - @@ -491,7 +488,7 @@ - + diff --git a/installer/resources/wrapper.config b/installer/resources/wrapper.config index 42958ba77..e35484de1 100644 --- a/installer/resources/wrapper.config +++ b/installer/resources/wrapper.config @@ -46,18 +46,17 @@ wrapper.java.classpath.11=lib/jasper-compiler.jar wrapper.java.classpath.12=lib/jasper-runtime.jar wrapper.java.classpath.13=lib/commons-logging.jar wrapper.java.classpath.14=lib/commons-el.jar -wrapper.java.classpath.15=lib/ant.jar # java service wrapper, BSD -wrapper.java.classpath.16=lib/wrapper.jar +wrapper.java.classpath.15=lib/wrapper.jar # systray, LGPL -wrapper.java.classpath.17=lib/systray.jar -wrapper.java.classpath.18=lib/systray4j.jar +wrapper.java.classpath.16=lib/systray.jar +wrapper.java.classpath.17=lib/systray4j.jar # BOB -wrapper.java.classpath.19=lib/BOB.jar +wrapper.java.classpath.18=lib/BOB.jar # desktopgui -wrapper.java.classpath.20=lib/appframework.jar -wrapper.java.classpath.21=lib/swing-worker.jar -wrapper.java.classpath.22=lib/desktopgui.jar +wrapper.java.classpath.19=lib/appframework.jar +wrapper.java.classpath.20=lib/swing-worker.jar +wrapper.java.classpath.21=lib/desktopgui.jar # Java Library Path (location of Wrapper.DLL or libwrapper.so) wrapper.java.library.path.1=. diff --git a/licenses/NOTICE-Ant.txt b/licenses/NOTICE-Ant.txt deleted file mode 100644 index 1fb6dde47..000000000 --- a/licenses/NOTICE-Ant.txt +++ /dev/null @@ -1,15 +0,0 @@ - ========================================================================= - == NOTICE file corresponding to the section 4 d of == - == the Apache License, Version 2.0, == - == in this case for the Apache Ant distribution. == - ========================================================================= - - This product includes software developed by - The Apache Software Foundation (http://www.apache.org/). - - This product includes also software developed by : - - the W3C consortium (http://www.w3c.org) , - - the SAX project (http://www.saxproject.org) - - Please read the different LICENSE files present in the root directory of - this distribution. diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java index 7c37cfc18..3279f437c 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java @@ -12,6 +12,8 @@ import java.util.Set; import net.i2p.data.DataStructure; import net.i2p.data.Hash; +import net.i2p.data.LeaseSet; +import net.i2p.data.RouterInfo; import net.i2p.router.Job; import net.i2p.router.RouterContext; @@ -45,10 +47,23 @@ class FloodfillStoreJob extends StoreJob { @Override protected void succeed() { super.succeed(); - if (_state != null) - getContext().jobQueue().addJob(new FloodfillVerifyStoreJob(getContext(), _state.getTarget(), _facade)); + if (_state != null) { + // Get the time stamp from the data we sent, so the Verify job can meke sure that + // it finds something stamped with that time or newer. + long published = 0; + boolean isRouterInfo = false; + DataStructure data = _state.getData(); + if (data instanceof RouterInfo) { + published = ((RouterInfo) data).getPublished(); + isRouterInfo = true; + } else if (data instanceof LeaseSet) { + published = ((LeaseSet) data).getEarliestLeaseDate(); + } + getContext().jobQueue().addJob(new FloodfillVerifyStoreJob(getContext(), _state.getTarget(), + published, isRouterInfo, _facade)); + } } @Override public String getName() { return "Floodfill netDb store"; } -} \ No newline at end of file +} diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java index d541f781f..e368b4567 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java @@ -5,6 +5,8 @@ import java.util.List; import net.i2p.data.DataStructure; import net.i2p.data.Hash; +import net.i2p.data.LeaseSet; +import net.i2p.data.RouterInfo; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DatabaseStoreMessage; @@ -29,21 +31,33 @@ public class FloodfillVerifyStoreJob extends JobImpl { private FloodfillNetworkDatabaseFacade _facade; private long _expiration; private long _sendTime; + private long _published; + private boolean _isRouterInfo; private static final int VERIFY_TIMEOUT = 10*1000; - public FloodfillVerifyStoreJob(RouterContext ctx, Hash key, FloodfillNetworkDatabaseFacade facade) { + public FloodfillVerifyStoreJob(RouterContext ctx, Hash key, long published, boolean isRouterInfo, FloodfillNetworkDatabaseFacade facade) { super(ctx); _key = key; + _published = published; + _isRouterInfo = isRouterInfo; _log = ctx.logManager().getLog(getClass()); _facade = facade; // wait 10 seconds before trying to verify the store getTiming().setStartAfter(ctx.clock().now() + VERIFY_TIMEOUT); - getContext().statManager().createRateStat("netDb.floodfillVerifyOK", "How long a floodfill verify takes when it succeeds", "NetworkDatabase", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); - getContext().statManager().createRateStat("netDb.floodfillVerifyFail", "How long a floodfill verify takes when it fails", "NetworkDatabase", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); - getContext().statManager().createRateStat("netDb.floodfillVerifyTimeout", "How long a floodfill verify takes when it times out", "NetworkDatabase", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); + getContext().statManager().createRateStat("netDb.floodfillVerifyOK", "How long a floodfill verify takes when it succeeds", "NetworkDatabase", new long[] { 60*60*1000 }); + getContext().statManager().createRateStat("netDb.floodfillVerifyFail", "How long a floodfill verify takes when it fails", "NetworkDatabase", new long[] { 60*60*1000 }); + getContext().statManager().createRateStat("netDb.floodfillVerifyTimeout", "How long a floodfill verify takes when it times out", "NetworkDatabase", new long[] { 60*60*1000 }); } public String getName() { return "Verify netdb store"; } + + /** + * Wait 10 seconds, then query a random floodfill for the leaseset or routerinfo + * that we just stored to a (hopefully different) floodfill peer. + * + * If it fails (after waiting up to another 10 seconds), resend the data. + * If the queried data is older than what we stored, that counts as a fail. + **/ public void runJob() { _target = pickTarget(); if (_target == null) return; @@ -118,20 +132,29 @@ public class FloodfillVerifyStoreJob extends JobImpl { public void runJob() { long delay = getContext().clock().now() - _sendTime; if (_message instanceof DatabaseStoreMessage) { - // store ok, w00t! - // Hmm should we verify it's as recent as the one we sent??? - getContext().profileManager().dbLookupSuccessful(_target, delay); - getContext().statManager().addRateData("netDb.floodfillVerifyOK", delay, 0); - } else { - // store failed, boo, hiss! - if (_message instanceof DatabaseSearchReplyMessage) { - // assume 0 old, all new, 0 invalid, 0 dup - getContext().profileManager().dbLookupReply(_target, 0, - ((DatabaseSearchReplyMessage)_message).getNumReplies(), 0, 0, delay); + // Verify it's as recent as the one we sent + boolean success = false; + DatabaseStoreMessage dsm = (DatabaseStoreMessage)_message; + if (_isRouterInfo && dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO) + success = dsm.getRouterInfo().getPublished() >= _published; + else if ((!_isRouterInfo) && dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) + success = dsm.getLeaseSet().getEarliestLeaseDate() >= _published; + if (success) { + // store ok, w00t! + getContext().profileManager().dbLookupSuccessful(_target, delay); + getContext().statManager().addRateData("netDb.floodfillVerifyOK", delay, 0); + return; } - getContext().statManager().addRateData("netDb.floodfillVerifyFail", delay, 0); - resend(); + if (_log.shouldLog(Log.WARN)) + _log.warn("Verify failed - older"); + } else if (_message instanceof DatabaseSearchReplyMessage) { + // assume 0 old, all new, 0 invalid, 0 dup + getContext().profileManager().dbLookupReply(_target, 0, + ((DatabaseSearchReplyMessage)_message).getNumReplies(), 0, 0, delay); } + // store failed, boo, hiss! + getContext().statManager().addRateData("netDb.floodfillVerifyFail", delay, 0); + resend(); } public void setMessage(I2NPMessage message) { _message = message; } } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java index 28a35862b..c8a0685af 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java @@ -627,9 +627,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException { long now = _context.clock().now(); boolean upLongEnough = _context.router().getUptime() > 60*60*1000; - // Once we're over 300 routers, reduce the expiration time down from the default, + // Once we're over 150 routers, reduce the expiration time down from the default, // as a crude way of limiting memory usage. - // i.e. at 600 routers the expiration time will be about half the default, etc. + // i.e. at 300 routers the expiration time will be about half the default, etc. // And if we're floodfill, we can keep the expiration really short, since // we are always getting the latest published to us. // As the net grows this won't be sufficient, and we'll have to implement @@ -638,9 +638,10 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context)) adjustedExpiration = ROUTER_INFO_EXPIRATION_FLOODFILL; else + // _kb.size() includes leasesets but that's ok adjustedExpiration = Math.min(ROUTER_INFO_EXPIRATION, ROUTER_INFO_EXPIRATION_MIN + - ((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * 300 / (_kb.size() + 1))); + ((ROUTER_INFO_EXPIRATION - ROUTER_INFO_EXPIRATION_MIN) * 150 / (_kb.size() + 1))); if (!key.equals(routerInfo.getIdentity().getHash())) { if (_log.shouldLog(Log.WARN))
Filter: a -b -c -d -e -f -g -h -i -j -k -l -m -n -o -p -q -r -s -t -u -v -w -x -y -z -0-9 -all
Filter: +a +b +c +d +e +f +g +h +i +j +k +l +m +n +o +p +q +r +s +t +u +v +w +x +y +z +0-9 +all
Current filter: ${book.filter} -(clear filter)