diff --git a/history.txt b/history.txt index 39958da08..2ab62f009 100644 --- a/history.txt +++ b/history.txt @@ -1,7 +1,9 @@ + 2014-04-05 zzz * I2PTunnel: - Add server option for unique local address per-client - Fix changing outproxy without stopping tunnel (ticket #1164) + * NetDB: Skip key cert LS stores and verifies for floodfills that don't support them 2014-04-01 zzz * Console: Fix summary bar html when displaying an update constraint diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 282c18b42..0725033fa 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -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 = 2; + public final static long BUILD = 3; /** for example "-test" */ public final static String EXTRA = ""; 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 4661f5c36..24a7bc40a 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java @@ -200,6 +200,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad Hash rkey = _context.routingKeyGenerator().getRoutingKey(key); FloodfillPeerSelector sel = (FloodfillPeerSelector)getPeerSelector(); List peers = sel.selectFloodfillParticipants(rkey, MAX_TO_FLOOD, getKBuckets()); + // todo key cert skip? long until = _context.routingKeyGenerator().getTimeTillMidnight(); if (until < NEXT_RKEY_LS_ADVANCE_TIME || (ds.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO && until < NEXT_RKEY_RI_ADVANCE_TIME)) { @@ -209,6 +210,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad List nextPeers = sel.selectFloodfillParticipants(nkey, NEXT_FLOOD_QTY, getKBuckets()); int i = 0; for (Hash h : nextPeers) { + // todo key cert skip? if (!peers.contains(h)) { peers.add(h); i++; 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 5e312e2d2..645474357 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java @@ -4,8 +4,10 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import net.i2p.data.Certificate; import net.i2p.data.DatabaseEntry; 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; @@ -169,9 +171,31 @@ class FloodfillVerifyStoreJob extends JobImpl { private Hash pickTarget() { Hash rkey = getContext().routingKeyGenerator().getRoutingKey(_key); FloodfillPeerSelector sel = (FloodfillPeerSelector)_facade.getPeerSelector(); - List peers = sel.selectFloodfillParticipants(rkey, 1, _ignore, _facade.getKBuckets()); - if (!peers.isEmpty()) - return peers.get(0); + boolean isKeyCert = false; + if (!_isRouterInfo) { + LeaseSet ls = _facade.lookupLeaseSetLocally(_key); + if (ls != null && + ls.getDestination().getCertificate().getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) + isKeyCert = true; + } + if (isKeyCert) { + while (true) { + List peers = sel.selectFloodfillParticipants(rkey, 1, _ignore, _facade.getKBuckets()); + if (peers.isEmpty()) + break; + Hash peer = peers.get(0); + RouterInfo ri = _facade.lookupRouterInfoLocally(peer); + if (ri != null && StoreJob.supportsKeyCerts(ri)) + return peer; + if (_log.shouldLog(Log.INFO)) + _log.info(getJobId() + ": Skipping verify w/ router that doesn't support key certs " + peer); + _ignore.add(peer); + } + } else { + List peers = sel.selectFloodfillParticipants(rkey, 1, _ignore, _facade.getKBuckets()); + if (!peers.isEmpty()) + return peers.get(0); + } if (_log.shouldLog(Log.WARN)) _log.warn("No other peers to verify floodfill with, using the one we sent to"); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java index b38ad1489..a575a8f0c 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java @@ -112,7 +112,10 @@ class StoreJob extends JobImpl { } } + /** overridden in FSJ */ protected int getParallelization() { return PARALLELIZATION; } + + /** overridden in FSJ */ protected int getRedundancy() { return REDUNDANCY; } /** @@ -157,26 +160,29 @@ class StoreJob extends JobImpl { } } else { //_state.addPending(closestHashes); - if (_log.shouldLog(Log.INFO)) - _log.info(getJobId() + ": Continue sending key " + _state.getTarget() + " after " + _state.getAttempted().size() + " tries to " + closestHashes); + int queued = 0; + int skipped = 0; for (Hash peer : closestHashes) { DatabaseEntry ds = _facade.getDataStore().get(peer); if ( (ds == null) || !(ds.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) ) { if (_log.shouldLog(Log.INFO)) _log.info(getJobId() + ": Error selecting closest hash that wasnt a router! " + peer + " : " + ds); _state.addSkipped(peer); + skipped++; } else if (_state.getData().getType() == DatabaseEntry.KEY_TYPE_LEASESET && ((LeaseSet)_state.getData()).getDestination().getCertificate().getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY && !supportsKeyCerts((RouterInfo)ds)) { if (_log.shouldLog(Log.INFO)) - _log.info(getJobId() + ": Skipping router that doesn't support key certs " + peer + " : " + ds); + _log.info(getJobId() + ": Skipping router that doesn't support key certs " + peer); _state.addSkipped(peer); + skipped++; } else if (_state.getData().getType() == DatabaseEntry.KEY_TYPE_LEASESET && ((LeaseSet)_state.getData()).getLeaseCount() > 6 && !supportsBigLeaseSets((RouterInfo)ds)) { if (_log.shouldLog(Log.INFO)) - _log.info(getJobId() + ": Skipping router that doesn't support big leasesets " + peer + " : " + ds); + _log.info(getJobId() + ": Skipping router that doesn't support big leasesets " + peer); _state.addSkipped(peer); + skipped++; } else { int peerTimeout = _facade.getPeerTimeout(peer); @@ -206,11 +212,21 @@ class StoreJob extends JobImpl { // ERR: see hidden mode comments in HandleDatabaseLookupMessageJob // // Do not store to hidden nodes // if (!((RouterInfo)ds).isHidden()) { + if (_log.shouldLog(Log.INFO)) + _log.info(getJobId() + ": Continue sending key " + _state.getTarget() + + " after " + _state.getAttempted().size() + " tries to " + closestHashes); _state.addPending(peer); sendStore((RouterInfo)ds, peerTimeout); + queued++; //} } } + if (queued == 0 && _state.getPending().isEmpty()) { + if (_log.shouldLog(Log.INFO)) + _log.info(getJobId() + ": No more peers left after skipping " + skipped + " and none pending"); + // queue a job to go around again rather than recursing + getContext().jobQueue().addJob(new WaitJob(getContext())); + } } } @@ -507,7 +523,7 @@ class StoreJob extends JobImpl { * Does he support key certs (assumed with a non-DSA key)? * @since 0.9.12 */ - private static boolean supportsKeyCerts(RouterInfo ri) { + public static boolean supportsKeyCerts(RouterInfo ri) { String v = ri.getOption("router.version"); if (v == null) return false; @@ -520,7 +536,7 @@ class StoreJob extends JobImpl { * Does he support more than 6 leasesets? * @since 0.9.12 */ - private static boolean supportsBigLeaseSets(RouterInfo ri) { + public static boolean supportsBigLeaseSets(RouterInfo ri) { String v = ri.getOption("router.version"); if (v == null) return false;