diff --git a/history.txt b/history.txt index f0f1fdc47..c39d1758a 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,11 @@ -$Id: history.txt,v 1.478 2006-05-17 22:42:57 complication Exp $ +$Id: history.txt,v 1.479 2006-05-18 17:31:08 jrandom Exp $ + +2006-05-31 jrandom + * Only send netDb searches to the floodfill peers for the time being + * Add some proof of concept filters for tunnel participation. By default, + it will skip peers with an advertised bandwith of less than 32KBps or + an advertised uptime of less than 2 hours. If this is sufficient, a + safer implementation of these filters will be implemented. * 2006-05-18 0.6.1.19 released diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 9d6fa3ecc..fb1740796 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.418 $ $Date: 2006-05-17 22:42:57 $"; + public final static String ID = "$Revision: 1.419 $ $Date: 2006-05-18 17:31:10 $"; public final static String VERSION = "0.6.1.19"; - public final static long BUILD = 0; + public final static long BUILD = 1; 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/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java index 0f9e62a51..93f362717 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java @@ -120,6 +120,22 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad else return false; } + + public List getKnownRouterData() { + List rv = new ArrayList(); + DataStore ds = getDataStore(); + if (ds != null) { + Set keys = ds.getKeys(); + if (keys != null) { + for (Iterator iter = keys.iterator(); iter.hasNext(); ) { + Object o = getDataStore().get((Hash)iter.next()); + if (o instanceof RouterInfo) + rv.add(o); + } + } + } + return rv; + } /** * Begin a kademlia style search for the key specified, which can take up to timeoutMs and diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java index 54a10d1d7..8ebdf2f45 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java @@ -87,6 +87,8 @@ class FloodfillPeerSelector extends PeerSelector { if ( (!SearchJob.onlyQueryFloodfillPeers(_context)) && (_wanted > _matches) && (_key != null) ) { BigInteger diff = getDistance(_key, entry); _sorted.put(diff, entry); + } else { + return; } } _matches++; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java index 530990409..075b3bd75 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java @@ -121,7 +121,7 @@ class SearchJob extends JobImpl { public long getExpiration() { return _expiration; } public long getTimeoutMs() { return _timeoutMs; } - private static final boolean DEFAULT_FLOODFILL_ONLY = false; + private static final boolean DEFAULT_FLOODFILL_ONLY = true; static boolean onlyQueryFloodfillPeers(RouterContext ctx) { if (isCongested(ctx)) diff --git a/router/java/src/net/i2p/router/peermanager/PeerManager.java b/router/java/src/net/i2p/router/peermanager/PeerManager.java index b3b418daa..38cbc6236 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManager.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManager.java @@ -15,9 +15,13 @@ import java.util.*; import net.i2p.data.Hash; import net.i2p.router.PeerSelectionCriteria; import net.i2p.router.RouterContext; +import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.util.SimpleTimer; import net.i2p.util.Log; +import net.i2p.data.RouterInfo; +import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; + /** * Manage the current state of the statistics * @@ -204,12 +208,27 @@ class PeerManager { return null; } public List getPeersByCapability(char capability) { - synchronized (_capabilitiesByPeer) { - List peers = locked_getPeers(capability); - if (peers != null) - return new ArrayList(peers); + if (false) { + synchronized (_capabilitiesByPeer) { + List peers = locked_getPeers(capability); + if (peers != null) + return new ArrayList(peers); + } + return null; + } else { + FloodfillNetworkDatabaseFacade f = (FloodfillNetworkDatabaseFacade)_context.netDb(); + List routerInfos = f.getKnownRouterData(); + List rv = new ArrayList(); + for (Iterator iter = routerInfos.iterator(); iter.hasNext(); ) { + RouterInfo ri = (RouterInfo)iter.next(); + String caps = ri.getCapabilities(); + if (caps.indexOf(capability) >= 0) + rv.add(ri.getIdentity().calculateHash()); + } + if (_log.shouldLog(Log.WARN)) + _log.warn("Peers with capacity " + capability + ": " + rv.size()); + return rv; } - return null; } public void renderStatusHTML(Writer out) throws IOException { diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java index 721e88502..8d606e3f4 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java @@ -2,11 +2,11 @@ package net.i2p.router.tunnel.pool; import java.util.*; import net.i2p.I2PAppContext; -import net.i2p.data.DataFormatException; -import net.i2p.data.Hash; +import net.i2p.data.*; import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.router.TunnelPoolSettings; +import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.util.Log; /** @@ -153,6 +153,103 @@ abstract class TunnelPeerSelector { if (caps == null) return new HashSet(0); HashSet rv = new HashSet(caps); return rv; + } else if (filterSlow(ctx, isInbound, isExploratory)) { + Log log = ctx.logManager().getLog(TunnelPeerSelector.class); + String excludeCaps = ctx.getProperty("router.excludePeerCaps", + String.valueOf(Router.CAPABILITY_BW16) + + String.valueOf(Router.CAPABILITY_BW32)); + Set peers = new HashSet(); + if (excludeCaps != null) { + char excl[] = excludeCaps.toCharArray(); + FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade)ctx.netDb(); + List known = fac.getKnownRouterData(); + if (known != null) { + for (int i = 0; i < known.size(); i++) { + RouterInfo peer = (RouterInfo)known.get(i); + String cap = peer.getCapabilities(); + if (cap == null) { + peers.add(peer.getIdentity().calculateHash()); + continue; + } + for (int j = 0; j < excl.length; j++) { + if (cap.indexOf(excl[j]) >= 0) { + peers.add(peer.getIdentity().calculateHash()); + continue; + } + } + int maxLen = 0; + if (cap.indexOf(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL) >= 0) + maxLen++; + if (cap.indexOf(Router.CAPABILITY_REACHABLE) >= 0) + maxLen++; + if (cap.indexOf(Router.CAPABILITY_UNREACHABLE) >= 0) + maxLen++; + if (cap.length() <= maxLen) + peers.add(peer.getIdentity().calculateHash()); + // otherwise, it contains flags we aren't trying to focus on, + // so don't exclude it based on published capacity + + if (filterUptime(ctx, isInbound, isExploratory)) { + Properties opts = peer.getOptions(); + if (opts != null) { + String val = opts.getProperty("stat_uptime"); + long uptimeMs = 0; + if (val != null) { + long factor = 1; + if (val.endsWith("ms")) { + factor = 1; + val = val.substring(0, val.length()-2); + } else if (val.endsWith("s")) { + factor = 1000l; + val = val.substring(0, val.length()-1); + } else if (val.endsWith("m")) { + factor = 60*1000l; + val = val.substring(0, val.length()-1); + } else if (val.endsWith("h")) { + factor = 60*60*1000l; + val = val.substring(0, val.length()-1); + } else if (val.endsWith("d")) { + factor = 24*60*60*1000l; + val = val.substring(0, val.length()-1); + } + try { uptimeMs = Long.parseLong(val); } catch (NumberFormatException nfe) {} + uptimeMs *= factor; + } else { + // not publishing an uptime, so exclude it + peers.add(peer.getIdentity().calculateHash()); + continue; + } + + long infoAge = ctx.clock().now() - peer.getPublished(); + if (infoAge < 0) { + infoAge = 0; + } else if (infoAge > 24*60*60*1000) { + peers.add(peer.getIdentity().calculateHash()); + continue; + } else { + if (infoAge + uptimeMs < 4*60*60*1000) { + // up for less than 4 hours, so exclude it + peers.add(peer.getIdentity().calculateHash()); + } + } + } else { + // not publishing stats, so exclude it + peers.add(peer.getIdentity().calculateHash()); + continue; + } + } + } + } + /* + for (int i = 0; i < excludeCaps.length(); i++) { + List matches = ctx.peerManager().getPeersByCapability(excludeCaps.charAt(i)); + if (log.shouldLog(Log.INFO)) + log.info("Filtering out " + matches.size() + " peers with capability " + excludeCaps.charAt(i)); + peers.addAll(matches); + } + */ + } + return peers; } else { return new HashSet(1); } @@ -162,6 +259,7 @@ abstract class TunnelPeerSelector { private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.outboundClientExcludeUnreachable"; private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.inboundExploratoryExcludeUnreachable"; private static final String PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.inboundClientExcludeUnreachable"; + private static final boolean DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false; private static final boolean DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = false; private static final boolean DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false; @@ -186,4 +284,56 @@ abstract class TunnelPeerSelector { //System.err.println("Filter unreachable? " + rv + " (inbound? " + isInbound + ", exploratory? " + isExploratory); return rv; } + + + private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_SLOW = "router.outboundExploratoryExcludeSlow"; + private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_SLOW = "router.outboundClientExcludeSlow"; + private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_SLOW = "router.inboundExploratoryExcludeSlow"; + private static final String PROP_INBOUND_CLIENT_EXCLUDE_SLOW = "router.inboundClientExcludeSlow"; + + protected boolean filterSlow(RouterContext ctx, boolean isInbound, boolean isExploratory) { + boolean def = true; + String val = null; + + if (isExploratory) + if (isInbound) + val = ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_SLOW); + else + val = ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_SLOW); + else + if (isInbound) + val = ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_SLOW); + else + val = ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_SLOW); + + boolean rv = (val != null ? Boolean.valueOf(val).booleanValue() : def); + //System.err.println("Filter unreachable? " + rv + " (inbound? " + isInbound + ", exploratory? " + isExploratory); + return rv; + } + + private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UPTIME = "router.outboundExploratoryExcludeUptime"; + private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME = "router.outboundClientExcludeUptime"; + private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UPTIME = "router.inboundExploratoryExcludeUptime"; + private static final String PROP_INBOUND_CLIENT_EXCLUDE_UPTIME = "router.inboundClientExcludeUptime"; + + /** do we want to skip peers who haven't been up for long? */ + protected boolean filterUptime(RouterContext ctx, boolean isInbound, boolean isExploratory) { + boolean def = true; + String val = null; + + if (isExploratory) + if (isInbound) + val = ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_UPTIME); + else + val = ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UPTIME); + else + if (isInbound) + val = ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UPTIME); + else + val = ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME); + + boolean rv = (val != null ? Boolean.valueOf(val).booleanValue() : def); + //System.err.println("Filter unreachable? " + rv + " (inbound? " + isInbound + ", exploratory? " + isExploratory); + return rv; + } } diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java index 0a1578fd3..ad91b74ff 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java @@ -495,11 +495,12 @@ public class TunnelPoolManager implements TunnelManagerFacade { out.write("