forked from I2P_Developers/i2p.i2p
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.
This commit is contained in:
@ -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
|
||||
|
@ -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 = "";
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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<String, String> changes = new HashMap<String, String>();
|
||||
@ -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<PeerState> peers = new ArrayList<PeerState>(_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<RouterAddress> 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());
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user