diff --git a/install-headless.txt b/INSTALL-headless.txt similarity index 87% rename from install-headless.txt rename to INSTALL-headless.txt index 6def73d54fcd4ebe8651641b96ecdca4c4177b8d..03229c7964bd2ef66e7f161b96e343b8dcc9a4f7 100644 --- a/install-headless.txt +++ b/INSTALL-headless.txt @@ -1,8 +1,7 @@ -$Id: install-headless.txt,v 1.5 2005/09/29 14:19:23 jrandom Exp $ Headless I2P installation instructions 1) tar xjf i2p.tar.bz2 (you've already done this) -2) cd i2p ; vi install-headless.txt (you're doing this now) +2) cd i2p ; vi INSTALL-headless.txt (you're doing this now) 3) sh postinstall.sh (this launches the router) 4) lynx http://localhost:7657/index.jsp (configure the router) diff --git a/install.txt b/INSTALL.txt similarity index 100% rename from install.txt rename to INSTALL.txt diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index 8e76273098154ca34df4fd706588654cc23c5847..486bcdead5cb7098ac9725c607f5b9fd70e16b81 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -75,7 +75,7 @@ public class I2PTunnel implements Logging, EventDispatcher { private static long __tunnelId = 0; private long _tunnelId; private Properties _clientOptions; - private final List _sessions; + private final List<I2PSession> _sessions; public static final int PACKET_DELAY = 100; @@ -179,7 +179,7 @@ public class I2PTunnel implements Logging, EventDispatcher { } } - List getSessions() { + List<I2PSession> getSessions() { synchronized (_sessions) { return new ArrayList(_sessions); } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java index 3c571857afc506de94539133b3387243553ff729..190a4a96d6ee58b909419477a91448c4315c2f79 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java @@ -44,6 +44,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna protected final Object sockLock = new Object(); // Guards sockMgr and mySockets protected I2PSocketManager sockMgr; // should be final and use a factory. LINT protected List mySockets = new ArrayList(); + protected boolean _ownDest; protected Destination dest = null; private int localPort; @@ -114,6 +115,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna this.l = l; this.handlerName = handlerName + _clientId; this.privKeyFile = pkf; + _ownDest = ownDest; // == ! shared client _context = tunnel.getContext(); @@ -129,13 +131,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna boolean openNow = !Boolean.valueOf(tunnel.getClientOptions().getProperty("i2cp.delayOpen")).booleanValue(); if (openNow) { while (sockMgr == null) { - synchronized (sockLock) { - if (ownDest) { - sockMgr = buildSocketManager(); - } else { - sockMgr = getSocketManager(); - } - } + verifySocketManager(); if (sockMgr == null) { _log.log(Log.CRIT, "Unable to create socket manager (our own? " + ownDest + ")"); try { Thread.sleep(10*1000); } catch (InterruptedException ie) {} @@ -209,27 +205,67 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } } + /** + * Sets the this.sockMgr field if it is null, or if we want a new one + * + * We need a socket manager before getDefaultOptions() and most other things + */ + protected void verifySocketManager() { + synchronized(sockLock) { + boolean newManager = false; + if (this.sockMgr == null) { + newManager = true; + } else { + I2PSession sess = sockMgr.getSession(); + if (sess == null) { + newManager = true; + } else if (sess.isClosed() && + Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.closeOnIdle")).booleanValue() && + Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.newDestOnResume")).booleanValue()) { + // build a new socket manager and a new dest if the session is closed. + getTunnel().removeSession(sess); + if (_log.shouldLog(Log.WARN)) + _log.warn(getTunnel().getClientOptions().getProperty("inbound.nickname") + ": Built a new destination on resume"); + newManager = true; + } // else the old socket manager will reconnect the old session if necessary + } + if (newManager) { + if (_ownDest) + this.sockMgr = buildSocketManager(); + else + this.sockMgr = getSocketManager(); + } + } + } + + /** this is ONLY for shared clients */ private static I2PSocketManager socketManager; + /** this is ONLY for shared clients */ protected synchronized I2PSocketManager getSocketManager() { return getSocketManager(getTunnel(), this.privKeyFile); } + /** this is ONLY for shared clients */ protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel) { return getSocketManager(tunnel, null); } + /** this is ONLY for shared clients */ protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) { if (socketManager != null) { I2PSession s = socketManager.getSession(); if ( (s == null) || (s.isClosed()) ) { - _log.info("Building a new socket manager since the old one closed [s=" + s + "]"); + if (_log.shouldLog(Log.INFO)) + _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Building a new socket manager since the old one closed [s=" + s + "]"); if (s != null) tunnel.removeSession(s); socketManager = buildSocketManager(tunnel, pkf); } else { - _log.info("Not building a new socket manager since the old one is open [s=" + s + "]"); + if (_log.shouldLog(Log.INFO)) + _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Not building a new socket manager since the old one is open [s=" + s + "]"); } } else { - _log.info("Building a new socket manager since there is no other one"); + if (_log.shouldLog(Log.INFO)) + _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Building a new socket manager since there is no other one"); socketManager = buildSocketManager(tunnel, pkf); } return socketManager; @@ -278,6 +314,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } } sockManager.setName("Client"); + if (_log.shouldLog(Log.INFO)) + _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Built a new socket manager [s=" + sockManager.getSession() + "]"); tunnel.addSession(sockManager.getSession()); return sockManager; } @@ -343,12 +381,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna * @return a new I2PSocket */ public I2PSocket createI2PSocket(Destination dest) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException { - if (sockMgr == null) { - // we need this before getDefaultOptions() - synchronized(sockLock) { - sockMgr = getSocketManager(); - } - } + verifySocketManager(); return createI2PSocket(dest, getDefaultOptions()); } @@ -369,22 +402,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna public I2PSocket createI2PSocket(Destination dest, I2PSocketOptions opt) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException { I2PSocket i2ps; - if (sockMgr == null) { - // delayed open - call get instead of build because the locking is up there - synchronized(sockLock) { - sockMgr = getSocketManager(); - } - } else if (Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.closeOnIdle")).booleanValue() && - Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.newDestOnResume")).booleanValue()) { - synchronized(sockLock) { - I2PSocketManager oldSockMgr = sockMgr; - // This will build a new socket manager and a new dest if the session is closed. - sockMgr = getSocketManager(); - if (oldSockMgr != sockMgr) { - _log.warn("Built a new destination on resume"); - } - } - } // else the old socket manager will reconnect the old session if necessary + verifySocketManager(); i2ps = sockMgr.connect(dest, opt); synchronized (sockLock) { mySockets.add(i2ps); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java index 13906807eb3d7f32068f8390c78e3fb7b9eafc8c..59971e8f3d7b1d429928ed52a29ecc982bb12ba7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java @@ -157,11 +157,7 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna if (!defaultOpts.contains("i2p.streaming.inactivityTimeout")) defaultOpts.setProperty("i2p.streaming.inactivityTimeout", ""+DEFAULT_READ_TIMEOUT); // delayed start - if (sockMgr == null) { - synchronized(sockLock) { - sockMgr = getSocketManager(); - } - } + verifySocketManager(); I2PSocketOptions opts = sockMgr.buildOptions(defaultOpts); if (!defaultOpts.containsKey(I2PSocketOptions.PROP_CONNECT_TIMEOUT)) opts.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 316731deec7f44c57ba141d7a19c718effd467a9..7e16114adccbaa7b6e0bb4de15533c86b70beea7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -211,11 +211,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable if (!defaultOpts.contains("i2p.streaming.inactivityTimeout")) defaultOpts.setProperty("i2p.streaming.inactivityTimeout", ""+DEFAULT_READ_TIMEOUT); // delayed start - if (sockMgr == null) { - synchronized(sockLock) { - sockMgr = getSocketManager(); - } - } + verifySocketManager(); I2PSocketOptions opts = sockMgr.buildOptions(defaultOpts); if (!defaultOpts.containsKey(I2PSocketOptions.PROP_CONNECT_TIMEOUT)) opts.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index 419e5a899d9e262353177e6c6bd57d5020dc16c0..1f67783e9b6578db5d1d803639be99d04834f652 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -434,6 +434,16 @@ public class TunnelController implements Logging { public boolean getIsRunning() { return _running; } public boolean getIsStarting() { return _starting; } + /** if running but no open sessions, we are in standby */ + public boolean getIsStandby() { + if (!_running) + return false; + for (I2PSession sess : _tunnel.getSessions()) { + if (!sess.isClosed()) + return false; + } + return true; + } public void getSummary(StringBuffer buf) { String type = getType(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java index 24bbb9119a4237c0cb546382465bc657a454ad60..4c23ced34741bf662e0a9294f9f8ebf2ee30f0af 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -77,6 +77,7 @@ public class IndexBean { public static final int RUNNING = 1; public static final int STARTING = 2; public static final int NOT_RUNNING = 3; + public static final int STANDBY = 4; public static final String PROP_TUNNEL_PASSPHRASE = "i2ptunnel.passphrase"; static final String PROP_NONCE = IndexBean.class.getName() + ".nonce"; @@ -412,8 +413,12 @@ public class IndexBean { public int getTunnelStatus(int tunnel) { TunnelController tun = getController(tunnel); if (tun == null) return NOT_RUNNING; - if (tun.getIsRunning()) return RUNNING; - else if (tun.getIsStarting()) return STARTING; + if (tun.getIsRunning()) { + if (isClient(tunnel) && tun.getIsStandby()) + return STANDBY; + else + return RUNNING; + } else if (tun.getIsStarting()) return STARTING; else return NOT_RUNNING; } @@ -778,12 +783,6 @@ public class IndexBean { config.setProperty("interface", _reachableByOther); else config.setProperty("interface", _reachableBy); - config.setProperty("option.inbound.nickname", CLIENT_NICKNAME); - config.setProperty("option.outbound.nickname", CLIENT_NICKNAME); - if (_name != null && !_sharedClient) { - config.setProperty("option.inbound.nickname", _name); - config.setProperty("option.outbound.nickname", _name); - } config.setProperty("sharedClient", _sharedClient + ""); for (String p : _booleanClientOpts) config.setProperty("option." + p, "" + _booleanOptions.contains(p)); @@ -896,14 +895,12 @@ public class IndexBean { config.setProperty("option.i2p.streaming.connectDelay", "1000"); else config.setProperty("option.i2p.streaming.connectDelay", "0"); - if (_name != null) { - if ( (!isClient(_type)) || (!_sharedClient) ) { - config.setProperty("option.inbound.nickname", _name); - config.setProperty("option.outbound.nickname", _name); - } else { - config.setProperty("option.inbound.nickname", CLIENT_NICKNAME); - config.setProperty("option.outbound.nickname", CLIENT_NICKNAME); - } + if (isClient(_type) && _sharedClient) { + config.setProperty("option.inbound.nickname", CLIENT_NICKNAME); + config.setProperty("option.outbound.nickname", CLIENT_NICKNAME); + } else if (_name != null) { + config.setProperty("option.inbound.nickname", _name); + config.setProperty("option.outbound.nickname", _name); } if ("interactive".equals(_profile)) // This was 1 which doesn't make much sense diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp index 4d9f6c57d9eac57838f96fe76ccd61503c87f672..6c89d5ff426f1a073720db13c37f6d78216e30b4 100644 --- a/apps/i2ptunnel/jsp/index.jsp +++ b/apps/i2ptunnel/jsp/index.jsp @@ -97,6 +97,11 @@ case IndexBean.STARTING: %><div class="statusStarting text">Starting...</div> <a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>">Stop</a> + <% + break; + case IndexBean.STANDBY: + %><div class="statusStarting text">Standby</div> + <a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>">Stop</a> <% break; case IndexBean.RUNNING: diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java index 066cb11443c0b3d9e9bc8e22743b332e05bff58c..e701ede9954e8925d1f2018014988859e3ad0fcc 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java @@ -91,8 +91,9 @@ public class ReseedHandler { public boolean isRunning() { return _isRunning; } public void run() { _isRunning = true; + System.out.println("Reseed start"); reseed(false); - System.out.println("Reseeding complete"); + System.out.println("Reseed complete"); System.setProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "false"); _isRunning = false; } @@ -133,7 +134,7 @@ public class ReseedHandler { } /** - * Fetch a directory listing and then all the routerInfo files in the listing. + * Fetch a directory listing and then up to 200 routerInfo files in the listing. * The listing must contain (exactly) strings that match: * href="routerInfo-{hash}.dat"> * and then it fetches the files @@ -147,6 +148,7 @@ public class ReseedHandler { try { System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",""); System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage","Reseeding: fetching seed URL."); + System.err.println("Reseed from " + seedURL); URL dir = new URL(seedURL); byte contentRaw[] = readURL(dir); if (contentRaw == null) { @@ -160,7 +162,8 @@ public class ReseedHandler { String content = new String(contentRaw); Set urls = new HashSet(); int cur = 0; - while (true) { + int total = 0; + while (total++ < 1000) { int start = content.indexOf("href=\"routerInfo-", cur); if (start < 0) break; @@ -170,7 +173,7 @@ public class ReseedHandler { urls.add(name); cur = end + 1; } - if (urls.size() <= 0) { + if (total <= 0) { _log.error("Read " + contentRaw.length + " bytes from seed " + seedURL + ", but found no routerInfo URLs."); System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage", "Last reseed failed fully (no routerInfo URLs at seed URL). " + @@ -178,13 +181,16 @@ public class ReseedHandler { return; } + List urlList = new ArrayList(urls); + Collections.shuffle(urlList); int fetched = 0; int errors = 0; - for (Iterator iter = urls.iterator(); iter.hasNext(); ) { + // 200 max from one URL + for (Iterator iter = urlList.iterator(); iter.hasNext() && fetched < 200; ) { try { System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage", "Reseeding: fetching router info from seed URL (" + - fetched + " successful, " + errors + " errors, " + urls.size() + " total)."); + fetched + " successful, " + errors + " errors, " + total + " total)."); fetchSeed(seedURL, (String)iter.next()); fetched++; @@ -197,24 +203,24 @@ public class ReseedHandler { errors++; } } - if (echoStatus) System.out.println(); + System.err.println("Reseed got " + fetched + " router infos from " + seedURL); - int failPercent = 100 * errors / urls.size(); + int failPercent = 100 * errors / total; // Less than 10% of failures is considered success, // because some routerInfos will always fail. if ((failPercent >= 10) && (failPercent < 90)) { System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage", - "Last reseed failed partly (" + failPercent + "% of " + urls.size() + "). " + + "Last reseed failed partly (" + failPercent + "% of " + total + "). " + RESEED_TIPS); } if (failPercent >= 90) { System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage", - "Last reseed failed (" + failPercent + "% of " + urls.size() + "). " + + "Last reseed failed (" + failPercent + "% of " + total + "). " + RESEED_TIPS); } // Don't go on to the next URL if we have enough - if (fetched > 25) + if (fetched >= 100) _isRunning = false; } catch (Throwable t) { System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage", diff --git a/apps/routerconsole/jsp/configservice.jsp b/apps/routerconsole/jsp/configservice.jsp index 5d9de218abfc1eab7f820d29992abc87e5890e55..a69c112dbc11ca7d90310976567102d811b2bbe1 100644 --- a/apps/routerconsole/jsp/configservice.jsp +++ b/apps/routerconsole/jsp/configservice.jsp @@ -32,6 +32,7 @@ <input type="submit" name="action" value="Shutdown immediately" /> <input type="submit" name="action" value="Cancel graceful shutdown" /> + <% if (System.getProperty("wrapper.version") != null) { %> <p>If you want the router to restart itself after shutting down, you can choose one of the following. This is useful in some situations - for example, if you changed some settings that client applications only read at startup, such as the routerconsole password @@ -41,6 +42,7 @@ <input type="submit" name="action" value="Graceful restart" /> <input type="submit" name="action" value="Hard restart" /> + <% } %> <% if ( (System.getProperty("os.name") != null) && (System.getProperty("os.name").startsWith("Win")) ) { %> <h4>Systray integration</h4> @@ -61,11 +63,14 @@ down your router immediately. You may want to consider shutting down gracefully, as above, then running uninstall_i2p_service_winnt.bat.</p> <% } %> + + <% if (System.getProperty("wrapper.version") != null) { %> <h4>Debugging</h4> <p>At times, it may be helpful to debug I2P by getting a thread dump. To do so, please select the following option and review the thread dumped to <a href="logs.jsp#servicelogs">wrapper.log</a>.</p> <input type="submit" name="action" value="Dump threads" /> + <% } %> <h4>Launch browser on router startup?</h4> <p>I2P's main configuration interface is this web console, so for your convenience diff --git a/build.xml b/build.xml index f7a7294e38d0a23c949a7f23ea3a4bf45e97b48c..8fadcf8313227c24b3d43e7c56480fe5b0bfa9c3 100644 --- a/build.xml +++ b/build.xml @@ -278,7 +278,7 @@ <fileset dir="installer/lib/wrapper/win32/" /> </copy> <copy file="hosts.txt" todir="pkg-temp/" /> - <copy file="install-headless.txt" todir="pkg-temp/" /> + <copy file="INSTALL-headless.txt" todir="pkg-temp/" /> <copy file="history.txt" todir="pkg-temp/" /> <mkdir dir="pkg-temp/scripts" /> <copy file="apps/proxyscript/i2pProxy.pac" todir="pkg-temp/scripts/" /> diff --git a/checklist.txt b/checklist.txt index fcbe65028456e096dd4d951c77d019f626670ba5..baea847b956016fbf6089eb3339909e545d62e3b 100644 --- a/checklist.txt +++ b/checklist.txt @@ -18,6 +18,10 @@ Review the complete diff from the last release: mtn diff -r t:i2p-0.7.(xx-1) > out.diff vi out.diff +Verify that no untrusted revisions were inadvertently +blessed by a trusted party: + mtn log --brief --no-graph --to t:i2p-0.7.(xx-1) | cut -d ' ' -f 2- | sort + Build and tag: ant pkg mtn ci diff --git a/router/java/src/net/i2p/router/RouterWatchdog.java b/router/java/src/net/i2p/router/RouterWatchdog.java index e14331b6df2ac5fbfb0102fc3698e32f6a86e227..cb168102248a8a652cf837b16e36b1bbacb6ecf2 100644 --- a/router/java/src/net/i2p/router/RouterWatchdog.java +++ b/router/java/src/net/i2p/router/RouterWatchdog.java @@ -49,11 +49,15 @@ class RouterWatchdog implements Runnable { } private boolean shutdownOnHang() { + // prop default true + if (!Boolean.valueOf(_context.getProperty("watchdog.haltOnHang", "true")).booleanValue()) + return false; + // Client manager starts complaining after 10 minutes, and we run every minute, - // so this will restart 20 minutes after we lose a lease, if the wrapper is present. - if (_consecutiveErrors >= 10 && System.getProperty("wrapper.version") != null) + // so this will restart 30 minutes after we lose a lease, if the wrapper is present. + if (_consecutiveErrors >= 20 && System.getProperty("wrapper.version") != null) return true; - return Boolean.valueOf(_context.getProperty("watchdog.haltOnHang", "false")).booleanValue(); + return false; } private void dumpStatus() { @@ -90,13 +94,14 @@ class RouterWatchdog implements Runnable { long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); _log.error("Memory: " + DataHelper.formatSize(used) + '/' + DataHelper.formatSize(max)); if (_consecutiveErrors == 1) { + _log.log(Log.CRIT, "Router appears hung! Will restart in 20 minutes if it doesn't fix itself"); // This might work on linux... // It won't on windows, and we can't call i2prouter.bat either, it does something // completely different... ShellCommand sc = new ShellCommand(); boolean success = sc.executeSilentAndWaitTimed("./i2prouter dump", 10); if (success) - _log.error("DUMPED THREADS TO WRAPPER LOG"); + _log.log(Log.CRIT, "Threads dumped to wrapper log"); } } } @@ -127,7 +132,7 @@ class RouterWatchdog implements Runnable { _consecutiveErrors++; dumpStatus(); if (shutdownOnHang()) { - _log.log(Log.CRIT, "Router hung! hard restart!"); + _log.log(Log.CRIT, "Router hung! Restart forced by watchdog!"); try { Thread.sleep(30*1000); } catch (InterruptedException ie) {} // halt and not system.exit, since some of the shutdown hooks might be misbehaving Runtime.getRuntime().halt(Router.EXIT_HARD_RESTART); diff --git a/router/java/src/net/i2p/router/StatisticsManager.java b/router/java/src/net/i2p/router/StatisticsManager.java index d037ee300eabf11255b5e2eba528be61abdd1110..f107c5e1e9230059651be45c50a275d3616cd516 100644 --- a/router/java/src/net/i2p/router/StatisticsManager.java +++ b/router/java/src/net/i2p/router/StatisticsManager.java @@ -87,9 +87,14 @@ public class StatisticsManager implements Service { if (_includePeerRankings) { long publishedUptime = _context.router().getUptime(); + boolean commentOutIn074 = RouterVersion.VERSION.equals("0.7.3"); // Don't publish these for first hour - if (publishedUptime > 60*60*1000) - includeThroughput(stats); + if (publishedUptime > 62*60*1000) { + if (commentOutIn074) + includeThroughput(stats); + else + includeAverageThroughput(stats); + } //includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 }); //includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 }); //includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 }); @@ -223,16 +228,26 @@ public class StatisticsManager implements Service { return buf.toString(); } + /* report the same data for tx and rx, for enhanced anonymity */ + private void includeAverageThroughput(Properties stats) { + RateStat sendRate = _context.statManager().getRate("bw.sendRate"); + RateStat recvRate = _context.statManager().getRate("bw.recvRate"); + if (sendRate == null || recvRate == null) + return; + Rate s = sendRate.getRate(60*60*1000); + Rate r = recvRate.getRate(60*60*1000); + if (s == null || r == null) + return; + double speed = (s.getAverageValue() + r.getAverageValue()) / 2; + double max = Math.max(s.getExtremeAverageValue(), r.getExtremeAverageValue()); + String str = num(speed) + ';' + num(max) + ";0;0;"; + stats.setProperty("stat_bandwidthSendBps.60m", str); + stats.setProperty("stat_bandwidthReceiveBps.60m", str); + } + private void includeThroughput(Properties stats) { RateStat sendRate = _context.statManager().getRate("bw.sendRate"); if (sendRate != null) { - /**** - if (_context.router().getUptime() > 5*60*1000) { - Rate r = sendRate.getRate(5*60*1000); - if (r != null) - stats.setProperty("stat_bandwidthSendBps.5m", num(r.getAverageValue()) + ';' + num(r.getExtremeAverageValue()) + ";0;0;"); - } - ****/ if (_context.router().getUptime() > 60*60*1000) { Rate r = sendRate.getRate(60*60*1000); if (r != null) @@ -242,13 +257,6 @@ public class StatisticsManager implements Service { RateStat recvRate = _context.statManager().getRate("bw.recvRate"); if (recvRate != null) { - /**** - if (_context.router().getUptime() > 5*60*1000) { - Rate r = recvRate.getRate(5*60*1000); - if (r != null) - stats.setProperty("stat_bandwidthReceiveBps.5m", num(r.getAverageValue()) + ';' + num(r.getExtremeAverageValue()) + ";0;0;"); - } - ****/ if (_context.router().getUptime() > 60*60*1000) { Rate r = recvRate.getRate(60*60*1000); if (r != null) diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlySearchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlySearchJob.java index e5b5e962d6b076a2bde7f651b3f8ca08aef6661f..b6fec178cfeed2e0ed16a9a91bb3bd479d496c73 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlySearchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlySearchJob.java @@ -100,8 +100,10 @@ class FloodOnlySearchJob extends FloodSearchJob { if (floodfillPeers.size() <= 3) _shouldProcessDSRM = true; if (floodfillPeers.size() <= 0) { - if (_log.shouldLog(Log.ERROR)) - _log.error("Running netDb searches against the floodfill peers, but we don't know any"); + // ask anybody, they may not return the answer but they will return a few ff peers we can go look up, + // so this situation should be temporary + if (_log.shouldLog(Log.WARN)) + _log.warn("Running netDb searches against the floodfill peers, but we don't know any"); floodfillPeers = new ArrayList(_facade.getAllRouters()); if (floodfillPeers.size() <= 0) { if (_log.shouldLog(Log.ERROR)) diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java index 8c40d117b9842b434f6c1de677c1ec2aa6710f36..24c0350f92361ca0d4678dab76024132178cc125 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java @@ -8,6 +8,12 @@ import net.i2p.util.Log; /** * Ask the peer who sent us the DSRM for the RouterInfos. + * + * If we have the routerInfo already, try to refetch it from that router itself, + * if we aren't already connected to that router, + * which will help us establish that router as a good floodfill and speed our + * integration into the network. + * * A simple version of SearchReplyJob in SearchJob.java. * Skip the profile updates - this should be rare. * @@ -28,6 +34,8 @@ class SingleLookupJob extends JobImpl { continue; if (getContext().netDb().lookupRouterInfoLocally(peer) == null) getContext().jobQueue().addJob(new SingleSearchJob(getContext(), peer, from)); + else if (!getContext().commSystem().isEstablished(peer)) + getContext().jobQueue().addJob(new SingleSearchJob(getContext(), peer, peer)); } } public String getName() { return "NetDb process DSRM"; } diff --git a/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java b/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java index 693df45b181d41b676ca49d37ad16b813df36527..b24d79a11c76d9de4c3880803b425f49b086ed6c 100644 --- a/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java +++ b/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java @@ -34,8 +34,14 @@ public class FIFOBandwidthRefiller implements Runnable { //public static final String PROP_REPLENISH_FREQUENCY = "i2np.bandwidth.replenishFrequencyMs"; // no longer allow unlimited bandwidth - the user must specify a value, else use defaults below (KBps) - public static final int DEFAULT_INBOUND_BANDWIDTH = 64; - public static final int DEFAULT_OUTBOUND_BANDWIDTH = 32; + public static final int DEFAULT_INBOUND_BANDWIDTH = 96; + /** + * Caution, do not make DEFAULT_OUTBOUND_BANDWIDTH * DEFAULT_SHARE_PCT > 32 + * without thinking about the implications (default connection limits, for example) + * of moving the default bandwidth class from L to M, or maybe + * adjusting bandwidth class boundaries. + */ + public static final int DEFAULT_OUTBOUND_BANDWIDTH = 40; public static final int DEFAULT_INBOUND_BURST_BANDWIDTH = 80; public static final int DEFAULT_OUTBOUND_BURST_BANDWIDTH = 40;