diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index 99a64df949764cb84a6e2a544a1b0edaee240e05..1fe43f0bfe3435a631413b087ffa36df97fa7a24 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -171,6 +171,8 @@ public class SummaryHelper extends HelperBase { //if (_context.router().getRouterInfo().getCapabilities().indexOf('O') >= 0) // return _("WARN-Firewalled and Fast"); return _("Firewalled"); + case CommSystemFacade.STATUS_DISCONNECTED: + return _("Disconnected - check network cable"); case CommSystemFacade.STATUS_HOSED: return _("ERR-UDP Port In Use - Set i2np.udp.internalPort=xxxx in advanced config and restart"); case CommSystemFacade.STATUS_UNKNOWN: // fallthrough diff --git a/router/java/src/net/i2p/router/CommSystemFacade.java b/router/java/src/net/i2p/router/CommSystemFacade.java index 9bc1ae535676072fbd91af37d3d66f87ee4e58c5..82e73c2e10db07d32b66a3db7b55c88efa5ee96c 100644 --- a/router/java/src/net/i2p/router/CommSystemFacade.java +++ b/router/java/src/net/i2p/router/CommSystemFacade.java @@ -81,6 +81,7 @@ public abstract class CommSystemFacade implements Service { * Tell other transports our address changed */ public void notifyReplaceAddress(RouterAddress UDPAddr) {} + /** * These must be increasing in "badness" (see TransportManager.java), * but UNKNOWN must be last. @@ -99,14 +100,19 @@ public abstract class CommSystemFacade implements Service { * cannot receive unsolicited connections */ public static final short STATUS_REJECT_UNSOLICITED = 2; + /** + * We have no network interface at all + * @since 0.9.4 + */ + public static final short STATUS_DISCONNECTED = 3; /** * Our detection system is broken (SSU bind port failed) */ - public static final short STATUS_HOSED = 3; + public static final short STATUS_HOSED = 4; /** * Our reachability is unknown */ - public static final short STATUS_UNKNOWN = 4; + public static final short STATUS_UNKNOWN = 5; } diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 8b2a414f1d654f624dae838912968c5f7868da4a..725ca2779b9b8223291c3f90743141631137458b 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -619,6 +619,8 @@ public class Router implements RouterClock.ClockShiftListener { case CommSystemFacade.STATUS_REJECT_UNSOLICITED: ri.addCapability(CAPABILITY_UNREACHABLE); break; + case CommSystemFacade.STATUS_DISCONNECTED: + case CommSystemFacade.STATUS_HOSED: case CommSystemFacade.STATUS_UNKNOWN: // no explicit capability break; diff --git a/router/java/src/net/i2p/router/tasks/RouterWatchdog.java b/router/java/src/net/i2p/router/tasks/RouterWatchdog.java index 233c3bd7a055f508b46380df862d9f19b2a90846..5d54b426e4d4d69de68b1d6e308bba741c97dcba 100644 --- a/router/java/src/net/i2p/router/tasks/RouterWatchdog.java +++ b/router/java/src/net/i2p/router/tasks/RouterWatchdog.java @@ -4,6 +4,7 @@ import java.io.File; import net.i2p.data.DataHelper; import net.i2p.router.Job; +import net.i2p.router.CommSystemFacade; import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.router.util.EventLog; @@ -129,11 +130,15 @@ public class RouterWatchdog implements Runnable { boolean ok = verifyJobQueueLiveliness(); // If we aren't connected to the network that's why there's nobody to talk to long netErrors = 0; - RateStat rs = _context.statManager().getRate("udp.sendException"); - if (rs != null) { - Rate r = rs.getRate(60*1000); - if (r != null) - netErrors = r.getLastEventCount(); + if (_context.commSystem().getReachabilityStatus() == CommSystemFacade.STATUS_DISCONNECTED) { + netErrors = 10; + } else { + RateStat rs = _context.statManager().getRate("udp.sendException"); + if (rs != null) { + Rate r = rs.getRate(60*1000); + if (r != null) + netErrors = r.getLastEventCount(); + } } ok = ok && (verifyClientLiveliness() || netErrors >= 5); diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java index 29f3a23d4a42dbe026f5e9bc8413552548f8f428..4457bb80a90808079de206122f8ec9489270a992 100644 --- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java +++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java @@ -31,21 +31,26 @@ import net.i2p.router.transport.ntcp.NTCPAddress; import net.i2p.router.transport.ntcp.NTCPTransport; import net.i2p.router.transport.udp.UDPAddress; import net.i2p.router.transport.udp.UDPTransport; +import net.i2p.util.Addresses; import net.i2p.util.Log; import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; +import net.i2p.util.SimpleTimer2; import net.i2p.util.Translate; public class CommSystemFacadeImpl extends CommSystemFacade { private final Log _log; private final RouterContext _context; private TransportManager _manager; - private GeoIP _geoIP; + private final GeoIP _geoIP; + private volatile boolean _netMonitorStatus; public CommSystemFacadeImpl(RouterContext context) { _context = context; _log = _context.logManager().getLog(CommSystemFacadeImpl.class); _context.statManager().createRateStat("transport.getBidsJobTime", "How long does it take?", "Transport", new long[] { 10*60*1000l }); + _netMonitorStatus = true; + _geoIP = new GeoIP(_context); startGeoIP(); } @@ -54,6 +59,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade { _manager = new TransportManager(_context); _manager.startListening(); startTimestamper(); + startNetMonitor(); } /** @@ -169,8 +175,12 @@ public class CommSystemFacadeImpl extends CommSystemFacade { @Override public short getReachabilityStatus() { if (_manager == null) return STATUS_UNKNOWN; - if (_context.router().isHidden()) return STATUS_OK; - return _manager.getReachabilityStatus(); + if (!_netMonitorStatus) + return STATUS_DISCONNECTED; + short rv = _manager.getReachabilityStatus(); + if (rv != STATUS_HOSED && _context.router().isHidden()) + return STATUS_OK; + return rv; } @Override public void recheckReachability() { _manager.recheckReachability(); } @@ -416,7 +426,6 @@ public class CommSystemFacadeImpl extends CommSystemFacade { private static final int START_DELAY = 5*60*1000; private static final int LOOKUP_TIME = 30*60*1000; private void startGeoIP() { - _geoIP = new GeoIP(_context); _context.simpleScheduler().addEvent(new QueueAll(), START_DELAY); } @@ -555,6 +564,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade { private static final int TIME_START_DELAY = 5*60*1000; private static final int TIME_REPEAT_DELAY = 10*60*1000; + /** @since 0.7.12 */ private void startTimestamper() { _context.simpleScheduler().addPeriodicEvent(new Timestamper(), TIME_START_DELAY, TIME_REPEAT_DELAY); @@ -579,4 +589,28 @@ public class CommSystemFacadeImpl extends CommSystemFacade { _context.clock().setOffset(newOffset); } } + + /** @since 0.9.4 */ + private void startNetMonitor() { + new NetMonitor(); + } + + /** + * Simple check to see if we have a network connection + * @since 0.9.4 + */ + private class NetMonitor extends SimpleTimer2.TimedEvent { + private static final long SHORT_DELAY = 15*1000; + private static final long LONG_DELAY = 3*60*1000; + + public NetMonitor() { + super(_context.simpleTimer2(), 0); + } + + public void timeReached() { + boolean good = Addresses.isConnected(); + _netMonitorStatus = good; + reschedule(good ? LONG_DELAY : SHORT_DELAY); + } + } } diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java index 6303b385c4efde96761776569dea8eb7fad55fae..2c3a5ffd72178a8efe6ac5bb214235b319e5e3a9 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java @@ -10,6 +10,7 @@ import java.util.concurrent.ConcurrentHashMap; import net.i2p.data.Hash; import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.RouterInfo; +import net.i2p.router.CommSystemFacade; import net.i2p.router.RouterContext; import net.i2p.router.TunnelManagerFacade; import net.i2p.stat.Rate; @@ -104,6 +105,8 @@ class BuildExecutor implements Runnable { } private int allowed() { + if (_context.commSystem().getReachabilityStatus() == CommSystemFacade.STATUS_DISCONNECTED) + return 0; int maxKBps = _context.bandwidthLimiter().getOutboundKBytesPerSecond(); int allowed = maxKBps / 6; // Max. 1 concurrent build per 6 KB/s outbound RateStat rs = _context.statManager().getRate("tunnel.buildRequestTime");