diff --git a/history.txt b/history.txt
index fa85b7afa..370ec2820 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,13 @@
+2008-06-07 zzz
+ * NetDb: Tweak some logging on lease problems
+ * Shitlist:
+ - Add shitlistForever() and isShitlistedForever(), unused for now
+ - Sort the HTML output by router hash
+ * config.jsp: Add another warning
+ * netdb.jsp:
+ - Sort the lease HTML output by dest hash, local first
+ - Sort the router HTML output by router hash
+
2008-06-06 zzz
* LeaseSet:
- Sort the leases by expiration date in TunnelPool.locked_buildNewLeaseSet()
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 16af54d82..3f2309f5f 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -17,7 +17,7 @@ import net.i2p.CoreVersion;
public class RouterVersion {
public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $";
public final static String VERSION = "0.6.1.33";
- public final static long BUILD = 2003;
+ public final static long BUILD = 2004;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID);
diff --git a/router/java/src/net/i2p/router/Shitlist.java b/router/java/src/net/i2p/router/Shitlist.java
index 43c24a2e6..48cadfcf4 100644
--- a/router/java/src/net/i2p/router/Shitlist.java
+++ b/router/java/src/net/i2p/router/Shitlist.java
@@ -11,8 +11,8 @@ package net.i2p.router;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
-import net.i2p.data.DataHelper;
+import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.router.peermanager.PeerProfile;
import net.i2p.util.Log;
@@ -38,6 +38,8 @@ public class Shitlist {
}
public final static long SHITLIST_DURATION_MS = 40*60*1000; // 40 minute shitlist
+ public final static long SHITLIST_DURATION_MAX = 60*60*1000;
+ public final static long SHITLIST_DURATION_FOREVER = 181l*24*60*60*1000; // will get rounded down to 180d on console
public Shitlist(RouterContext context) {
_context = context;
@@ -91,6 +93,12 @@ public class Shitlist {
}
public boolean shitlistRouter(Hash peer, String reason) { return shitlistRouter(peer, reason, null); }
public boolean shitlistRouter(Hash peer, String reason, String transport) {
+ return shitlistRouter(peer, reason, null, false);
+ }
+ public boolean shitlistRouterForever(Hash peer, String reason) {
+ return shitlistRouter(peer, reason, null, true);
+ }
+ public boolean shitlistRouter(Hash peer, String reason, String transport, boolean forever) {
if (peer == null) {
_log.error("wtf, why did we try to shitlist null?", new Exception("shitfaced"));
return false;
@@ -103,18 +111,21 @@ public class Shitlist {
if (_log.shouldLog(Log.INFO))
_log.info("Shitlisting router " + peer.toBase64(), new Exception("Shitlist cause: " + reason));
- long period = SHITLIST_DURATION_MS + _context.random().nextLong(SHITLIST_DURATION_MS);
- PeerProfile prof = _context.profileOrganizer().getProfile(peer);
- if (prof != null) {
- period = SHITLIST_DURATION_MS << prof.incrementShitlists();
- period += _context.random().nextLong(period);
- }
-
- if (period > 60*60*1000)
- period = 60*60*1000;
-
Entry e = new Entry();
- e.expireOn = _context.clock().now() + period;
+ if (forever) {
+ e.expireOn = _context.clock().now() + SHITLIST_DURATION_FOREVER;
+ } else {
+ long period = SHITLIST_DURATION_MS + _context.random().nextLong(SHITLIST_DURATION_MS);
+ PeerProfile prof = _context.profileOrganizer().getProfile(peer);
+ if (prof != null) {
+ period = SHITLIST_DURATION_MS << prof.incrementShitlists();
+ period += _context.random().nextLong(period);
+ }
+
+ if (period > SHITLIST_DURATION_MAX)
+ period = SHITLIST_DURATION_MAX;
+ e.expireOn = _context.clock().now() + period;
+ }
e.cause = reason;
e.transports = null;
if (transport != null) {
@@ -123,17 +134,22 @@ public class Shitlist {
}
synchronized (_entries) {
- Entry old = (Entry)_entries.put(peer, e);
+ Entry old = (Entry)_entries.get(peer);
if (old != null) {
wasAlready = true;
- _entries.put(peer, old);
- if (e.transports == null) {
- old.transports = null;
- } else if (old.transports != null) {
- old.transports.addAll(e.transports);
+ // take the oldest expiration and cause, combine transports
+ if (old.expireOn > e.expireOn) {
+ e.expireOn = old.expireOn;
+ e.cause = old.cause;
+ }
+ if (e.transports != null) {
+ if (old.transports != null)
+ e.transports.addAll(old.transports);
+ else
+ e.transports = null;
}
- e = old;
}
+ _entries.put(peer, e);
}
if (transport == null) {
@@ -222,13 +238,27 @@ public class Shitlist {
return rv;
}
+ public boolean isShitlistedForever(Hash peer) {
+ Entry entry;
+ synchronized (_entries) {
+ entry = (Entry)_entries.get(peer);
+ }
+ return entry != null && entry.expireOn > _context.clock().now() + SHITLIST_DURATION_MAX;
+ }
+
+ class HashComparator implements Comparator {
+ public int compare(Object l, Object r) {
+ return ((Hash)l).toBase64().compareTo(((Hash)r).toBase64());
+ }
+ }
+
public void renderStatusHTML(Writer out) throws IOException {
StringBuffer buf = new StringBuffer(1024);
buf.append("
Shitlist
");
- Map entries = null;
+ Map entries = new TreeMap(new HashComparator());
synchronized (_entries) {
- entries = new HashMap(_entries);
+ entries.putAll(_entries);
}
buf.append("");
@@ -241,7 +271,7 @@ public class Shitlist {
continue;
}
buf.append("- ").append(key.toBase64()).append("");
- buf.append(" (?)");
+ buf.append(" (netdb)");
buf.append(" expiring in ");
buf.append(DataHelper.formatDuration(entry.expireOn-_context.clock().now()));
Set transports = entry.transports;
@@ -251,12 +281,16 @@ public class Shitlist {
buf.append("
\n");
buf.append(entry.cause);
}
+ // future
+ // buf.append(" (unshitlist now)");
buf.append(" \n");
}
buf.append("
\n");
- buf.append("Partial shitlisted peers (only blocked on some transports): ");
- buf.append(partial);
- buf.append("\n");
+ if (partial > 0) {
+ buf.append("Partial shitlisted peers (only blocked on some transports): ");
+ buf.append(partial);
+ buf.append("\n");
+ }
out.write(buf.toString());
out.flush();
}
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 60e2b1b8b..06b2fe398 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
@@ -13,6 +13,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
+import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -20,6 +21,7 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
+import java.util.TreeSet;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException;
@@ -579,13 +581,13 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
*/
String validate(Hash key, LeaseSet leaseSet) {
if (!key.equals(leaseSet.getDestination().calculateHash())) {
- if (_log.shouldLog(Log.WARN))
- _log.warn("Invalid store attempt! key does not match leaseSet.destination! key = "
+ 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 (_log.shouldLog(Log.WARN))
- _log.warn("Invalid leaseSet signature! leaseSet = " + leaseSet);
+ 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();
@@ -597,8 +599,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
+ " 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 (_log.shouldLog(Log.WARN))
- _log.warn("LeaseSet to expire too far in the future: "
+ if (_log.shouldLog(Log.ERROR))
+ _log.error("LeaseSet to expire too far in the future: "
+ leaseSet.getDestination().calculateHash().toBase64()
+ " expires on " + new Date(leaseSet.getEarliestLeaseDate()), new Exception("Rejecting store"));
return "Expired leaseSet for " + leaseSet.getDestination().calculateHash().toBase64()
@@ -924,6 +926,24 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
_context.jobQueue().addJob(new StoreJob(_context, this, key, ds, onSuccess, onFailure, sendTimeout, toIgnore));
}
+ class LeaseSetComparator implements Comparator {
+ public int compare(Object l, Object r) {
+ Destination dl = ((LeaseSet)l).getDestination();
+ Destination dr = ((LeaseSet)r).getDestination();
+ boolean locall = _context.clientManager().isLocal(dl);
+ boolean localr = _context.clientManager().isLocal(dr);
+ if (locall && !localr) return -1;
+ if (localr && !locall) return 1;
+ return dl.calculateHash().toBase64().compareTo(dr.calculateHash().toBase64());
+ }
+ }
+
+ class RouterInfoComparator implements Comparator {
+ public int compare(Object l, Object r) {
+ return ((RouterInfo)l).getIdentity().getHash().toBase64().compareTo(((RouterInfo)r).getIdentity().getHash().toBase64());
+ }
+ }
+
public void renderStatusHTML(Writer out) throws IOException {
StringBuffer buf = new StringBuffer(10*1024);
buf.append("Kademlia Network DB Contents
\n");
@@ -933,7 +953,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
out.flush();
return;
}
- Set leases = getLeases();
+ Set leases = new TreeSet(new LeaseSetComparator());
+ leases.addAll(getLeases());
buf.append("Leases
\n");
out.write(buf.toString());
buf.setLength(0);
@@ -978,7 +999,6 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
}
Hash us = _context.routerHash();
- Set routers = getRouters();
out.write("Routers
\n");
RouterInfo ourInfo = _context.router().getRouterInfo();
@@ -989,6 +1009,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
/* coreVersion to Map of routerVersion to Integer */
Map versions = new TreeMap();
+ Set routers = new TreeSet(new RouterInfoComparator());
+ routers.addAll(getRouters());
for (Iterator iter = routers.iterator(); iter.hasNext(); ) {
RouterInfo ri = (RouterInfo)iter.next();
Hash key = ri.getIdentity().getHash();
@@ -1038,7 +1060,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
String hash = info.getIdentity().getHash().toBase64();
if (isUs) {
buf.append("");
- buf.append("Our info (").append(hash).append(") :
\n");
+ buf.append("Our info: ").append(hash).append("
\n");
} else {
buf.append("");
buf.append("Peer info for: ").append(hash).append("
\n");