From 2c3311b4714beff824d1563cc622c72593bb3ad3 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 25 Jun 2016 21:25:12 +0000 Subject: [PATCH] SSU: Add support for IPv6 SSU Peer Testing (ticket #1752; proposal #126) In PeerTestManager, this is simply the removal of v6 restrictions, and the tracking of whether we are testing v4 or v6. In UDPTransport, track v4 and v6 peer tests separately. --- history.txt | 3 + .../src/net/i2p/router/RouterVersion.java | 2 +- .../router/transport/udp/PeerTestManager.java | 78 +++++---- .../router/transport/udp/PeerTestState.java | 10 +- .../router/transport/udp/UDPTransport.java | 153 +++++++++++++----- 5 files changed, 170 insertions(+), 76 deletions(-) diff --git a/history.txt b/history.txt index 0986643340..ddb6e8d05d 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,6 @@ +2016-06-26 zzz + * SSU peer testing: Add implementation (ticket #1752; proposal #126) + 2016-06-22 zzz * SSU peer testing: - Forget the test and don't keep retransmitting to Charlie diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 282c18b422..0725033fa6 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/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java index fb20e5f597..fd6f04ceeb 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java @@ -1,6 +1,7 @@ package net.i2p.router.transport.udp; import java.net.InetAddress; +import java.net.Inet6Address; import java.net.UnknownHostException; import java.util.Map; import java.util.Queue; @@ -187,7 +188,7 @@ class PeerTestManager { _log.warn("Not running test with Bob too close to us " + bobIP); return; } - PeerTestState test = new PeerTestState(ALICE, + PeerTestState test = new PeerTestState(ALICE, bobIP instanceof Inet6Address, _context.random().nextLong(MAX_NONCE), _context.clock().now()); test.setBobIP(bobIP); @@ -315,7 +316,9 @@ class PeerTestManager { // The reply is from Bob int ipSize = testInfo.readIPSize(); - if (ipSize != 4) { + boolean expectV6 = test.isIPv6(); + if ((!expectV6 && ipSize != 4) || + (expectV6 && ipSize != 16)) { // There appears to be a bug where Bob is sending us a zero-length IP. // We could proceed without setting the IP, but then when Charlie // sends us his message, we will think we are behind a symmetric NAT @@ -364,7 +367,7 @@ class PeerTestManager { // why are we doing this instead of calling testComplete() ? _currentTestComplete = true; _context.statManager().addRateData("udp.statusKnownCharlie", 1); - honorStatus(Status.UNKNOWN); + honorStatus(Status.UNKNOWN, test.isIPv6()); _currentTest = null; return; } @@ -377,8 +380,11 @@ class PeerTestManager { throw new UnknownHostException("port 0"); test.setAlicePortFromCharlie(testPort); byte ip[] = new byte[testInfo.readIPSize()]; - if (ip.length != 4) - throw new UnknownHostException("not IPv4"); + int ipSize = ip.length; + boolean expectV6 = test.isIPv6(); + if ((!expectV6 && ipSize != 4) || + (expectV6 && ipSize != 16)) + throw new UnknownHostException("bad sz - expect v6? " + expectV6 + " act sz: " + ipSize); testInfo.readIP(ip, 0); InetAddress addr = InetAddress.getByAddress(ip); test.setAliceIPFromCharlie(addr); @@ -442,22 +448,24 @@ class PeerTestManager { // return; // } + boolean isIPv6 = test.isIPv6(); Status status; if (test.getAlicePortFromCharlie() > 0) { // we received a second message from charlie if ( (test.getAlicePort() == test.getAlicePortFromCharlie()) && (test.getAliceIP() != null) && (test.getAliceIPFromCharlie() != null) && (test.getAliceIP().equals(test.getAliceIPFromCharlie())) ) { - status = Status.IPV4_OK_IPV6_UNKNOWN; + status = isIPv6 ? Status.IPV4_UNKNOWN_IPV6_OK : Status.IPV4_OK_IPV6_UNKNOWN; } else { - status = Status.IPV4_SNAT_IPV6_UNKNOWN; + // we don't have a SNAT state for IPv6 + status = isIPv6 ? Status.IPV4_UNKNOWN_IPV6_FIREWALLED : Status.IPV4_SNAT_IPV6_UNKNOWN; } } else if (test.getReceiveCharlieTime() > 0) { // we received only one message from charlie status = Status.UNKNOWN; } else if (test.getReceiveBobTime() > 0) { // we received a message from bob but no messages from charlie - status = Status.IPV4_FIREWALLED_IPV6_UNKNOWN; + status = isIPv6 ? Status.IPV4_UNKNOWN_IPV6_FIREWALLED : Status.IPV4_FIREWALLED_IPV6_UNKNOWN; } else { // we never received anything from bob - he is either down, // ignoring us, or unable to get a Charlie to respond @@ -467,7 +475,7 @@ class PeerTestManager { if (_log.shouldLog(Log.INFO)) _log.info("Test complete: " + test); - honorStatus(status); + honorStatus(status, isIPv6); if (forgetTest) _currentTest = null; } @@ -476,11 +484,12 @@ class PeerTestManager { * Depending upon the status, fire off different events (using received port/ip/etc as * necessary). * + * @param isIPv6 Is the change an IPv6 change? */ - private void honorStatus(Status status) { + private void honorStatus(Status status, boolean isIPv6) { if (_log.shouldLog(Log.INFO)) - _log.info("Test results: status = " + status); - _transport.setReachabilityStatus(status); + _log.info("Test results (IPv6? " + isIPv6 + "): status = " + status); + _transport.setReachabilityStatus(status, isIPv6); } /** @@ -518,7 +527,7 @@ class PeerTestManager { if ((testPort > 0 && (!TransportUtil.isValidPort(testPort))) || (testIP != null && ((!_transport.isValid(testIP)) || - testIP.length != 4 || + (testIP.length != 4 && testIP.length != 16) || _context.blocklist().isBlocklisted(testIP)))) { // spoof check, and don't respond to privileged ports if (_log.shouldLog(Log.WARN)) @@ -645,10 +654,11 @@ class PeerTestManager { */ private void receiveFromBobAsCharlie(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, long nonce, PeerTestState state) { long now = _context.clock().now(); + int sz = testInfo.readIPSize(); boolean isNew = false; if (state == null) { isNew = true; - state = new PeerTestState(CHARLIE, nonce, now); + state = new PeerTestState(CHARLIE, sz == 16, nonce, now); } else { if (state.getReceiveBobTime() > now - (RESEND_TIMEOUT / 2)) { if (_log.shouldLog(Log.WARN)) @@ -658,12 +668,13 @@ class PeerTestManager { } // TODO should only do most of this if isNew - int sz = testInfo.readIPSize(); byte aliceIPData[] = new byte[sz]; try { testInfo.readIP(aliceIPData, 0); - if (sz != 4) - throw new UnknownHostException("not IPv4"); + boolean expectV6 = state.isIPv6(); + if ((!expectV6 && sz != 4) || + (expectV6 && sz != 16)) + throw new UnknownHostException("bad sz - expect v6? " + expectV6 + " act sz: " + sz); int alicePort = testInfo.readPort(); if (alicePort == 0) throw new UnknownHostException("port 0"); @@ -731,22 +742,27 @@ class PeerTestManager { // we are Bob, so pick a (potentially) Charlie and send Charlie Alice's info PeerState charlie; RouterInfo charlieInfo = null; + int sz = from.getIP().length; + boolean isIPv6 = sz == 16; if (state == null) { // pick a new charlie - if (from.getIP().length != 4) { - if (_log.shouldLog(Log.WARN)) - _log.warn("PeerTest over IPv6 from Alice as Bob? " + from); - return; - } - charlie = _transport.pickTestPeer(CHARLIE, from); + //if (from.getIP().length != 4) { + // if (_log.shouldLog(Log.WARN)) + // _log.warn("PeerTest over IPv6 from Alice as Bob? " + from); + // return; + //} + charlie = _transport.pickTestPeer(CHARLIE, isIPv6, from); } else { charlie = _transport.getPeerState(new RemoteHostId(state.getCharlieIP().getAddress(), state.getCharliePort())); } - if (charlie != null) - charlieInfo = _context.netDb().lookupRouterInfoLocally(charlie.getRemotePeer()); - - if ( (charlie == null) || (charlieInfo == null) ) { + if (charlie == null) { if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to pick a charlie"); + _log.warn("Unable to pick a charlie (no peer), IPv6? " + isIPv6); + return; + } + charlieInfo = _context.netDb().lookupRouterInfoLocally(charlie.getRemotePeer()); + if (charlieInfo == null) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Unable to pick a charlie (no RI), IPv6? " + isIPv6); return; } @@ -761,14 +777,14 @@ class PeerTestManager { RouterAddress raddr = _transport.getTargetAddress(charlieInfo); if (raddr == null) { if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to pick a charlie"); + _log.warn("Unable to pick a charlie (no addr), IPv6? " + isIPv6); return; } UDPAddress addr = new UDPAddress(raddr); byte[] ikey = addr.getIntroKey(); if (ikey == null) { if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to pick a charlie"); + _log.warn("Unable to pick a charlie (no ikey), IPv6? " + isIPv6); return; } SessionKey charlieIntroKey = new SessionKey(ikey); @@ -780,7 +796,7 @@ class PeerTestManager { boolean isNew = false; if (state == null) { isNew = true; - state = new PeerTestState(BOB, nonce, now); + state = new PeerTestState(BOB, isIPv6, nonce, now); } else { if (state.getReceiveAliceTime() > now - (RESEND_TIMEOUT / 2)) { if (_log.shouldLog(Log.WARN)) diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestState.java b/router/java/src/net/i2p/router/transport/udp/PeerTestState.java index e700c77eba..c02734e7ea 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerTestState.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerTestState.java @@ -12,6 +12,7 @@ import net.i2p.data.SessionKey; class PeerTestState { private final long _testNonce; private final Role _ourRole; + private final boolean _isIPv6; private InetAddress _aliceIP; private int _alicePort; private InetAddress _bobIP; @@ -33,8 +34,9 @@ class PeerTestState { public enum Role {ALICE, BOB, CHARLIE}; - public PeerTestState(Role role, long nonce, long now) { + public PeerTestState(Role role, boolean isIPv6, long nonce, long now) { _ourRole = role; + _isIPv6 = isIPv6; _testNonce = nonce; _beginTime = now; } @@ -44,6 +46,12 @@ class PeerTestState { /** Are we Alice, bob, or Charlie. */ public Role getOurRole() { return _ourRole; } + /** + * Is this an IPv6 test? + * @since 0.9.27 + */ + public boolean isIPv6() { return _isIPv6; } + /** * If we are Alice, this will contain the IP that Bob says we * can be reached at - the IP Charlie says we can be reached diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 311c3459d8..86278d91dc 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -95,7 +95,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority * Do we have a public IPv6 address? * TODO periodically update via CSFI.NetMonitor? */ - private boolean _haveIPv6Address; + private volatile boolean _haveIPv6Address; private long _lastInboundIPv6; /** do we need to rebuild our external router address asap? */ @@ -219,6 +219,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority */ private static final String MIN_SIGTYPE_VERSION = "0.9.17"; + /** + * IPv6 Peer Testing supported + */ +///////////////////////////////////// Testing only, set to 0.9.27 before release //////////////////////////////////////// + private static final String MIN_V6_PEER_TEST_VERSION = "0.9.26"; + public UDPTransport(RouterContext ctx, DHSessionKeyBuilder.Factory dh) { super(ctx); @@ -535,7 +541,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // change to firewalled maybe? but we don't have any test to restore // a v6 address after it's removed. _lastInboundIPv6 = _context.clock().now(); - setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK); + if (!isIPv6Firewalled()) + setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true); } else { if (!isIPv4Firewalled()) setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); @@ -546,7 +553,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority for (InetAddress ia : bindToAddrs) { if (ia.getAddress().length == 16) { _lastInboundIPv6 = _context.clock().now(); - setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK); + if (!isIPv6Firewalled()) + setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true); } else { if (!isIPv4Firewalled()) setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); @@ -763,12 +771,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority void inboundConnectionReceived(boolean isIPv6) { if (isIPv6) { - // FIXME we need to check and time out after an hour of no inbound ipv6, - // change to firewalled maybe? but we don't have any test to restore - // a v6 address after it's removed. _lastInboundIPv6 = _context.clock().now(); - if (_currentOurV6Address != null) - setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK); + // former workaround for lack of IPv6 peer testing + //if (_currentOurV6Address != null) + // setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true); } else { // Introduced connections are still inbound, this is not evidence // that we are not firewalled. @@ -845,7 +851,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } else if (ip.length == 16) { // TODO should we set both to unknown and wait for an inbound v6 conn, // since there's no v6 testing? - setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK); + if (!isIPv6Firewalled()) + setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true); } } } @@ -1007,8 +1014,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } if (fireTest) { + // always false, commented out above _context.statManager().addRateData("udp.addressTestInsteadOfUpdate", 1); - _testEvent.forceRunImmediately(); + _testEvent.forceRunImmediately(isIPv6); } else if (updated) { _context.statManager().addRateData("udp.addressUpdated", 1); Map changes = new HashMap(); @@ -1061,7 +1069,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } // deadlock thru here ticket #1699 _context.router().rebuildRouterInfo(); - _testEvent.forceRunImmediately(); + _testEvent.forceRunImmediately(isIPv6); } return updated; } @@ -1329,7 +1337,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority status != Status.IPV4_DISABLED_IPV6_FIREWALLED && status != Status.DISCONNECTED && _reachabilityStatusUnchanged < 7) { - _testEvent.forceRunSoon(); + // IPv4 only for now + _testEvent.forceRunSoon(false); } } return true; @@ -3076,17 +3085,31 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } } - void setReachabilityStatus(Status status) { + /** + * IPv4 only + */ + private void setReachabilityStatus(Status status) { + setReachabilityStatus(status, false); + } + + /** + * @since 0.9.27 + * @param isIPv6 Is the change an IPv6 change? + */ + void setReachabilityStatus(Status status, boolean isIPv6) { synchronized (_rebuildLock) { - locked_setReachabilityStatus(status); + locked_setReachabilityStatus(status, isIPv6); } } - private void locked_setReachabilityStatus(Status newStatus) { + /** + * @param isIPv6 Is the change an IPv6 change? + */ + private void locked_setReachabilityStatus(Status newStatus, boolean isIPv6) { Status old = _reachabilityStatus; // merge new status into old Status status = Status.merge(old, newStatus); - _testEvent.setLastTested(); + _testEvent.setLastTested(isIPv6); // now modify if we are IPv6 only TransportUtil.IPv6Config config = getIPv6Config(); if (config == IPV6_ONLY) { @@ -3099,7 +3122,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } if (status != Status.UNKNOWN) { // now modify if we have no IPv6 address - if (_currentOurV6Address == null) { + if (_currentOurV6Address == null && !_haveIPv6Address) { if (status == Status.IPV4_OK_IPV6_UNKNOWN) status = Status.OK; else if (status == Status.IPV4_FIREWALLED_IPV6_UNKNOWN) @@ -3175,19 +3198,21 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority /** * Pick a Bob (if we are Alice) or a Charlie (if we are Bob). * - * For Bob (as called from PeerTestEvent below), returns an established IPv4 peer. + * For Bob (as called from PeerTestEvent below), returns an established IPv4/v6 peer. * While the protocol allows Alice to select an unestablished Bob, we don't support that. * * For Charlie (as called from PeerTestManager), returns an established IPv4 or IPv6 peer. * (doesn't matter how Bob and Charlie communicate) * * Any returned peer must advertise an IPv4 address to prove it is IPv4-capable. + * Ditto for v6. * - * @param peerRole BOB or CHARLIE only + * @param peerRole The role of the peer we are looking for, BOB or CHARLIE only (NOT our role) + * @param isIPv6 true to get a v6-capable peer back * @param dontInclude may be null * @return IPv4 peer or null */ - PeerState pickTestPeer(PeerTestState.Role peerRole, RemoteHostId dontInclude) { + PeerState pickTestPeer(PeerTestState.Role peerRole, boolean isIPv6, RemoteHostId dontInclude) { if (peerRole == ALICE) throw new IllegalArgumentException(); List peers = new ArrayList(_peersByIdent.values()); @@ -3195,20 +3220,31 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority PeerState peer = iter.next(); if ( (dontInclude != null) && (dontInclude.equals(peer.getRemoteHostId())) ) continue; - // enforce IPv4 connection if we are ALICE looking for a BOB + // enforce IPv4/v6 connection if we are ALICE looking for a BOB byte[] ip = peer.getRemoteIP(); - if (peerRole == BOB && ip.length != 4) + if (peerRole == BOB) { + if ((!isIPv6 && ip.length != 4) || + (isIPv6 && ip.length != 16)) continue; - // enforce IPv4 advertised for all + } + // enforce IPv4/v6 advertised for all RouterInfo peerInfo = _context.netDb().lookupRouterInfoLocally(peer.getRemotePeer()); if (peerInfo == null) continue; + if (isIPv6) { + String v = peerInfo.getVersion(); + if (VersionComparator.comp(v, MIN_SIGTYPE_VERSION) < 0) + continue; + } ip = null; List addrs = getTargetAddresses(peerInfo); for (RouterAddress addr : addrs) { ip = addr.getIP(); - if (ip != null && ip.length == 4) + if (ip != null) { + if ((!isIPv6 && ip.length != 4) || + (isIPv6 && ip.length != 16)) break; + } } if (ip == null) continue; @@ -3221,7 +3257,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private boolean shouldTest() { return ! (_context.router().isHidden() || - isIPv4Firewalled()); + (isIPv4Firewalled() && isIPv6Firewalled())); //String val = _context.getProperty(PROP_SHOULD_TEST); //return ( (val != null) && ("true".equals(val)) ); } @@ -3233,47 +3269,67 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private boolean _alive; /** when did we last test our reachability */ private final AtomicLong _lastTested = new AtomicLong(); - private boolean _forceRun; + private final AtomicLong _lastTestedV6 = new AtomicLong(); + private static final int NO_FORCE = 0, FORCE_IPV4 = 1, FORCE_IPV6 = 2; + private int _forceRun; PeerTestEvent() { super(_context.simpleTimer2()); } public synchronized void timeReached() { + // just for IPv6 for now if (shouldTest()) { - long sinceRun = _context.clock().now() - _lastTested.get(); - if ( (_forceRun && sinceRun >= MIN_TEST_FREQUENCY) || (sinceRun >= TEST_FREQUENCY) ) { - locked_runTest(); + long now = _context.clock().now(); + long sinceRunV4 = now - _lastTested.get(); + long sinceRunV6 = now - _lastTestedV6.get(); + if (_forceRun == FORCE_IPV4 && sinceRunV4 >= MIN_TEST_FREQUENCY) { + locked_runTest(false); + } else if (_haveIPv6Address &&_forceRun == FORCE_IPV6 && sinceRunV6 >= MIN_TEST_FREQUENCY) { + locked_runTest(true); + } else if (sinceRunV4 >= TEST_FREQUENCY) { + locked_runTest(false); + } else if (_haveIPv6Address && sinceRunV6 >= TEST_FREQUENCY) { + locked_runTest(true); + } else { + if (_log.shouldLog(Log.INFO)) + _log.info("PTE timeReached(), no test run, last v4 test: " + new java.util.Date(_lastTested.get()) + + " last v6 test: " + new java.util.Date(_lastTestedV6.get())); } } if (_alive) { long delay = (TEST_FREQUENCY / 2) + _context.random().nextInt(TEST_FREQUENCY); + // if we have 2 addresses, give IPv6 a chance also + if (_haveIPv6Address) + delay /= 2; schedule(delay); } } - private void locked_runTest() { - PeerState bob = pickTestPeer(BOB, null); + private void locked_runTest(boolean isIPv6) { + PeerState bob = pickTestPeer(BOB, isIPv6, null); if (bob != null) { if (_log.shouldLog(Log.INFO)) _log.info("Running periodic test with bob = " + bob); _testManager.runTest(bob.getRemoteIPAddress(), bob.getRemotePort(), bob.getCurrentCipherKey(), bob.getCurrentMACKey()); - setLastTested(); + setLastTested(isIPv6); } else { if (_log.shouldLog(Log.WARN)) - _log.warn("Unable to run a periodic test, as there are no peers with the capacity required"); + _log.warn("Unable to run peer test, no peers available - v6? " + isIPv6); } - _forceRun = false; + _forceRun = NO_FORCE; } /** * Run within the next 45 seconds at the latest * @since 0.9.13 */ - public synchronized void forceRunSoon() { - if (isIPv4Firewalled()) + public synchronized void forceRunSoon(boolean isIPv6) { + if (!isIPv6 && isIPv4Firewalled()) return; - _forceRun = true; + if (isIPv6 && isIPv6Firewalled()) + return; + _forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4; reschedule(MIN_TEST_FREQUENCY); } @@ -3282,11 +3338,16 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority * Run within the next 5 seconds at the latest * @since 0.9.13 */ - public synchronized void forceRunImmediately() { - if (isIPv4Firewalled()) + public synchronized void forceRunImmediately(boolean isIPv6) { + if (!isIPv6 && isIPv4Firewalled()) return; - _lastTested.set(0); - _forceRun = true; + if (isIPv6 && isIPv6Firewalled()) + return; + if (isIPv6) + _lastTestedV6.set(0); + else + _lastTested.set(0); + _forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4; reschedule(5*1000); } @@ -3304,9 +3365,15 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority * Set the last-tested timer to now * @since 0.9.13 */ - public void setLastTested() { + public void setLastTested(boolean isIPv6) { // do not synchronize - deadlock with PeerTestManager - _lastTested.set(_context.clock().now()); + long now = _context.clock().now(); + if (isIPv6) + _lastTestedV6.set(now); + else + _lastTested.set(now); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("PTE.setLastTested() - v6? " + isIPv6, new Exception()); } }