package net.i2p.router.transport.udp; import java.util.concurrent.atomic.AtomicLong; import net.i2p.router.RouterContext; import net.i2p.util.Log; import net.i2p.util.SimpleTimer2; import static net.i2p.router.transport.TransportUtil.IPv6Config.*; import static net.i2p.router.transport.udp.PeerTestState.Role.*; /** * Initiate a test (we are Alice) * * @since 0.9.30 moved out of UDPTransport */ class PeerTestEvent extends SimpleTimer2.TimedEvent { private final RouterContext _context; private final Log _log; private final UDPTransport _transport; private final PeerTestManager _testManager; private boolean _alive; /** when did we last test our reachability */ private final AtomicLong _lastTested = new AtomicLong(); private final AtomicLong _lastTestedV6 = new AtomicLong(); private static final int NO_FORCE = 0, FORCE_IPV4 = 1, FORCE_IPV6 = 2; private int _forceRun; private static final int TEST_FREQUENCY = 13*60*1000; private static final int MIN_TEST_FREQUENCY = 45*1000; PeerTestEvent(RouterContext ctx, UDPTransport udp, PeerTestManager ptmgr) { super(ctx.simpleTimer2()); _context = ctx; _log = ctx.logManager().getLog(PeerTestEvent.class); _transport = udp; _testManager = ptmgr; } public synchronized void timeReached() { if (shouldTest()) { long now = _context.clock().now(); long sinceRunV4 = now - _lastTested.get(); long sinceRunV6 = now - _lastTestedV6.get(); boolean configV4fw = _transport.isIPv4Firewalled(); boolean configV6fw = _transport.isIPv6Firewalled(); if (!configV4fw && _forceRun == FORCE_IPV4 && sinceRunV4 >= MIN_TEST_FREQUENCY) { locked_runTest(false); } else if (!configV6fw && _transport.hasIPv6Address() &&_forceRun == FORCE_IPV6 && sinceRunV6 >= MIN_TEST_FREQUENCY) { locked_runTest(true); } else if (!configV4fw && sinceRunV4 >= TEST_FREQUENCY && _transport.getIPv6Config() != IPV6_ONLY) { locked_runTest(false); } else if (!configV6fw && _transport.hasIPv6Address() && 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 (_transport.hasIPv6Address() && _transport.getIPv6Config() != IPV6_ONLY) delay /= 2; schedule(delay); } } private void locked_runTest(boolean isIPv6) { PeerState bob = _transport.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(isIPv6); } else { if (_log.shouldLog(Log.WARN)) _log.warn("Unable to run peer test, no peers available - v6? " + isIPv6); } _forceRun = NO_FORCE; } /** * Run within the next 45 seconds at the latest * @since 0.9.13 */ public synchronized void forceRunSoon(boolean isIPv6) { if (!isIPv6 && _transport.isIPv4Firewalled()) return; if (isIPv6 && _transport.isIPv6Firewalled()) return; _forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4; reschedule(MIN_TEST_FREQUENCY); } /** * * Run within the next 5 seconds at the latest * @since 0.9.13 */ public synchronized void forceRunImmediately(boolean isIPv6) { if (!isIPv6 && _transport.isIPv4Firewalled()) return; if (isIPv6 && _transport.isIPv6Firewalled()) return; if (isIPv6) _lastTestedV6.set(0); else _lastTested.set(0); _forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4; reschedule(5*1000); } public synchronized void setIsAlive(boolean isAlive) { _alive = isAlive; if (isAlive) { long delay = _context.random().nextInt(2*TEST_FREQUENCY); reschedule(delay); } else { cancel(); } } /** * Set the last-tested timer to now * @since 0.9.13 */ public void setLastTested(boolean isIPv6) { // do not synchronize - deadlock with PeerTestManager 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()); } private boolean shouldTest() { return ! (_context.router().isHidden() || (_transport.isIPv4Firewalled() && _transport.isIPv6Firewalled())); //String val = _context.getProperty(PROP_SHOULD_TEST); //return ( (val != null) && ("true".equals(val)) ); } }